Showing
53 changed files
with
2361 additions
and
1086 deletions
| @@ -49,6 +49,7 @@ linter: | @@ -49,6 +49,7 @@ linter: | ||
| 49 | prefer_equal_for_default_values: true | 49 | prefer_equal_for_default_values: true | 
| 50 | avoid_init_to_null: true | 50 | avoid_init_to_null: true | 
| 51 | unnecessary_getters_setters: true | 51 | unnecessary_getters_setters: true | 
| 52 | + annotate_overrides: true | ||
| 52 | #- unnecessary_getters # prefer # Disabled pending fix: https://github.com/dart-lang/linter/issues/23 | 53 | #- unnecessary_getters # prefer # Disabled pending fix: https://github.com/dart-lang/linter/issues/23 | 
| 53 | #- prefer_expression_function_bodies # consider | 54 | #- prefer_expression_function_bodies # consider | 
| 54 | unnecessary_this: true | 55 | unnecessary_this: true | 
example/android/.gitignore
0 → 100644
example/android/app/build.gradle
0 → 100644
| 1 | +def localProperties = new Properties() | ||
| 2 | +def localPropertiesFile = rootProject.file('local.properties') | ||
| 3 | +if (localPropertiesFile.exists()) { | ||
| 4 | + localPropertiesFile.withReader('UTF-8') { reader -> | ||
| 5 | + localProperties.load(reader) | ||
| 6 | + } | ||
| 7 | +} | ||
| 8 | + | ||
| 9 | +def flutterRoot = localProperties.getProperty('flutter.sdk') | ||
| 10 | +if (flutterRoot == null) { | ||
| 11 | + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') | ||
| 15 | +if (flutterVersionCode == null) { | ||
| 16 | + flutterVersionCode = '1' | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +def flutterVersionName = localProperties.getProperty('flutter.versionName') | ||
| 20 | +if (flutterVersionName == null) { | ||
| 21 | + flutterVersionName = '1.0' | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +apply plugin: 'com.android.application' | ||
| 25 | +apply plugin: 'kotlin-android' | ||
| 26 | +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" | ||
| 27 | + | ||
| 28 | +android { | ||
| 29 | + compileSdkVersion 29 | ||
| 30 | + | ||
| 31 | + sourceSets { | ||
| 32 | + main.java.srcDirs += 'src/main/kotlin' | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + lintOptions { | ||
| 36 | + disable 'InvalidPackage' | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + defaultConfig { | ||
| 40 | + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). | ||
| 41 | + applicationId "com.example.example" | ||
| 42 | + minSdkVersion 16 | ||
| 43 | + targetSdkVersion 29 | ||
| 44 | + versionCode flutterVersionCode.toInteger() | ||
| 45 | + versionName flutterVersionName | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + buildTypes { | ||
| 49 | + release { | ||
| 50 | + // TODO: Add your own signing config for the release build. | ||
| 51 | + // Signing with the debug keys for now, so `flutter run --release` works. | ||
| 52 | + signingConfig signingConfigs.debug | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | +} | ||
| 56 | + | ||
| 57 | +flutter { | ||
| 58 | + source '../..' | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +dependencies { | ||
| 62 | + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" | ||
| 63 | +} | 
| 1 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | + package="com.example.example"> | ||
| 3 | + <!-- Flutter needs it to communicate with the running application | ||
| 4 | + to allow setting breakpoints, to provide hot reload, etc. | ||
| 5 | + --> | ||
| 6 | + <uses-permission android:name="android.permission.INTERNET"/> | ||
| 7 | +</manifest> | 
| 1 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | + package="com.example.example"> | ||
| 3 | + <application | ||
| 4 | + android:label="example" | ||
| 5 | + android:icon="@mipmap/ic_launcher"> | ||
| 6 | + <activity | ||
| 7 | + android:name=".MainActivity" | ||
| 8 | + android:launchMode="singleTop" | ||
| 9 | + android:theme="@style/LaunchTheme" | ||
| 10 | + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" | ||
| 11 | + android:hardwareAccelerated="true" | ||
| 12 | + android:windowSoftInputMode="adjustResize"> | ||
| 13 | + <!-- Specifies an Android theme to apply to this Activity as soon as | ||
| 14 | + the Android process has started. This theme is visible to the user | ||
| 15 | + while the Flutter UI initializes. After that, this theme continues | ||
| 16 | + to determine the Window background behind the Flutter UI. --> | ||
| 17 | + <meta-data | ||
| 18 | + android:name="io.flutter.embedding.android.NormalTheme" | ||
| 19 | + android:resource="@style/NormalTheme" | ||
| 20 | + /> | ||
| 21 | + <!-- Displays an Android View that continues showing the launch screen | ||
| 22 | + Drawable until Flutter paints its first frame, then this splash | ||
| 23 | + screen fades out. A splash screen is useful to avoid any visual | ||
| 24 | + gap between the end of Android's launch screen and the painting of | ||
| 25 | + Flutter's first frame. --> | ||
| 26 | + <meta-data | ||
| 27 | + android:name="io.flutter.embedding.android.SplashScreenDrawable" | ||
| 28 | + android:resource="@drawable/launch_background" | ||
| 29 | + /> | ||
| 30 | + <intent-filter> | ||
| 31 | + <action android:name="android.intent.action.MAIN"/> | ||
| 32 | + <category android:name="android.intent.category.LAUNCHER"/> | ||
| 33 | + </intent-filter> | ||
| 34 | + </activity> | ||
| 35 | + <!-- Don't delete the meta-data below. | ||
| 36 | + This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> | ||
| 37 | + <meta-data | ||
| 38 | + android:name="flutterEmbedding" | ||
| 39 | + android:value="2" /> | ||
| 40 | + </application> | ||
| 41 | +</manifest> | 
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<!-- Modify this file to customize your launch splash screen --> | ||
| 3 | +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| 4 | + <item android:drawable="?android:colorBackground" /> | ||
| 5 | + | ||
| 6 | + <!-- You can insert your own image assets here --> | ||
| 7 | + <!-- <item> | ||
| 8 | + <bitmap | ||
| 9 | + android:gravity="center" | ||
| 10 | + android:src="@mipmap/launch_image" /> | ||
| 11 | + </item> --> | ||
| 12 | +</layer-list> | 
 
544 Bytes
 
442 Bytes
 
721 Bytes
 
1.01 KB
 
1.41 KB
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<resources> | ||
| 3 | + <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on --> | ||
| 4 | + <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> | ||
| 5 | + <!-- Show a splash screen on the activity. Automatically removed when | ||
| 6 | + Flutter draws its first frame --> | ||
| 7 | + <item name="android:windowBackground">@drawable/launch_background</item> | ||
| 8 | + </style> | ||
| 9 | + <!-- Theme applied to the Android Window as soon as the process has started. | ||
| 10 | + This theme determines the color of the Android Window while your | ||
| 11 | + Flutter UI initializes, as well as behind your Flutter UI while its | ||
| 12 | + running. | ||
| 13 | + | ||
| 14 | + This Theme is only used starting with V2 of Flutter's Android embedding. --> | ||
| 15 | + <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar"> | ||
| 16 | + <item name="android:windowBackground">?android:colorBackground</item> | ||
| 17 | + </style> | ||
| 18 | +</resources> | 
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<resources> | ||
| 3 | + <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off --> | ||
| 4 | + <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"> | ||
| 5 | + <!-- Show a splash screen on the activity. Automatically removed when | ||
| 6 | + Flutter draws its first frame --> | ||
| 7 | + <item name="android:windowBackground">@drawable/launch_background</item> | ||
| 8 | + </style> | ||
| 9 | + <!-- Theme applied to the Android Window as soon as the process has started. | ||
| 10 | + This theme determines the color of the Android Window while your | ||
| 11 | + Flutter UI initializes, as well as behind your Flutter UI while its | ||
| 12 | + running. | ||
| 13 | + | ||
| 14 | + This Theme is only used starting with V2 of Flutter's Android embedding. --> | ||
| 15 | + <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> | ||
| 16 | + <item name="android:windowBackground">?android:colorBackground</item> | ||
| 17 | + </style> | ||
| 18 | +</resources> | 
| 1 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 2 | + package="com.example.example"> | ||
| 3 | + <!-- Flutter needs it to communicate with the running application | ||
| 4 | + to allow setting breakpoints, to provide hot reload, etc. | ||
| 5 | + --> | ||
| 6 | + <uses-permission android:name="android.permission.INTERNET"/> | ||
| 7 | +</manifest> | 
example/android/build.gradle
0 → 100644
| 1 | +buildscript { | ||
| 2 | + ext.kotlin_version = '1.3.50' | ||
| 3 | + repositories { | ||
| 4 | + google() | ||
| 5 | + jcenter() | ||
| 6 | + } | ||
| 7 | + | ||
| 8 | + dependencies { | ||
| 9 | + classpath 'com.android.tools.build:gradle:3.5.0' | ||
| 10 | + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | ||
| 11 | + } | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +allprojects { | ||
| 15 | + repositories { | ||
| 16 | + google() | ||
| 17 | + jcenter() | ||
| 18 | + } | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +rootProject.buildDir = '../build' | ||
| 22 | +subprojects { | ||
| 23 | + project.buildDir = "${rootProject.buildDir}/${project.name}" | ||
| 24 | +} | ||
| 25 | +subprojects { | ||
| 26 | + project.evaluationDependsOn(':app') | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +task clean(type: Delete) { | ||
| 30 | + delete rootProject.buildDir | ||
| 31 | +} | 
example/android/gradle.properties
0 → 100644
example/android/settings.gradle
0 → 100644
| 1 | +include ':app' | ||
| 2 | + | ||
| 3 | +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") | ||
| 4 | +def properties = new Properties() | ||
| 5 | + | ||
| 6 | +assert localPropertiesFile.exists() | ||
| 7 | +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } | ||
| 8 | + | ||
| 9 | +def flutterSdkPath = properties.getProperty("flutter.sdk") | ||
| 10 | +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" | ||
| 11 | +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" | 
example/linux/.gitignore
0 → 100644
| 1 | +flutter/ephemeral | 
example/linux/CMakeLists.txt
0 → 100644
| 1 | +cmake_minimum_required(VERSION 3.10) | ||
| 2 | +project(runner LANGUAGES CXX) | ||
| 3 | + | ||
| 4 | +set(BINARY_NAME "example") | ||
| 5 | +set(APPLICATION_ID "com.example.example") | ||
| 6 | + | ||
| 7 | +cmake_policy(SET CMP0063 NEW) | ||
| 8 | + | ||
| 9 | +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") | ||
| 10 | + | ||
| 11 | +# Configure build options. | ||
| 12 | +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) | ||
| 13 | + set(CMAKE_BUILD_TYPE "Debug" CACHE | ||
| 14 | + STRING "Flutter build mode" FORCE) | ||
| 15 | + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS | ||
| 16 | + "Debug" "Profile" "Release") | ||
| 17 | +endif() | ||
| 18 | + | ||
| 19 | +# Compilation settings that should be applied to most targets. | ||
| 20 | +function(APPLY_STANDARD_SETTINGS TARGET) | ||
| 21 | + target_compile_features(${TARGET} PUBLIC cxx_std_14) | ||
| 22 | + target_compile_options(${TARGET} PRIVATE -Wall -Werror) | ||
| 23 | + target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>") | ||
| 24 | + target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>") | ||
| 25 | +endfunction() | ||
| 26 | + | ||
| 27 | +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") | ||
| 28 | + | ||
| 29 | +# Flutter library and tool build rules. | ||
| 30 | +add_subdirectory(${FLUTTER_MANAGED_DIR}) | ||
| 31 | + | ||
| 32 | +# System-level dependencies. | ||
| 33 | +find_package(PkgConfig REQUIRED) | ||
| 34 | +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) | ||
| 35 | + | ||
| 36 | +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") | ||
| 37 | + | ||
| 38 | +# Application build | ||
| 39 | +add_executable(${BINARY_NAME} | ||
| 40 | + "main.cc" | ||
| 41 | + "my_application.cc" | ||
| 42 | + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" | ||
| 43 | +) | ||
| 44 | +apply_standard_settings(${BINARY_NAME}) | ||
| 45 | +target_link_libraries(${BINARY_NAME} PRIVATE flutter) | ||
| 46 | +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) | ||
| 47 | +add_dependencies(${BINARY_NAME} flutter_assemble) | ||
| 48 | +# Only the install-generated bundle's copy of the executable will launch | ||
| 49 | +# correctly, since the resources must in the right relative locations. To avoid | ||
| 50 | +# people trying to run the unbundled copy, put it in a subdirectory instead of | ||
| 51 | +# the default top-level location. | ||
| 52 | +set_target_properties(${BINARY_NAME} | ||
| 53 | + PROPERTIES | ||
| 54 | + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" | ||
| 55 | +) | ||
| 56 | + | ||
| 57 | +# Generated plugin build rules, which manage building the plugins and adding | ||
| 58 | +# them to the application. | ||
| 59 | +include(flutter/generated_plugins.cmake) | ||
| 60 | + | ||
| 61 | + | ||
| 62 | +# === Installation === | ||
| 63 | +# By default, "installing" just makes a relocatable bundle in the build | ||
| 64 | +# directory. | ||
| 65 | +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") | ||
| 66 | +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) | ||
| 67 | + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) | ||
| 68 | +endif() | ||
| 69 | + | ||
| 70 | +# Start with a clean build bundle directory every time. | ||
| 71 | +install(CODE " | ||
| 72 | + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") | ||
| 73 | + " COMPONENT Runtime) | ||
| 74 | + | ||
| 75 | +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") | ||
| 76 | +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") | ||
| 77 | + | ||
| 78 | +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" | ||
| 79 | + COMPONENT Runtime) | ||
| 80 | + | ||
| 81 | +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" | ||
| 82 | + COMPONENT Runtime) | ||
| 83 | + | ||
| 84 | +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" | ||
| 85 | + COMPONENT Runtime) | ||
| 86 | + | ||
| 87 | +if(PLUGIN_BUNDLED_LIBRARIES) | ||
| 88 | + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" | ||
| 89 | + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" | ||
| 90 | + COMPONENT Runtime) | ||
| 91 | +endif() | ||
| 92 | + | ||
| 93 | +# Fully re-copy the assets directory on each build to avoid having stale files | ||
| 94 | +# from a previous install. | ||
| 95 | +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") | ||
| 96 | +install(CODE " | ||
| 97 | + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") | ||
| 98 | + " COMPONENT Runtime) | ||
| 99 | +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" | ||
| 100 | + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) | ||
| 101 | + | ||
| 102 | +# Install the AOT library on non-Debug builds only. | ||
| 103 | +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") | ||
| 104 | + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" | ||
| 105 | + COMPONENT Runtime) | ||
| 106 | +endif() | 
example/linux/flutter/CMakeLists.txt
0 → 100644
| 1 | +cmake_minimum_required(VERSION 3.10) | ||
| 2 | + | ||
| 3 | +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") | ||
| 4 | + | ||
| 5 | +# Configuration provided via flutter tool. | ||
| 6 | +include(${EPHEMERAL_DIR}/generated_config.cmake) | ||
| 7 | + | ||
| 8 | +# TODO: Move the rest of this into files in ephemeral. See | ||
| 9 | +# https://github.com/flutter/flutter/issues/57146. | ||
| 10 | + | ||
| 11 | +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), | ||
| 12 | +# which isn't available in 3.10. | ||
| 13 | +function(list_prepend LIST_NAME PREFIX) | ||
| 14 | + set(NEW_LIST "") | ||
| 15 | + foreach(element ${${LIST_NAME}}) | ||
| 16 | + list(APPEND NEW_LIST "${PREFIX}${element}") | ||
| 17 | + endforeach(element) | ||
| 18 | + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) | ||
| 19 | +endfunction() | ||
| 20 | + | ||
| 21 | +# === Flutter Library === | ||
| 22 | +# System-level dependencies. | ||
| 23 | +find_package(PkgConfig REQUIRED) | ||
| 24 | +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) | ||
| 25 | +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) | ||
| 26 | +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) | ||
| 27 | +pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid) | ||
| 28 | + | ||
| 29 | +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") | ||
| 30 | + | ||
| 31 | +# Published to parent scope for install step. | ||
| 32 | +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) | ||
| 33 | +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) | ||
| 34 | +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) | ||
| 35 | +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) | ||
| 36 | + | ||
| 37 | +list(APPEND FLUTTER_LIBRARY_HEADERS | ||
| 38 | + "fl_basic_message_channel.h" | ||
| 39 | + "fl_binary_codec.h" | ||
| 40 | + "fl_binary_messenger.h" | ||
| 41 | + "fl_dart_project.h" | ||
| 42 | + "fl_engine.h" | ||
| 43 | + "fl_json_message_codec.h" | ||
| 44 | + "fl_json_method_codec.h" | ||
| 45 | + "fl_message_codec.h" | ||
| 46 | + "fl_method_call.h" | ||
| 47 | + "fl_method_channel.h" | ||
| 48 | + "fl_method_codec.h" | ||
| 49 | + "fl_method_response.h" | ||
| 50 | + "fl_plugin_registrar.h" | ||
| 51 | + "fl_plugin_registry.h" | ||
| 52 | + "fl_standard_message_codec.h" | ||
| 53 | + "fl_standard_method_codec.h" | ||
| 54 | + "fl_string_codec.h" | ||
| 55 | + "fl_value.h" | ||
| 56 | + "fl_view.h" | ||
| 57 | + "flutter_linux.h" | ||
| 58 | +) | ||
| 59 | +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") | ||
| 60 | +add_library(flutter INTERFACE) | ||
| 61 | +target_include_directories(flutter INTERFACE | ||
| 62 | + "${EPHEMERAL_DIR}" | ||
| 63 | +) | ||
| 64 | +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") | ||
| 65 | +target_link_libraries(flutter INTERFACE | ||
| 66 | + PkgConfig::GTK | ||
| 67 | + PkgConfig::GLIB | ||
| 68 | + PkgConfig::GIO | ||
| 69 | + PkgConfig::BLKID | ||
| 70 | +) | ||
| 71 | +add_dependencies(flutter flutter_assemble) | ||
| 72 | + | ||
| 73 | +# === Flutter tool backend === | ||
| 74 | +# _phony_ is a non-existent file to force this command to run every time, | ||
| 75 | +# since currently there's no way to get a full input/output list from the | ||
| 76 | +# flutter tool. | ||
| 77 | +add_custom_command( | ||
| 78 | + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} | ||
| 79 | + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ | ||
| 80 | + COMMAND ${CMAKE_COMMAND} -E env | ||
| 81 | + ${FLUTTER_TOOL_ENVIRONMENT} | ||
| 82 | + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" | ||
| 83 | + linux-x64 ${CMAKE_BUILD_TYPE} | ||
| 84 | +) | ||
| 85 | +add_custom_target(flutter_assemble DEPENDS | ||
| 86 | + "${FLUTTER_LIBRARY}" | ||
| 87 | + ${FLUTTER_LIBRARY_HEADERS} | ||
| 88 | +) | 
| 1 | +// | ||
| 2 | +// Generated file. Do not edit. | ||
| 3 | +// | ||
| 4 | + | ||
| 5 | +#ifndef GENERATED_PLUGIN_REGISTRANT_ | ||
| 6 | +#define GENERATED_PLUGIN_REGISTRANT_ | ||
| 7 | + | ||
| 8 | +#include <flutter_linux/flutter_linux.h> | ||
| 9 | + | ||
| 10 | +// Registers Flutter plugins. | ||
| 11 | +void fl_register_plugins(FlPluginRegistry* registry); | ||
| 12 | + | ||
| 13 | +#endif // GENERATED_PLUGIN_REGISTRANT_ | 
| 1 | +# | ||
| 2 | +# Generated file, do not edit. | ||
| 3 | +# | ||
| 4 | + | ||
| 5 | +list(APPEND FLUTTER_PLUGIN_LIST | ||
| 6 | +) | ||
| 7 | + | ||
| 8 | +set(PLUGIN_BUNDLED_LIBRARIES) | ||
| 9 | + | ||
| 10 | +foreach(plugin ${FLUTTER_PLUGIN_LIST}) | ||
| 11 | + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) | ||
| 12 | + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) | ||
| 13 | + list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>) | ||
| 14 | + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) | ||
| 15 | +endforeach(plugin) | 
example/linux/main.cc
0 → 100644
example/linux/my_application.cc
0 → 100644
| 1 | +#include "my_application.h" | ||
| 2 | + | ||
| 3 | +#include <flutter_linux/flutter_linux.h> | ||
| 4 | +#ifdef GDK_WINDOWING_X11 | ||
| 5 | +#include <gdk/gdkx.h> | ||
| 6 | +#endif | ||
| 7 | + | ||
| 8 | +#include "flutter/generated_plugin_registrant.h" | ||
| 9 | + | ||
| 10 | +struct _MyApplication { | ||
| 11 | + GtkApplication parent_instance; | ||
| 12 | +}; | ||
| 13 | + | ||
| 14 | +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) | ||
| 15 | + | ||
| 16 | +// Implements GApplication::activate. | ||
| 17 | +static void my_application_activate(GApplication* application) { | ||
| 18 | + GtkWindow* window = | ||
| 19 | + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); | ||
| 20 | + | ||
| 21 | + // Use a header bar when running in GNOME as this is the common style used | ||
| 22 | + // by applications and is the setup most users will be using (e.g. Ubuntu | ||
| 23 | + // desktop). | ||
| 24 | + // If running on X and not using GNOME then just use a traditional title bar | ||
| 25 | + // in case the window manager does more exotic layout, e.g. tiling. | ||
| 26 | + // If running on Wayland assume the header bar will work (may need changing | ||
| 27 | + // if future cases occur). | ||
| 28 | + gboolean use_header_bar = TRUE; | ||
| 29 | +#ifdef GDK_WINDOWING_X11 | ||
| 30 | + GdkScreen *screen = gtk_window_get_screen(window); | ||
| 31 | + if (GDK_IS_X11_SCREEN(screen)) { | ||
| 32 | + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); | ||
| 33 | + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { | ||
| 34 | + use_header_bar = FALSE; | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | +#endif | ||
| 38 | + if (use_header_bar) { | ||
| 39 | + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); | ||
| 40 | + gtk_widget_show(GTK_WIDGET(header_bar)); | ||
| 41 | + gtk_header_bar_set_title(header_bar, "example"); | ||
| 42 | + gtk_header_bar_set_show_close_button(header_bar, TRUE); | ||
| 43 | + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); | ||
| 44 | + } | ||
| 45 | + else { | ||
| 46 | + gtk_window_set_title(window, "example"); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + gtk_window_set_default_size(window, 1280, 720); | ||
| 50 | + gtk_widget_show(GTK_WIDGET(window)); | ||
| 51 | + | ||
| 52 | + g_autoptr(FlDartProject) project = fl_dart_project_new(); | ||
| 53 | + | ||
| 54 | + FlView* view = fl_view_new(project); | ||
| 55 | + gtk_widget_show(GTK_WIDGET(view)); | ||
| 56 | + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); | ||
| 57 | + | ||
| 58 | + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); | ||
| 59 | + | ||
| 60 | + gtk_widget_grab_focus(GTK_WIDGET(view)); | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +static void my_application_class_init(MyApplicationClass* klass) { | ||
| 64 | + G_APPLICATION_CLASS(klass)->activate = my_application_activate; | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +static void my_application_init(MyApplication* self) {} | ||
| 68 | + | ||
| 69 | +MyApplication* my_application_new() { | ||
| 70 | + return MY_APPLICATION(g_object_new(my_application_get_type(), | ||
| 71 | + "application-id", APPLICATION_ID, | ||
| 72 | + nullptr)); | ||
| 73 | +} | 
example/linux/my_application.h
0 → 100644
| 1 | +#ifndef FLUTTER_MY_APPLICATION_H_ | ||
| 2 | +#define FLUTTER_MY_APPLICATION_H_ | ||
| 3 | + | ||
| 4 | +#include <gtk/gtk.h> | ||
| 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_ | 
example/web/favicon.png
0 → 100644
 
917 Bytes
example/web/icons/Icon-192.png
0 → 100644
 
5.17 KB
example/web/icons/Icon-512.png
0 → 100644
 
8.06 KB
example/web/index.html
0 → 100644
| 1 | +<!DOCTYPE html> | ||
| 2 | +<html> | ||
| 3 | +<head> | ||
| 4 | + <!-- | ||
| 5 | + If you are serving your web app in a path other than the root, change the | ||
| 6 | + href value below to reflect the base path you are serving from. | ||
| 7 | + | ||
| 8 | + The path provided below has to start and end with a slash "/" in order for | ||
| 9 | + it to work correctly. | ||
| 10 | + | ||
| 11 | + Fore more details: | ||
| 12 | + * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base | ||
| 13 | + --> | ||
| 14 | + <base href="/"> | ||
| 15 | + | ||
| 16 | + <meta charset="UTF-8"> | ||
| 17 | + <meta content="IE=Edge" http-equiv="X-UA-Compatible"> | ||
| 18 | + <meta name="description" content="A new Flutter project."> | ||
| 19 | + | ||
| 20 | + <!-- iOS meta tags & icons --> | ||
| 21 | + <meta name="apple-mobile-web-app-capable" content="yes"> | ||
| 22 | + <meta name="apple-mobile-web-app-status-bar-style" content="black"> | ||
| 23 | + <meta name="apple-mobile-web-app-title" content="example"> | ||
| 24 | + <link rel="apple-touch-icon" href="icons/Icon-192.png"> | ||
| 25 | + | ||
| 26 | + <!-- Favicon --> | ||
| 27 | + <link rel="icon" type="image/png" href="favicon.png"/> | ||
| 28 | + | ||
| 29 | + <title>example</title> | ||
| 30 | + <link rel="manifest" href="manifest.json"> | ||
| 31 | +</head> | ||
| 32 | +<body> | ||
| 33 | + <!-- This script installs service_worker.js to provide PWA functionality to | ||
| 34 | + application. For more information, see: | ||
| 35 | + https://developers.google.com/web/fundamentals/primers/service-workers --> | ||
| 36 | + <script> | ||
| 37 | + if ('serviceWorker' in navigator) { | ||
| 38 | + window.addEventListener('flutter-first-frame', function () { | ||
| 39 | + navigator.serviceWorker.register('flutter_service_worker.js'); | ||
| 40 | + }); | ||
| 41 | + } | ||
| 42 | + </script> | ||
| 43 | + <script src="main.dart.js" type="application/javascript"></script> | ||
| 44 | +</body> | ||
| 45 | +</html> | 
example/web/manifest.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "example", | ||
| 3 | + "short_name": "example", | ||
| 4 | + "start_url": ".", | ||
| 5 | + "display": "standalone", | ||
| 6 | + "background_color": "#0175C2", | ||
| 7 | + "theme_color": "#0175C2", | ||
| 8 | + "description": "A new Flutter project.", | ||
| 9 | + "orientation": "portrait-primary", | ||
| 10 | + "prefer_related_applications": false, | ||
| 11 | + "icons": [ | ||
| 12 | + { | ||
| 13 | + "src": "icons/Icon-192.png", | ||
| 14 | + "sizes": "192x192", | ||
| 15 | + "type": "image/png" | ||
| 16 | + }, | ||
| 17 | + { | ||
| 18 | + "src": "icons/Icon-512.png", | ||
| 19 | + "sizes": "512x512", | ||
| 20 | + "type": "image/png" | ||
| 21 | + } | ||
| 22 | + ] | ||
| 23 | +} | 
| @@ -11,9 +11,6 @@ import 'root/parse_route.dart'; | @@ -11,9 +11,6 @@ import 'root/parse_route.dart'; | ||
| 11 | import 'root/root_controller.dart'; | 11 | import 'root/root_controller.dart'; | 
| 12 | import 'routes/transitions_type.dart'; | 12 | import 'routes/transitions_type.dart'; | 
| 13 | 13 | ||
| 14 | -//TODO: Split this class on "Snackbar" "Dialog" "bottomSheet" | ||
| 15 | -//and "navigation" extensions | ||
| 16 | - | ||
| 17 | extension ExtensionSnackbar on GetInterface { | 14 | extension ExtensionSnackbar on GetInterface { | 
| 18 | void rawSnackbar({ | 15 | void rawSnackbar({ | 
| 19 | String title, | 16 | String title, | 
| 1 | library get_rx; | 1 | library get_rx; | 
| 2 | 2 | ||
| 3 | -export 'src/rx_core/rx_impl.dart'; | ||
| 4 | -export 'src/rx_core/rx_interface.dart'; | ||
| 5 | -export 'src/rx_iterables/rx_list.dart'; | ||
| 6 | -export 'src/rx_iterables/rx_map.dart'; | ||
| 7 | -export 'src/rx_iterables/rx_set.dart'; | 3 | +export 'src/rx_stream/rx_stream.dart'; | 
| 4 | +export 'src/rx_types/rx_types.dart'; | ||
| 8 | export 'src/rx_workers/rx_workers.dart'; | 5 | export 'src/rx_workers/rx_workers.dart'; | 
| 1 | -import 'dart:async'; | ||
| 2 | -import 'dart:collection'; | ||
| 3 | -import 'dart:math'; | ||
| 4 | -import 'package:flutter/foundation.dart'; | ||
| 5 | - | ||
| 6 | -import '../rx_core/rx_impl.dart'; | ||
| 7 | -import '../rx_core/rx_interface.dart'; | ||
| 8 | -import '../rx_typedefs/rx_typedefs.dart'; | ||
| 9 | - | ||
| 10 | -/// Create a list similar to `List<T>` | ||
| 11 | -class RxList<E> implements List<E>, RxInterface<List<E>> { | ||
| 12 | - RxList([List<E> initial]) { | ||
| 13 | - if (initial != null) _list = initial; | ||
| 14 | - } | ||
| 15 | - | ||
| 16 | - List<E> _list = <E>[]; | ||
| 17 | - | ||
| 18 | - @override | ||
| 19 | - Iterator<E> get iterator => value.iterator; | ||
| 20 | - | ||
| 21 | - @override | ||
| 22 | - bool get isEmpty => value.isEmpty; | ||
| 23 | - | ||
| 24 | - bool get canUpdate { | ||
| 25 | - return _subscriptions.length > 0; | ||
| 26 | - } | ||
| 27 | - | ||
| 28 | - @override | ||
| 29 | - bool get isNotEmpty => value.isNotEmpty; | ||
| 30 | - | ||
| 31 | - @override | ||
| 32 | - StreamController<List<E>> subject = StreamController.broadcast(); | ||
| 33 | - | ||
| 34 | - final _subscriptions = HashMap<Stream<List<E>>, StreamSubscription>(); | ||
| 35 | - | ||
| 36 | - void operator []=(int index, E val) { | ||
| 37 | - _list[index] = val; | ||
| 38 | - refresh(); | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - void refresh() { | ||
| 42 | - subject.add(_list); | ||
| 43 | - } | ||
| 44 | - | ||
| 45 | - /// Special override to push() element(s) in a reactive way | ||
| 46 | - /// inside the List, | ||
| 47 | - RxList<E> operator +(Iterable<E> val) { | ||
| 48 | - addAll(val); | ||
| 49 | - refresh(); | ||
| 50 | - return this; | ||
| 51 | - } | ||
| 52 | - | ||
| 53 | - E operator [](int index) { | ||
| 54 | - return value[index]; | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | - void add(E item) { | ||
| 58 | - _list.add(item); | ||
| 59 | - refresh(); | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - @override | ||
| 63 | - void addAll(Iterable<E> item) { | ||
| 64 | - _list.addAll(item); | ||
| 65 | - refresh(); | ||
| 66 | - } | ||
| 67 | - | ||
| 68 | - /// Add [item] to [List<E>] only if [item] is not null. | ||
| 69 | - void addNonNull(E item) { | ||
| 70 | - if (item != null) add(item); | ||
| 71 | - } | ||
| 72 | - | ||
| 73 | - /// Add [Iterable<E>] to [List<E>] only if [Iterable<E>] is not null. | ||
| 74 | - void addAllNonNull(Iterable<E> item) { | ||
| 75 | - if (item != null) addAll(item); | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - /// Add [item] to [List<E>] only if [condition] is true. | ||
| 79 | - void addIf(dynamic condition, E item) { | ||
| 80 | - if (condition is Condition) condition = condition(); | ||
| 81 | - if (condition is bool && condition) add(item); | ||
| 82 | - } | ||
| 83 | - | ||
| 84 | - /// Adds [Iterable<E>] to [List<E>] only if [condition] is true. | ||
| 85 | - void addAllIf(dynamic condition, Iterable<E> items) { | ||
| 86 | - if (condition is Condition) condition = condition(); | ||
| 87 | - if (condition is bool && condition) addAll(items); | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - @override | ||
| 91 | - void insert(int index, E item) { | ||
| 92 | - _list.insert(index, item); | ||
| 93 | - refresh(); | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - @override | ||
| 97 | - void insertAll(int index, Iterable<E> iterable) { | ||
| 98 | - _list.insertAll(index, iterable); | ||
| 99 | - refresh(); | ||
| 100 | - } | ||
| 101 | - | ||
| 102 | - @override | ||
| 103 | - int get length => value.length; | ||
| 104 | - | ||
| 105 | - /// Removes an item from the list. | ||
| 106 | - /// | ||
| 107 | - /// This is O(N) in the number of items in the list. | ||
| 108 | - /// | ||
| 109 | - /// Returns whether the item was present in the list. | ||
| 110 | - @override | ||
| 111 | - bool remove(Object item) { | ||
| 112 | - final hasRemoved = _list.remove(item); | ||
| 113 | - if (hasRemoved) { | ||
| 114 | - refresh(); | ||
| 115 | - } | ||
| 116 | - return hasRemoved; | ||
| 117 | - } | ||
| 118 | - | ||
| 119 | - @override | ||
| 120 | - E removeAt(int index) { | ||
| 121 | - final item = _list.removeAt(index); | ||
| 122 | - refresh(); | ||
| 123 | - return item; | ||
| 124 | - } | ||
| 125 | - | ||
| 126 | - @override | ||
| 127 | - E removeLast() { | ||
| 128 | - final item = _list.removeLast(); | ||
| 129 | - refresh(); | ||
| 130 | - return item; | ||
| 131 | - } | ||
| 132 | - | ||
| 133 | - @override | ||
| 134 | - void removeRange(int start, int end) { | ||
| 135 | - _list.removeRange(start, end); | ||
| 136 | - refresh(); | ||
| 137 | - } | ||
| 138 | - | ||
| 139 | - @override | ||
| 140 | - void removeWhere(bool Function(E) test) { | ||
| 141 | - _list.removeWhere(test); | ||
| 142 | - refresh(); | ||
| 143 | - } | ||
| 144 | - | ||
| 145 | - @override | ||
| 146 | - void clear() { | ||
| 147 | - _list.clear(); | ||
| 148 | - refresh(); | ||
| 149 | - } | ||
| 150 | - | ||
| 151 | - @override | ||
| 152 | - void sort([int compare(E a, E b)]) { | ||
| 153 | - _list.sort(compare); | ||
| 154 | - refresh(); | ||
| 155 | - } | ||
| 156 | - | ||
| 157 | - @override | ||
| 158 | - void close() { | ||
| 159 | - _subscriptions.forEach((observable, subscription) { | ||
| 160 | - subscription.cancel(); | ||
| 161 | - }); | ||
| 162 | - _subscriptions.clear(); | ||
| 163 | - subject.close(); | ||
| 164 | - } | ||
| 165 | - | ||
| 166 | - /// Replaces all existing items of this list with [item] | ||
| 167 | - void assign(E item) { | ||
| 168 | - clear(); | ||
| 169 | - add(item); | ||
| 170 | - } | ||
| 171 | - | ||
| 172 | - void update(void fn(Iterable<E> value)) { | ||
| 173 | - fn(value); | ||
| 174 | - refresh(); | ||
| 175 | - } | ||
| 176 | - | ||
| 177 | - /// Replaces all existing items of this list with [items] | ||
| 178 | - void assignAll(Iterable<E> items) { | ||
| 179 | - clear(); | ||
| 180 | - addAll(items); | ||
| 181 | - } | ||
| 182 | - | ||
| 183 | - @protected | ||
| 184 | - List<E> get value { | ||
| 185 | - if (getObs != null) { | ||
| 186 | - getObs.addListener(subject.stream); | ||
| 187 | - } | ||
| 188 | - return _list; | ||
| 189 | - } | ||
| 190 | - | ||
| 191 | - String get string => value.toString(); | ||
| 192 | - | ||
| 193 | - void addListener(Stream<List<E>> rxGetX) { | ||
| 194 | - if (_subscriptions.containsKey(rxGetX)) { | ||
| 195 | - return; | ||
| 196 | - } | ||
| 197 | - _subscriptions[rxGetX] = rxGetX.listen(subject.add); | ||
| 198 | - } | ||
| 199 | - | ||
| 200 | - set value(List<E> val) { | ||
| 201 | - if (_list == val) return; | ||
| 202 | - _list = val; | ||
| 203 | - refresh(); | ||
| 204 | - } | ||
| 205 | - | ||
| 206 | - Stream<List<E>> get stream => subject.stream; | ||
| 207 | - | ||
| 208 | - StreamSubscription<List<E>> listen( | ||
| 209 | - void Function(List<E>) onData, { | ||
| 210 | - Function onError, | ||
| 211 | - void Function() onDone, | ||
| 212 | - bool cancelOnError, | ||
| 213 | - }) => | ||
| 214 | - stream.listen(onData, onError: onError, onDone: onDone); | ||
| 215 | - | ||
| 216 | - /// Binds an existing [Stream<List>] to this [RxList]. | ||
| 217 | - /// You can bind multiple sources to update the value. | ||
| 218 | - /// Closing the subscription will happen automatically when the observer | ||
| 219 | - /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree. | ||
| 220 | - void bindStream(Stream<List<E>> stream) { | ||
| 221 | - _subscriptions[stream] = stream.listen((va) => value = va); | ||
| 222 | - } | ||
| 223 | - | ||
| 224 | - @override | ||
| 225 | - E get first => value.first; | ||
| 226 | - | ||
| 227 | - @override | ||
| 228 | - E get last => value.last; | ||
| 229 | - | ||
| 230 | - @override | ||
| 231 | - bool any(bool Function(E) test) { | ||
| 232 | - return value.any(test); | ||
| 233 | - } | ||
| 234 | - | ||
| 235 | - @override | ||
| 236 | - Map<int, E> asMap() { | ||
| 237 | - return value.asMap(); | ||
| 238 | - } | ||
| 239 | - | ||
| 240 | - @override | ||
| 241 | - List<R> cast<R>() { | ||
| 242 | - return value.cast<R>(); | ||
| 243 | - } | ||
| 244 | - | ||
| 245 | - @override | ||
| 246 | - bool contains(Object element) { | ||
| 247 | - return value.contains(element); | ||
| 248 | - } | ||
| 249 | - | ||
| 250 | - @override | ||
| 251 | - E elementAt(int index) { | ||
| 252 | - return value.elementAt(index); | ||
| 253 | - } | ||
| 254 | - | ||
| 255 | - @override | ||
| 256 | - bool every(bool Function(E) test) { | ||
| 257 | - return value.every(test); | ||
| 258 | - } | ||
| 259 | - | ||
| 260 | - @override | ||
| 261 | - Iterable<T> expand<T>(Iterable<T> Function(E) f) { | ||
| 262 | - return value.expand(f); | ||
| 263 | - } | ||
| 264 | - | ||
| 265 | - @override | ||
| 266 | - void fillRange(int start, int end, [E fillValue]) { | ||
| 267 | - _list.fillRange(start, end, fillValue); | ||
| 268 | - refresh(); | ||
| 269 | - } | ||
| 270 | - | ||
| 271 | - @override | ||
| 272 | - E firstWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 273 | - return value.firstWhere(test, orElse: orElse); | ||
| 274 | - } | ||
| 275 | - | ||
| 276 | - @override | ||
| 277 | - T fold<T>(T initialValue, T Function(T, E) combine) { | ||
| 278 | - return value.fold(initialValue, combine); | ||
| 279 | - } | ||
| 280 | - | ||
| 281 | - @override | ||
| 282 | - Iterable<E> followedBy(Iterable<E> other) { | ||
| 283 | - return value.followedBy(other); | ||
| 284 | - } | ||
| 285 | - | ||
| 286 | - @override | ||
| 287 | - void forEach(void Function(E) f) { | ||
| 288 | - value.forEach(f); | ||
| 289 | - } | ||
| 290 | - | ||
| 291 | - @override | ||
| 292 | - Iterable<E> getRange(int start, int end) { | ||
| 293 | - return value.getRange(start, end); | ||
| 294 | - } | ||
| 295 | - | ||
| 296 | - @override | ||
| 297 | - int indexOf(E element, [int start = 0]) { | ||
| 298 | - return value.indexOf(element, start); | ||
| 299 | - } | ||
| 300 | - | ||
| 301 | - @override | ||
| 302 | - int indexWhere(bool Function(E) test, [int start = 0]) { | ||
| 303 | - return value.indexWhere(test, start); | ||
| 304 | - } | ||
| 305 | - | ||
| 306 | - @override | ||
| 307 | - String join([String separator = ""]) { | ||
| 308 | - return value.join(separator); | ||
| 309 | - } | ||
| 310 | - | ||
| 311 | - @override | ||
| 312 | - int lastIndexOf(E element, [int start]) { | ||
| 313 | - return value.lastIndexOf(element, start); | ||
| 314 | - } | ||
| 315 | - | ||
| 316 | - @override | ||
| 317 | - int lastIndexWhere(bool Function(E) test, [int start]) { | ||
| 318 | - return value.lastIndexWhere(test, start); | ||
| 319 | - } | ||
| 320 | - | ||
| 321 | - @override | ||
| 322 | - E lastWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 323 | - return value.lastWhere(test, orElse: orElse); | ||
| 324 | - } | ||
| 325 | - | ||
| 326 | - @override | ||
| 327 | - set length(int newLength) { | ||
| 328 | - _list.length = newLength; | ||
| 329 | - refresh(); | ||
| 330 | - } | ||
| 331 | - | ||
| 332 | - @override | ||
| 333 | - Iterable<T> map<T>(T Function(E) f) { | ||
| 334 | - return value.map(f); | ||
| 335 | - } | ||
| 336 | - | ||
| 337 | - @override | ||
| 338 | - E reduce(E Function(E, E) combine) { | ||
| 339 | - return value.reduce(combine); | ||
| 340 | - } | ||
| 341 | - | ||
| 342 | - @override | ||
| 343 | - void replaceRange(int start, int end, Iterable<E> replacement) { | ||
| 344 | - _list.replaceRange(start, end, replacement); | ||
| 345 | - refresh(); | ||
| 346 | - } | ||
| 347 | - | ||
| 348 | - @override | ||
| 349 | - void retainWhere(bool Function(E) test) { | ||
| 350 | - _list.retainWhere(test); | ||
| 351 | - refresh(); | ||
| 352 | - } | ||
| 353 | - | ||
| 354 | - @override | ||
| 355 | - Iterable<E> get reversed => value.reversed; | ||
| 356 | - | ||
| 357 | - @override | ||
| 358 | - void setAll(int index, Iterable<E> iterable) { | ||
| 359 | - _list.setAll(index, iterable); | ||
| 360 | - refresh(); | ||
| 361 | - } | ||
| 362 | - | ||
| 363 | - @override | ||
| 364 | - void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { | ||
| 365 | - _list.setRange(start, end, iterable, skipCount); | ||
| 366 | - refresh(); | ||
| 367 | - } | ||
| 368 | - | ||
| 369 | - @override | ||
| 370 | - void shuffle([Random random]) { | ||
| 371 | - _list.shuffle(random); | ||
| 372 | - refresh(); | ||
| 373 | - } | ||
| 374 | - | ||
| 375 | - @override | ||
| 376 | - E get single => value.single; | ||
| 377 | - | ||
| 378 | - @override | ||
| 379 | - E singleWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 380 | - return value.singleWhere(test, orElse: orElse); | ||
| 381 | - } | ||
| 382 | - | ||
| 383 | - @override | ||
| 384 | - Iterable<E> skip(int count) { | ||
| 385 | - return value.skip(count); | ||
| 386 | - } | ||
| 387 | - | ||
| 388 | - @override | ||
| 389 | - Iterable<E> skipWhile(bool Function(E) test) { | ||
| 390 | - return value.skipWhile(test); | ||
| 391 | - } | ||
| 392 | - | ||
| 393 | - @override | ||
| 394 | - List<E> sublist(int start, [int end]) { | ||
| 395 | - return value.sublist(start, end); | ||
| 396 | - } | ||
| 397 | - | ||
| 398 | - @override | ||
| 399 | - Iterable<E> take(int count) { | ||
| 400 | - return value.take(count); | ||
| 401 | - } | ||
| 402 | - | ||
| 403 | - @override | ||
| 404 | - Iterable<E> takeWhile(bool Function(E) test) { | ||
| 405 | - return value.takeWhile(test); | ||
| 406 | - } | ||
| 407 | - | ||
| 408 | - @override | ||
| 409 | - List<E> toList({bool growable = true}) { | ||
| 410 | - return value.toList(growable: growable); | ||
| 411 | - } | ||
| 412 | - | ||
| 413 | - @override | ||
| 414 | - Set<E> toSet() { | ||
| 415 | - return value.toSet(); | ||
| 416 | - } | ||
| 417 | - | ||
| 418 | - @override | ||
| 419 | - Iterable<E> where(bool Function(E) test) { | ||
| 420 | - return value.where(test); | ||
| 421 | - } | ||
| 422 | - | ||
| 423 | - @override | ||
| 424 | - Iterable<T> whereType<T>() { | ||
| 425 | - return value.whereType<T>(); | ||
| 426 | - } | ||
| 427 | - | ||
| 428 | - @override | ||
| 429 | - set first(E value) { | ||
| 430 | - _list.first = value; | ||
| 431 | - refresh(); | ||
| 432 | - } | ||
| 433 | - | ||
| 434 | - @override | ||
| 435 | - set last(E value) { | ||
| 436 | - _list.last = value; | ||
| 437 | - refresh(); | ||
| 438 | - } | ||
| 439 | -} | ||
| 440 | - | ||
| 441 | -extension ListExtension<E> on List<E> { | ||
| 442 | - RxList<E> get obs { | ||
| 443 | - if (this != null) { | ||
| 444 | - return RxList<E>(<E>[])..addAllNonNull(this); | ||
| 445 | - } else { | ||
| 446 | - return RxList<E>(null); | ||
| 447 | - } | ||
| 448 | - } | ||
| 449 | -} | 
| 1 | -import 'dart:async'; | ||
| 2 | -import 'dart:collection'; | ||
| 3 | -import 'package:flutter/foundation.dart'; | ||
| 4 | - | ||
| 5 | -import '../rx_core/rx_impl.dart'; | ||
| 6 | -import '../rx_core/rx_interface.dart'; | ||
| 7 | -import '../rx_typedefs/rx_typedefs.dart'; | ||
| 8 | - | ||
| 9 | -class RxSet<E> implements Set<E>, RxInterface<Set<E>> { | ||
| 10 | - RxSet([Set<E> initial]) { | ||
| 11 | - if (initial != null) _set = initial; | ||
| 12 | - } | ||
| 13 | - | ||
| 14 | - Set<E> _set = <E>{}; | ||
| 15 | - | ||
| 16 | - @override | ||
| 17 | - Iterator<E> get iterator => value.iterator; | ||
| 18 | - | ||
| 19 | - @override | ||
| 20 | - bool get isEmpty => value.isEmpty; | ||
| 21 | - | ||
| 22 | - bool get canUpdate { | ||
| 23 | - return _subscriptions.length > 0; | ||
| 24 | - } | ||
| 25 | - | ||
| 26 | - @override | ||
| 27 | - bool get isNotEmpty => value.isNotEmpty; | ||
| 28 | - | ||
| 29 | - StreamController<Set<E>> subject = StreamController<Set<E>>.broadcast(); | ||
| 30 | - final _subscriptions = HashMap<Stream<Set<E>>, StreamSubscription>(); | ||
| 31 | - | ||
| 32 | - /// Adds [item] only if [condition] resolves to true. | ||
| 33 | - void addIf(dynamic condition, E item) { | ||
| 34 | - if (condition is Condition) condition = condition(); | ||
| 35 | - if (condition is bool && condition) add(item); | ||
| 36 | - } | ||
| 37 | - | ||
| 38 | - /// Adds all [items] only if [condition] resolves to true. | ||
| 39 | - void addAllIf(dynamic condition, Iterable<E> items) { | ||
| 40 | - if (condition is Condition) condition = condition(); | ||
| 41 | - if (condition is bool && condition) addAll(items); | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | - void refresh() { | ||
| 45 | - subject.add(_set); | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - /// Special override to push() element(s) in a reactive way | ||
| 49 | - /// inside the List, | ||
| 50 | - RxSet<E> operator +(Set<E> val) { | ||
| 51 | - addAll(val); | ||
| 52 | - refresh(); | ||
| 53 | - return this; | ||
| 54 | - } | ||
| 55 | - | ||
| 56 | - @override | ||
| 57 | - bool add(E value) { | ||
| 58 | - final val = _set.add(value); | ||
| 59 | - refresh(); | ||
| 60 | - return val; | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | - @override | ||
| 64 | - void addAll(Iterable<E> item) { | ||
| 65 | - _set.addAll(item); | ||
| 66 | - refresh(); | ||
| 67 | - } | ||
| 68 | - | ||
| 69 | - /// Adds only if [item] is not null. | ||
| 70 | - void addNonNull(E item) { | ||
| 71 | - if (item != null) add(item); | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - /// Adds only if [item] is not null. | ||
| 75 | - void addAllNonNull(Iterable<E> item) { | ||
| 76 | - if (item != null) addAll(item); | ||
| 77 | - } | ||
| 78 | - | ||
| 79 | - int get length => value.length; | ||
| 80 | - | ||
| 81 | - /// Removes an item from the list. | ||
| 82 | - /// | ||
| 83 | - /// This is O(N) in the number of items in the list. | ||
| 84 | - /// | ||
| 85 | - /// Returns whether the item was present in the list. | ||
| 86 | - bool remove(Object item) { | ||
| 87 | - var hasRemoved = _set.remove(item); | ||
| 88 | - if (hasRemoved) { | ||
| 89 | - refresh(); | ||
| 90 | - } | ||
| 91 | - return hasRemoved; | ||
| 92 | - } | ||
| 93 | - | ||
| 94 | - void removeWhere(bool Function(E) test) { | ||
| 95 | - _set.removeWhere(test); | ||
| 96 | - refresh(); | ||
| 97 | - } | ||
| 98 | - | ||
| 99 | - void clear() { | ||
| 100 | - _set.clear(); | ||
| 101 | - refresh(); | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | - void close() { | ||
| 105 | - _subscriptions.forEach((observable, subscription) { | ||
| 106 | - subscription.cancel(); | ||
| 107 | - }); | ||
| 108 | - _subscriptions.clear(); | ||
| 109 | - subject.close(); | ||
| 110 | - } | ||
| 111 | - | ||
| 112 | - /// Replaces all existing items of this list with [item] | ||
| 113 | - void assign(E item) { | ||
| 114 | - clear(); | ||
| 115 | - add(item); | ||
| 116 | - } | ||
| 117 | - | ||
| 118 | - void update(void fn(Iterable<E> value)) { | ||
| 119 | - fn(value); | ||
| 120 | - refresh(); | ||
| 121 | - } | ||
| 122 | - | ||
| 123 | - /// Replaces all existing items of this list with [items] | ||
| 124 | - void assignAll(Iterable<E> items) { | ||
| 125 | - clear(); | ||
| 126 | - addAll(items); | ||
| 127 | - } | ||
| 128 | - | ||
| 129 | - @protected | ||
| 130 | - Set<E> get value { | ||
| 131 | - if (getObs != null) { | ||
| 132 | - getObs.addListener(subject.stream); | ||
| 133 | - } | ||
| 134 | - return _set; | ||
| 135 | - } | ||
| 136 | - | ||
| 137 | - String get string => value.toString(); | ||
| 138 | - | ||
| 139 | - void addListener(Stream<Set<E>> rxGetX) { | ||
| 140 | - if (_subscriptions.containsKey(rxGetX)) { | ||
| 141 | - return; | ||
| 142 | - } | ||
| 143 | - _subscriptions[rxGetX] = rxGetX.listen((data) { | ||
| 144 | - subject.add(data); | ||
| 145 | - }); | ||
| 146 | - } | ||
| 147 | - | ||
| 148 | - set value(Set<E> val) { | ||
| 149 | - if (_set == val) return; | ||
| 150 | - _set = val; | ||
| 151 | - refresh(); | ||
| 152 | - } | ||
| 153 | - | ||
| 154 | - Stream<Set<E>> get stream => subject.stream; | ||
| 155 | - | ||
| 156 | - StreamSubscription<Set<E>> listen(void Function(Set<E>) onData, | ||
| 157 | - {Function onError, void Function() onDone, bool cancelOnError}) => | ||
| 158 | - stream.listen(onData, onError: onError, onDone: onDone); | ||
| 159 | - | ||
| 160 | - /// Binds an existing [Stream<Set>] to this [RxSet]. | ||
| 161 | - /// You can bind multiple sources to update the value. | ||
| 162 | - /// Closing the subscription will happen automatically when the observer | ||
| 163 | - /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree. | ||
| 164 | - void bindStream(Stream<Set<E>> stream) { | ||
| 165 | - _subscriptions[stream] = stream.listen((va) => value = va); | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - @override | ||
| 169 | - E get first => value.first; | ||
| 170 | - | ||
| 171 | - @override | ||
| 172 | - E get last => value.last; | ||
| 173 | - | ||
| 174 | - @override | ||
| 175 | - bool any(bool Function(E) test) { | ||
| 176 | - return value.any(test); | ||
| 177 | - } | ||
| 178 | - | ||
| 179 | - @override | ||
| 180 | - Set<R> cast<R>() { | ||
| 181 | - return value.cast<R>(); | ||
| 182 | - } | ||
| 183 | - | ||
| 184 | - @override | ||
| 185 | - bool contains(Object element) { | ||
| 186 | - return value.contains(element); | ||
| 187 | - } | ||
| 188 | - | ||
| 189 | - @override | ||
| 190 | - E elementAt(int index) { | ||
| 191 | - return value.elementAt(index); | ||
| 192 | - } | ||
| 193 | - | ||
| 194 | - @override | ||
| 195 | - bool every(bool Function(E) test) { | ||
| 196 | - return value.every(test); | ||
| 197 | - } | ||
| 198 | - | ||
| 199 | - @override | ||
| 200 | - Iterable<T> expand<T>(Iterable<T> Function(E) f) { | ||
| 201 | - return value.expand(f); | ||
| 202 | - } | ||
| 203 | - | ||
| 204 | - @override | ||
| 205 | - E firstWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 206 | - return value.firstWhere(test, orElse: orElse); | ||
| 207 | - } | ||
| 208 | - | ||
| 209 | - @override | ||
| 210 | - T fold<T>(T initialValue, T Function(T, E) combine) { | ||
| 211 | - return value.fold(initialValue, combine); | ||
| 212 | - } | ||
| 213 | - | ||
| 214 | - @override | ||
| 215 | - Iterable<E> followedBy(Iterable<E> other) { | ||
| 216 | - return value.followedBy(other); | ||
| 217 | - } | ||
| 218 | - | ||
| 219 | - @override | ||
| 220 | - void forEach(void Function(E) f) { | ||
| 221 | - value.forEach(f); | ||
| 222 | - } | ||
| 223 | - | ||
| 224 | - @override | ||
| 225 | - String join([String separator = ""]) { | ||
| 226 | - return value.join(separator); | ||
| 227 | - } | ||
| 228 | - | ||
| 229 | - @override | ||
| 230 | - E lastWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 231 | - return value.lastWhere(test, orElse: orElse); | ||
| 232 | - } | ||
| 233 | - | ||
| 234 | - @override | ||
| 235 | - Iterable<T> map<T>(T Function(E) f) { | ||
| 236 | - return value.map(f); | ||
| 237 | - } | ||
| 238 | - | ||
| 239 | - @override | ||
| 240 | - E reduce(E Function(E, E) combine) { | ||
| 241 | - return value.reduce(combine); | ||
| 242 | - } | ||
| 243 | - | ||
| 244 | - @override | ||
| 245 | - E get single => value.single; | ||
| 246 | - | ||
| 247 | - @override | ||
| 248 | - E singleWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 249 | - return value.singleWhere(test, orElse: orElse); | ||
| 250 | - } | ||
| 251 | - | ||
| 252 | - @override | ||
| 253 | - Iterable<E> skip(int count) { | ||
| 254 | - return value.skip(count); | ||
| 255 | - } | ||
| 256 | - | ||
| 257 | - @override | ||
| 258 | - Iterable<E> skipWhile(bool Function(E) test) { | ||
| 259 | - return value.skipWhile(test); | ||
| 260 | - } | ||
| 261 | - | ||
| 262 | - @override | ||
| 263 | - Iterable<E> take(int count) { | ||
| 264 | - return value.take(count); | ||
| 265 | - } | ||
| 266 | - | ||
| 267 | - @override | ||
| 268 | - Iterable<E> takeWhile(bool Function(E) test) { | ||
| 269 | - return value.takeWhile(test); | ||
| 270 | - } | ||
| 271 | - | ||
| 272 | - @override | ||
| 273 | - List<E> toList({bool growable = true}) { | ||
| 274 | - return value.toList(growable: growable); | ||
| 275 | - } | ||
| 276 | - | ||
| 277 | - @override | ||
| 278 | - Set<E> toSet() { | ||
| 279 | - return value.toSet(); | ||
| 280 | - } | ||
| 281 | - | ||
| 282 | - @override | ||
| 283 | - Iterable<E> where(bool Function(E) test) { | ||
| 284 | - return value.where(test); | ||
| 285 | - } | ||
| 286 | - | ||
| 287 | - @override | ||
| 288 | - Iterable<T> whereType<T>() { | ||
| 289 | - return value.whereType<T>(); | ||
| 290 | - } | ||
| 291 | - | ||
| 292 | - @override | ||
| 293 | - bool containsAll(Iterable<Object> other) { | ||
| 294 | - return value.containsAll(other); | ||
| 295 | - } | ||
| 296 | - | ||
| 297 | - @override | ||
| 298 | - Set<E> difference(Set<Object> other) { | ||
| 299 | - return value.difference(other); | ||
| 300 | - } | ||
| 301 | - | ||
| 302 | - @override | ||
| 303 | - Set<E> intersection(Set<Object> other) { | ||
| 304 | - return value.intersection(other); | ||
| 305 | - } | ||
| 306 | - | ||
| 307 | - @override | ||
| 308 | - E lookup(Object object) { | ||
| 309 | - return value.lookup(object); | ||
| 310 | - } | ||
| 311 | - | ||
| 312 | - @override | ||
| 313 | - void removeAll(Iterable<Object> elements) { | ||
| 314 | - _set.removeAll(elements); | ||
| 315 | - refresh(); | ||
| 316 | - } | ||
| 317 | - | ||
| 318 | - @override | ||
| 319 | - void retainAll(Iterable<Object> elements) { | ||
| 320 | - _set.retainAll(elements); | ||
| 321 | - refresh(); | ||
| 322 | - } | ||
| 323 | - | ||
| 324 | - @override | ||
| 325 | - void retainWhere(bool Function(E) E) { | ||
| 326 | - _set.retainWhere(E); | ||
| 327 | - refresh(); | ||
| 328 | - } | ||
| 329 | - | ||
| 330 | - @override | ||
| 331 | - Set<E> union(Set<E> other) { | ||
| 332 | - return value.union(other); | ||
| 333 | - } | ||
| 334 | -} | ||
| 335 | - | ||
| 336 | -extension SetExtension<E> on Set<E> { | ||
| 337 | - RxSet<E> get obs { | ||
| 338 | - if (this != null) { | ||
| 339 | - return RxSet<E>(<E>{})..addAllNonNull(this); | ||
| 340 | - } else { | ||
| 341 | - return RxSet<E>(null); | ||
| 342 | - } | ||
| 343 | - } | ||
| 344 | -} | 
lib/get_rx/src/rx_stream/get_stream.dart
0 → 100644
| 1 | +part of rx_stream; | ||
| 2 | + | ||
| 3 | +/// [GetStream] is the lightest and most performative way of working | ||
| 4 | +/// with events at Dart. You sintaxe is like StreamController, but it works | ||
| 5 | +/// with simple callbacks. In this way, every event calls only one function. | ||
| 6 | +/// There is no buffering, to very low memory consumption. | ||
| 7 | +/// event [add] will add a object to stream. [addError] will add a error | ||
| 8 | +/// to stream. [listen] is a very light StreamSubscription interface. | ||
| 9 | +/// Is possible take the last value with [value] property. | ||
| 10 | +class GetStream<T> { | ||
| 11 | + LightListenable<T> listenable = LightListenable<T>(); | ||
| 12 | + | ||
| 13 | + T _value; | ||
| 14 | + | ||
| 15 | + T get value => _value; | ||
| 16 | + | ||
| 17 | + void add(T event) { | ||
| 18 | + _value = event; | ||
| 19 | + _checkIfDisposed(); | ||
| 20 | + listenable.notifyData(event); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + void _checkIfDisposed([bool isClosed = false]) { | ||
| 24 | + if (listenable == null) { | ||
| 25 | + throw '''[LightStream] Error: | ||
| 26 | +You cannot ${isClosed ? "close" : "add events to"} a closed stream.'''; | ||
| 27 | + } | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + void addError(Object error, [StackTrace stackTrace]) { | ||
| 31 | + _checkIfDisposed(); | ||
| 32 | + listenable.notifyError(error, stackTrace); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + void close() { | ||
| 36 | + _checkIfDisposed(true); | ||
| 37 | + listenable.notifyDone(); | ||
| 38 | + listenable.dispose(); | ||
| 39 | + listenable = null; | ||
| 40 | + _value = null; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + int get length => listenable.length; | ||
| 44 | + | ||
| 45 | + bool get hasListeners => listenable.hasListeners; | ||
| 46 | + | ||
| 47 | + bool get isClosed => listenable == null; | ||
| 48 | + | ||
| 49 | + LightSubscription<T> listen(void Function(T event) onData, | ||
| 50 | + {Function onError, void Function() onDone, bool cancelOnError}) { | ||
| 51 | + final subs = LightSubscription<T>(listenable) | ||
| 52 | + ..onData(onData) | ||
| 53 | + ..onError(onError) | ||
| 54 | + ..onDone(onDone); | ||
| 55 | + listenable.addSubscription(subs); | ||
| 56 | + return subs; | ||
| 57 | + } | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +class LightListenable<T> { | ||
| 61 | + List<LightSubscription<T>> _onData = <LightSubscription<T>>[]; | ||
| 62 | + | ||
| 63 | + void removeSubscription(LightSubscription<T> subs) { | ||
| 64 | + _onData.remove(subs); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + void addSubscription(LightSubscription<T> subs) { | ||
| 68 | + _onData.add(subs); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + int get length => _onData?.length; | ||
| 72 | + | ||
| 73 | + bool get hasListeners => _onData.isNotEmpty; | ||
| 74 | + | ||
| 75 | + void notifyData(T data) { | ||
| 76 | + _checkIfDisposed(); | ||
| 77 | + for (final item in _onData) { | ||
| 78 | + if (item.isPaused) { | ||
| 79 | + break; | ||
| 80 | + } | ||
| 81 | + item._data?.call(data); | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + void _checkIfDisposed() { | ||
| 86 | + if (isDisposed) { | ||
| 87 | + throw '[LightStream] Error: You cannot add events to a closed stream.'; | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + void notifyError(Object error, [StackTrace stackTrace]) { | ||
| 92 | + _checkIfDisposed(); | ||
| 93 | + for (final item in _onData) { | ||
| 94 | + if (item.isPaused) { | ||
| 95 | + break; | ||
| 96 | + } | ||
| 97 | + item._onError?.call(error, stackTrace); | ||
| 98 | + if (item.cancelOnError) { | ||
| 99 | + item.cancel?.call(); | ||
| 100 | + item._onDone?.call(); | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + void notifyDone() { | ||
| 106 | + _checkIfDisposed(); | ||
| 107 | + for (final item in _onData) { | ||
| 108 | + if (item.isPaused) { | ||
| 109 | + break; | ||
| 110 | + } | ||
| 111 | + item._onDone?.call(); | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + void dispose() => _onData = null; | ||
| 116 | + | ||
| 117 | + bool get isDisposed => _onData == null; | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +class LightSubscription<T> extends StreamSubscription<T> { | ||
| 121 | + final LightListenable<T> listener; | ||
| 122 | + | ||
| 123 | + LightSubscription(this.listener); | ||
| 124 | + | ||
| 125 | + bool cancelOnError = false; | ||
| 126 | + | ||
| 127 | + @override | ||
| 128 | + Future<void> cancel() async => listener.removeSubscription(this); | ||
| 129 | + | ||
| 130 | + OnData<T> _data; | ||
| 131 | + | ||
| 132 | + Function _onError; | ||
| 133 | + | ||
| 134 | + Callback _onDone; | ||
| 135 | + | ||
| 136 | + bool _isPaused = false; | ||
| 137 | + | ||
| 138 | + @override | ||
| 139 | + void onData(OnData<T> handleData) => _data = handleData; | ||
| 140 | + | ||
| 141 | + @override | ||
| 142 | + void onError(Function handleError) => _onError = handleError; | ||
| 143 | + | ||
| 144 | + @override | ||
| 145 | + void onDone(Callback handleDone) => _onDone = handleDone; | ||
| 146 | + | ||
| 147 | + @override | ||
| 148 | + void pause([Future<void> resumeSignal]) => _isPaused = true; | ||
| 149 | + | ||
| 150 | + @override | ||
| 151 | + void resume() => _isPaused = false; | ||
| 152 | + | ||
| 153 | + @override | ||
| 154 | + bool get isPaused => _isPaused; | ||
| 155 | + | ||
| 156 | + @override | ||
| 157 | + Future<E> asFuture<E>([E futureValue]) => Future.value(futureValue); | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | +class GetStreamTransformation<T> extends Stream<T> { | ||
| 161 | + final LightListenable<T> listenable; | ||
| 162 | + | ||
| 163 | + GetStreamTransformation(this.listenable); | ||
| 164 | + | ||
| 165 | + @override | ||
| 166 | + LightSubscription<T> listen(void Function(T event) onData, | ||
| 167 | + {Function onError, void Function() onDone, bool cancelOnError}) { | ||
| 168 | + final subs = LightSubscription<T>(listenable) | ||
| 169 | + ..onData(onData) | ||
| 170 | + ..onError(onError) | ||
| 171 | + ..onDone(onDone); | ||
| 172 | + listenable.addSubscription(subs); | ||
| 173 | + return subs; | ||
| 174 | + } | ||
| 175 | +} | 
lib/get_rx/src/rx_stream/mini_stream.dart
0 → 100644
| 1 | +part of rx_stream; | ||
| 2 | + | ||
| 3 | +class Node<T> { | ||
| 4 | + T data; | ||
| 5 | + Node<T> next; | ||
| 6 | + Node({this.data, this.next}); | ||
| 7 | +} | ||
| 8 | + | ||
| 9 | +class MiniSubscription<T> { | ||
| 10 | + const MiniSubscription( | ||
| 11 | + this.data, this.onError, this.onDone, this.cancelOnError, this.listener); | ||
| 12 | + final OnData<T> data; | ||
| 13 | + final Function onError; | ||
| 14 | + final Callback onDone; | ||
| 15 | + final bool cancelOnError; | ||
| 16 | + | ||
| 17 | + Future<void> cancel() async => listener.removeListener(this); | ||
| 18 | + | ||
| 19 | + final FastList<T> listener; | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +class MiniStream<T> { | ||
| 23 | + FastList<T> listenable = FastList<T>(); | ||
| 24 | + | ||
| 25 | + T _value; | ||
| 26 | + | ||
| 27 | + T get value => _value; | ||
| 28 | + | ||
| 29 | + set value(T val) { | ||
| 30 | + add(val); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + void add(T event) { | ||
| 34 | + assert(listenable != null); | ||
| 35 | + _value = event; | ||
| 36 | + listenable._notifyData(event); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + void addError(Object error, [StackTrace stackTrace]) { | ||
| 40 | + assert(listenable != null); | ||
| 41 | + listenable._notifyError(error, stackTrace); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + int get length => listenable.length; | ||
| 45 | + | ||
| 46 | + bool get hasListeners => listenable.isNotEmpty; | ||
| 47 | + | ||
| 48 | + bool get isClosed => listenable == null; | ||
| 49 | + | ||
| 50 | + MiniSubscription<T> listen(void Function(T event) onData, | ||
| 51 | + {Function onError, void Function() onDone, bool cancelOnError = false}) { | ||
| 52 | + final subs = MiniSubscription<T>( | ||
| 53 | + onData, | ||
| 54 | + onError, | ||
| 55 | + onDone, | ||
| 56 | + cancelOnError, | ||
| 57 | + listenable, | ||
| 58 | + ); | ||
| 59 | + listenable.addListener(subs); | ||
| 60 | + return subs; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + void close() { | ||
| 64 | + if (listenable == null) { | ||
| 65 | + throw 'You can not close a closed Stream'; | ||
| 66 | + } | ||
| 67 | + listenable._notifyDone(); | ||
| 68 | + listenable = null; | ||
| 69 | + _value = null; | ||
| 70 | + } | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +class FastList<T> { | ||
| 74 | + Node<MiniSubscription<T>> _head; | ||
| 75 | + | ||
| 76 | + void _notifyData(T data) { | ||
| 77 | + var currentNode = _head; | ||
| 78 | + do { | ||
| 79 | + currentNode.data.data(data); | ||
| 80 | + currentNode = currentNode.next; | ||
| 81 | + } while (currentNode != null); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + void _notifyDone() { | ||
| 85 | + var currentNode = _head; | ||
| 86 | + do { | ||
| 87 | + currentNode.data.onDone?.call(); | ||
| 88 | + currentNode = currentNode.next; | ||
| 89 | + } while (currentNode != null); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + void _notifyError(Object error, [StackTrace stackTrace]) { | ||
| 93 | + var currentNode = _head; | ||
| 94 | + while (currentNode != null) { | ||
| 95 | + currentNode.data.onError?.call(error, stackTrace); | ||
| 96 | + currentNode = currentNode.next; | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + /// Checks if this list is empty | ||
| 101 | + bool get isEmpty => _head == null; | ||
| 102 | + | ||
| 103 | + bool get isNotEmpty => !isEmpty; | ||
| 104 | + | ||
| 105 | + /// Returns the length of this list | ||
| 106 | + int get length { | ||
| 107 | + var length = 0; | ||
| 108 | + var currentNode = _head; | ||
| 109 | + | ||
| 110 | + while (currentNode != null) { | ||
| 111 | + currentNode = currentNode.next; | ||
| 112 | + length++; | ||
| 113 | + } | ||
| 114 | + return length; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + /// Shows the element at position [position]. `null` for invalid positions. | ||
| 118 | + MiniSubscription<T> _elementAt(int position) { | ||
| 119 | + if (isEmpty || length < position || position < 0) return null; | ||
| 120 | + | ||
| 121 | + var node = _head; | ||
| 122 | + var current = 0; | ||
| 123 | + | ||
| 124 | + while (current != position) { | ||
| 125 | + node = node.next; | ||
| 126 | + current++; | ||
| 127 | + } | ||
| 128 | + return node.data; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + /// Inserts [data] at the end of the list. | ||
| 132 | + void addListener(MiniSubscription<T> data) { | ||
| 133 | + var newNode = Node(data: data); | ||
| 134 | + | ||
| 135 | + if (isEmpty) { | ||
| 136 | + _head = newNode; | ||
| 137 | + } else { | ||
| 138 | + var currentNode = _head; | ||
| 139 | + while (currentNode.next != null) { | ||
| 140 | + currentNode = currentNode.next; | ||
| 141 | + } | ||
| 142 | + currentNode.next = newNode; | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + bool contains(T element) { | ||
| 147 | + var length = this.length; | ||
| 148 | + for (var i = 0; i < length; i++) { | ||
| 149 | + if (_elementAt(i) == element) return true; | ||
| 150 | + if (length != this.length) { | ||
| 151 | + throw ConcurrentModificationError(this); | ||
| 152 | + } | ||
| 153 | + } | ||
| 154 | + return false; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + void removeListener(MiniSubscription<T> element) { | ||
| 158 | + var length = this.length; | ||
| 159 | + for (var i = 0; i < length; i++) { | ||
| 160 | + if (_elementAt(i) == element) { | ||
| 161 | + _removeAt(i); | ||
| 162 | + break; | ||
| 163 | + } | ||
| 164 | + } | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + MiniSubscription<T> _removeAt(int position) { | ||
| 168 | + var index = 0; | ||
| 169 | + var currentNode = _head; | ||
| 170 | + Node<MiniSubscription<T>> previousNode; | ||
| 171 | + | ||
| 172 | + if (isEmpty || length < position || position < 0) { | ||
| 173 | + throw Exception('Invalid position'); | ||
| 174 | + } else if (position == 0) { | ||
| 175 | + _head = _head.next; | ||
| 176 | + } else { | ||
| 177 | + while (index != position) { | ||
| 178 | + previousNode = currentNode; | ||
| 179 | + currentNode = currentNode.next; | ||
| 180 | + index++; | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + if (previousNode == null) { | ||
| 184 | + _head = null; | ||
| 185 | + } else { | ||
| 186 | + previousNode.next = currentNode.next; | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + currentNode.next = null; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + return currentNode.data; | ||
| 193 | + } | ||
| 194 | +} | 
lib/get_rx/src/rx_stream/rx_stream.dart
0 → 100644
| 1 | -import 'dart:async'; | ||
| 2 | -import 'dart:collection'; | ||
| 3 | -import '../rx_core/rx_interface.dart'; | ||
| 4 | -part 'rx_num.dart'; | 1 | +part of rx_types; | 
| 5 | 2 | ||
| 6 | /// global object that registers against `GetX` and `Obx`, and allows the | 3 | /// global object that registers against `GetX` and `Obx`, and allows the | 
| 7 | /// reactivity | 4 | /// reactivity | 
| 8 | /// of those `Widgets` and Rx values. | 5 | /// of those `Widgets` and Rx values. | 
| 9 | RxInterface getObs; | 6 | RxInterface getObs; | 
| 10 | 7 | ||
| 11 | -/// Base Rx class that manages all the stream logic for any Type. | ||
| 12 | -abstract class _RxImpl<T> implements RxInterface<T> { | ||
| 13 | - _RxImpl(T initial) { | ||
| 14 | - _value = initial; | ||
| 15 | - } | ||
| 16 | - StreamController<T> subject = StreamController<T>.broadcast(); | ||
| 17 | - final _subscriptions = HashMap<Stream<T>, StreamSubscription>(); | ||
| 18 | - | ||
| 19 | - T _value; | ||
| 20 | - | 8 | +mixin RxObjectMixin<T> { | 
| 9 | + GetStream<T> subject = GetStream<T>(); | ||
| 10 | + final _subscriptions = <StreamSubscription>[]; | ||
| 21 | bool get canUpdate => _subscriptions.isNotEmpty; | 11 | bool get canUpdate => _subscriptions.isNotEmpty; | 
| 22 | 12 | ||
| 23 | - /// Makes this Rx looks like a function so you can update a new | ||
| 24 | - /// value using [rx(someOtherValue)]. Practical to assign the Rx directly | ||
| 25 | - /// to some Widget that has a signature ::onChange( value ) | ||
| 26 | - /// | ||
| 27 | - /// Example: | ||
| 28 | - /// ``` | ||
| 29 | - /// final myText = 'GetX rocks!'.obs; | ||
| 30 | - /// | ||
| 31 | - /// // in your Constructor, just to check it works :P | ||
| 32 | - /// ever( myText, print ) ; | ||
| 33 | - /// | ||
| 34 | - /// // in your build(BuildContext) { | ||
| 35 | - /// TextField( | ||
| 36 | - /// onChanged: myText, | ||
| 37 | - /// ), | ||
| 38 | - ///``` | ||
| 39 | - T call([T v]) { | ||
| 40 | - if (v != null) { | ||
| 41 | - value = v; | ||
| 42 | - } | ||
| 43 | - return value; | ||
| 44 | - } | 13 | + T _value; | 
| 45 | 14 | ||
| 46 | /// Makes a direct update of [value] adding it to the Stream | 15 | /// Makes a direct update of [value] adding it to the Stream | 
| 47 | /// useful when you make use of Rx for custom Types to referesh your UI. | 16 | /// useful when you make use of Rx for custom Types to referesh your UI. | 
| @@ -65,31 +34,6 @@ abstract class _RxImpl<T> implements RxInterface<T> { | @@ -65,31 +34,6 @@ abstract class _RxImpl<T> implements RxInterface<T> { | ||
| 65 | subject.add(value); | 34 | subject.add(value); | 
| 66 | } | 35 | } | 
| 67 | 36 | ||
| 68 | - /// Uses a callback to update [value] internally, similar to [refresh], | ||
| 69 | - /// but provides the current value as the argument. | ||
| 70 | - /// Makes sense for custom Rx types (like Models). | ||
| 71 | - /// | ||
| 72 | - /// Sample: | ||
| 73 | - /// ``` | ||
| 74 | - /// class Person { | ||
| 75 | - /// String name, last; | ||
| 76 | - /// int age; | ||
| 77 | - /// Person({this.name, this.last, this.age}); | ||
| 78 | - /// @override | ||
| 79 | - /// String toString() => '$name $last, $age years old'; | ||
| 80 | - /// } | ||
| 81 | - /// | ||
| 82 | - /// final person = Person(name: 'John', last: 'Doe', age: 18).obs; | ||
| 83 | - /// person.update((person) { | ||
| 84 | - /// person.name = 'Roi'; | ||
| 85 | - /// }); | ||
| 86 | - /// print( person ); | ||
| 87 | - /// ``` | ||
| 88 | - void update(void fn(T val)) { | ||
| 89 | - fn(_value); | ||
| 90 | - subject.add(_value); | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | /// updates the value to [null] and adds it to the Stream. | 37 | /// updates the value to [null] and adds it to the Stream. | 
| 94 | /// Even with null-safety coming, is still an important feature to support, as | 38 | /// Even with null-safety coming, is still an important feature to support, as | 
| 95 | /// [call()] doesn't accept [null] values. For instance, | 39 | /// [call()] doesn't accept [null] values. For instance, | 
| @@ -104,6 +48,53 @@ abstract class _RxImpl<T> implements RxInterface<T> { | @@ -104,6 +48,53 @@ abstract class _RxImpl<T> implements RxInterface<T> { | ||
| 104 | subject.add(_value = null); | 48 | subject.add(_value = null); | 
| 105 | } | 49 | } | 
| 106 | 50 | ||
| 51 | + /// Closes the subscriptions for this Rx, releasing the resources. | ||
| 52 | + void close() { | ||
| 53 | + for (final subscription in _subscriptions) { | ||
| 54 | + subscription?.cancel(); | ||
| 55 | + } | ||
| 56 | + _subscriptions.clear(); | ||
| 57 | + subject.close(); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + /// Makes this Rx looks like a function so you can update a new | ||
| 61 | + /// value using [rx(someOtherValue)]. Practical to assign the Rx directly | ||
| 62 | + /// to some Widget that has a signature ::onChange( value ) | ||
| 63 | + /// | ||
| 64 | + /// Example: | ||
| 65 | + /// ``` | ||
| 66 | + /// final myText = 'GetX rocks!'.obs; | ||
| 67 | + /// | ||
| 68 | + /// // in your Constructor, just to check it works :P | ||
| 69 | + /// ever( myText, print ) ; | ||
| 70 | + /// | ||
| 71 | + /// // in your build(BuildContext) { | ||
| 72 | + /// TextField( | ||
| 73 | + /// onChanged: myText, | ||
| 74 | + /// ), | ||
| 75 | + ///``` | ||
| 76 | + T call([T v]) { | ||
| 77 | + if (v != null) { | ||
| 78 | + value = v; | ||
| 79 | + } | ||
| 80 | + return value; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + /// This is an internal method. | ||
| 84 | + /// Subscribe to changes on the inner stream. | ||
| 85 | + void addListener(GetStream<T> rxGetx) { | ||
| 86 | + if (_subscriptions.contains(rxGetx.listen)) { | ||
| 87 | + return; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + final subs = rxGetx.listen((data) { | ||
| 91 | + subject.add(data); | ||
| 92 | + }); | ||
| 93 | + _subscriptions.add(subs); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + bool firstRebuild = true; | ||
| 97 | + | ||
| 107 | /// Same as `toString()` but using a getter. | 98 | /// Same as `toString()` but using a getter. | 
| 108 | String get string => value.toString(); | 99 | String get string => value.toString(); | 
| 109 | 100 | ||
| @@ -128,26 +119,6 @@ abstract class _RxImpl<T> implements RxInterface<T> { | @@ -128,26 +119,6 @@ abstract class _RxImpl<T> implements RxInterface<T> { | ||
| 128 | // ignore: avoid_equals_and_hash_code_on_mutable_classes | 119 | // ignore: avoid_equals_and_hash_code_on_mutable_classes | 
| 129 | int get hashCode => _value.hashCode; | 120 | int get hashCode => _value.hashCode; | 
| 130 | 121 | ||
| 131 | - /// Closes the subscriptions for this Rx, releasing the resources. | ||
| 132 | - void close() { | ||
| 133 | - _subscriptions.forEach((observable, subscription) => subscription.cancel()); | ||
| 134 | - _subscriptions.clear(); | ||
| 135 | - subject.close(); | ||
| 136 | - } | ||
| 137 | - | ||
| 138 | - /// This is an internal method. | ||
| 139 | - /// Subscribe to changes on the inner stream. | ||
| 140 | - void addListener(Stream<T> rxGetx) { | ||
| 141 | - if (_subscriptions.containsKey(rxGetx)) { | ||
| 142 | - return; | ||
| 143 | - } | ||
| 144 | - _subscriptions[rxGetx] = rxGetx.listen((data) { | ||
| 145 | - subject.add(data); | ||
| 146 | - }); | ||
| 147 | - } | ||
| 148 | - | ||
| 149 | - bool firstRebuild = true; | ||
| 150 | - | ||
| 151 | /// Updates the [value] and adds it to the stream, updating the observer | 122 | /// Updates the [value] and adds it to the stream, updating the observer | 
| 152 | /// Widget, only if it's different from the previous value. | 123 | /// Widget, only if it's different from the previous value. | 
| 153 | set value(T val) { | 124 | set value(T val) { | 
| @@ -160,26 +131,63 @@ abstract class _RxImpl<T> implements RxInterface<T> { | @@ -160,26 +131,63 @@ abstract class _RxImpl<T> implements RxInterface<T> { | ||
| 160 | /// Returns the current [value] | 131 | /// Returns the current [value] | 
| 161 | T get value { | 132 | T get value { | 
| 162 | if (getObs != null) { | 133 | if (getObs != null) { | 
| 163 | - getObs.addListener(subject.stream); | 134 | + getObs.addListener(subject); | 
| 164 | } | 135 | } | 
| 165 | return _value; | 136 | return _value; | 
| 166 | } | 137 | } | 
| 167 | 138 | ||
| 168 | - Stream<T> get stream => subject.stream; | 139 | + Stream<T> get stream => GetStreamTransformation<T>(subject.listenable); | 
| 169 | 140 | ||
| 170 | - StreamSubscription<T> listen(void Function(T) onData, | ||
| 171 | - {Function onError, void Function() onDone, bool cancelOnError}) => | ||
| 172 | - stream.listen(onData, onError: onError, onDone: onDone); | 141 | + StreamSubscription<T> listen( | 
| 142 | + void Function(T) onData, { | ||
| 143 | + Function onError, | ||
| 144 | + void Function() onDone, | ||
| 145 | + bool cancelOnError = false, | ||
| 146 | + }) => | ||
| 147 | + subject.listen(onData, | ||
| 148 | + onError: onError, onDone: onDone, cancelOnError: cancelOnError); | ||
| 173 | 149 | ||
| 174 | /// Binds an existing [Stream<T>] to this Rx<T> to keep the values in sync. | 150 | /// Binds an existing [Stream<T>] to this Rx<T> to keep the values in sync. | 
| 175 | /// You can bind multiple sources to update the value. | 151 | /// You can bind multiple sources to update the value. | 
| 176 | /// Closing the subscription will happen automatically when the observer | 152 | /// Closing the subscription will happen automatically when the observer | 
| 177 | /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree. | 153 | /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree. | 
| 178 | void bindStream(Stream<T> stream) { | 154 | void bindStream(Stream<T> stream) { | 
| 179 | - _subscriptions[stream] = stream.listen((va) => value = va); | 155 | + _subscriptions.add(stream.listen((va) => value = va)); | 
| 156 | + } | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | +/// Base Rx class that manages all the stream logic for any Type. | ||
| 160 | +abstract class _RxImpl<T> with RxObjectMixin<T> implements RxInterface<T> { | ||
| 161 | + _RxImpl(T initial) { | ||
| 162 | + _value = initial; | ||
| 180 | } | 163 | } | 
| 181 | 164 | ||
| 182 | Stream<R> map<R>(R mapper(T data)) => stream.map(mapper); | 165 | Stream<R> map<R>(R mapper(T data)) => stream.map(mapper); | 
| 166 | + | ||
| 167 | + /// Uses a callback to update [value] internally, similar to [refresh], | ||
| 168 | + /// but provides the current value as the argument. | ||
| 169 | + /// Makes sense for custom Rx types (like Models). | ||
| 170 | + /// | ||
| 171 | + /// Sample: | ||
| 172 | + /// ``` | ||
| 173 | + /// class Person { | ||
| 174 | + /// String name, last; | ||
| 175 | + /// int age; | ||
| 176 | + /// Person({this.name, this.last, this.age}); | ||
| 177 | + /// @override | ||
| 178 | + /// String toString() => '$name $last, $age years old'; | ||
| 179 | + /// } | ||
| 180 | + /// | ||
| 181 | + /// final person = Person(name: 'John', last: 'Doe', age: 18).obs; | ||
| 182 | + /// person.update((person) { | ||
| 183 | + /// person.name = 'Roi'; | ||
| 184 | + /// }); | ||
| 185 | + /// print( person ); | ||
| 186 | + /// ``` | ||
| 187 | + void update(void fn(T val)) { | ||
| 188 | + fn(_value); | ||
| 189 | + subject.add(_value); | ||
| 190 | + } | ||
| 183 | } | 191 | } | 
| 184 | 192 | ||
| 185 | /// Rx class for `bool` Type. | 193 | /// Rx class for `bool` Type. | 
| @@ -202,6 +210,7 @@ class RxBool extends _RxImpl<bool> { | @@ -202,6 +210,7 @@ class RxBool extends _RxImpl<bool> { | ||
| 202 | return this; | 210 | return this; | 
| 203 | } | 211 | } | 
| 204 | 212 | ||
| 213 | + @override | ||
| 205 | String toString() { | 214 | String toString() { | 
| 206 | return value ? "true" : "false"; | 215 | return value ? "true" : "false"; | 
| 207 | } | 216 | } | 
| 1 | -import 'dart:async'; | ||
| 2 | -import '../rx_typedefs/rx_typedefs.dart'; | 1 | +part of rx_types; | 
| 3 | 2 | ||
| 4 | /// This class is the foundation for all reactive (Rx) classes that makes Get | 3 | /// This class is the foundation for all reactive (Rx) classes that makes Get | 
| 5 | /// so powerful. | 4 | /// so powerful. | 
| @@ -8,10 +7,10 @@ import '../rx_typedefs/rx_typedefs.dart'; | @@ -8,10 +7,10 @@ import '../rx_typedefs/rx_typedefs.dart'; | ||
| 8 | abstract class RxInterface<T> { | 7 | abstract class RxInterface<T> { | 
| 9 | RxInterface([T initial]); | 8 | RxInterface([T initial]); | 
| 10 | 9 | ||
| 11 | - StreamController<T> subject; | 10 | + GetStream<T> subject; | 
| 12 | 11 | ||
| 13 | /// Adds a listener to stream | 12 | /// Adds a listener to stream | 
| 14 | - void addListener(Stream<T> rxGetx); | 13 | + void addListener(GetStream<T> rxGetx); | 
| 15 | 14 | ||
| 16 | bool get canUpdate; | 15 | bool get canUpdate; | 
| 17 | 16 | ||
| @@ -21,8 +20,10 @@ abstract class RxInterface<T> { | @@ -21,8 +20,10 @@ abstract class RxInterface<T> { | ||
| 21 | 20 | ||
| 22 | /// Closes the stream | 21 | /// Closes the stream | 
| 23 | // FIXME: shouldn't we expose the returned future? | 22 | // FIXME: shouldn't we expose the returned future? | 
| 24 | - void close() => subject?.close(); | 23 | + void close(); | 
| 25 | 24 | ||
| 26 | /// Calls [callback] with current value, when the value changes. | 25 | /// Calls [callback] with current value, when the value changes. | 
| 27 | - StreamSubscription<T> listen(ValueCallback<T> callback); | 26 | + StreamSubscription<T> listen(void Function(T event) onData, | 
| 27 | + {Function onError, void Function() onDone, bool cancelOnError}); | ||
| 28 | } | 28 | } | 
| 29 | + | 
| 1 | -part of 'rx_impl.dart'; | 1 | +part of rx_types; | 
| 2 | 2 | ||
| 3 | /// Base Rx class for all num Rx's. | 3 | /// Base Rx class for all num Rx's. | 
| 4 | abstract class _BaseRxNum<T extends num> extends _RxImpl<T> { | 4 | abstract class _BaseRxNum<T extends num> extends _RxImpl<T> { | 
| @@ -299,23 +299,29 @@ class RxDouble extends _BaseRxNum<double> { | @@ -299,23 +299,29 @@ class RxDouble extends _BaseRxNum<double> { | ||
| 299 | } | 299 | } | 
| 300 | 300 | ||
| 301 | /// Multiplication operator. | 301 | /// Multiplication operator. | 
| 302 | + @override | ||
| 302 | double operator *(num other) => value * other; | 303 | double operator *(num other) => value * other; | 
| 303 | 304 | ||
| 305 | + @override | ||
| 304 | double operator %(num other) => value % other; | 306 | double operator %(num other) => value % other; | 
| 305 | 307 | ||
| 306 | /// Division operator. | 308 | /// Division operator. | 
| 309 | + @override | ||
| 307 | double operator /(num other) => value / other; | 310 | double operator /(num other) => value / other; | 
| 308 | 311 | ||
| 309 | /// Truncating division operator. | 312 | /// Truncating division operator. | 
| 310 | /// | 313 | /// | 
| 311 | /// The result of the truncating division `a ~/ b` is equivalent to | 314 | /// The result of the truncating division `a ~/ b` is equivalent to | 
| 312 | /// `(a / b).truncate()`. | 315 | /// `(a / b).truncate()`. | 
| 316 | + @override | ||
| 313 | int operator ~/(num other) => value ~/ other; | 317 | int operator ~/(num other) => value ~/ other; | 
| 314 | 318 | ||
| 315 | /// Negate operator. */ | 319 | /// Negate operator. */ | 
| 320 | + @override | ||
| 316 | double operator -() => -value; | 321 | double operator -() => -value; | 
| 317 | 322 | ||
| 318 | /// Returns the absolute value of this [double]. | 323 | /// Returns the absolute value of this [double]. | 
| 324 | + @override | ||
| 319 | double abs() => value.abs(); | 325 | double abs() => value.abs(); | 
| 320 | 326 | ||
| 321 | /// Returns the sign of the double's numerical value. | 327 | /// Returns the sign of the double's numerical value. | 
| @@ -323,6 +329,7 @@ class RxDouble extends _BaseRxNum<double> { | @@ -323,6 +329,7 @@ class RxDouble extends _BaseRxNum<double> { | ||
| 323 | /// Returns -1.0 if the value is less than zero, | 329 | /// Returns -1.0 if the value is less than zero, | 
| 324 | /// +1.0 if the value is greater than zero, | 330 | /// +1.0 if the value is greater than zero, | 
| 325 | /// and the value itself if it is -0.0, 0.0 or NaN. | 331 | /// and the value itself if it is -0.0, 0.0 or NaN. | 
| 332 | + @override | ||
| 326 | double get sign => value.sign; | 333 | double get sign => value.sign; | 
| 327 | 334 | ||
| 328 | /// Returns the integer closest to `this`. | 335 | /// Returns the integer closest to `this`. | 
| @@ -331,22 +338,26 @@ class RxDouble extends _BaseRxNum<double> { | @@ -331,22 +338,26 @@ class RxDouble extends _BaseRxNum<double> { | ||
| 331 | /// `(3.5).round() == 4` and `(-3.5).round() == -4`. | 338 | /// `(3.5).round() == 4` and `(-3.5).round() == -4`. | 
| 332 | /// | 339 | /// | 
| 333 | /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError]. | 340 | /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError]. | 
| 341 | + @override | ||
| 334 | int round() => value.round(); | 342 | int round() => value.round(); | 
| 335 | 343 | ||
| 336 | /// Returns the greatest integer no greater than `this`. | 344 | /// Returns the greatest integer no greater than `this`. | 
| 337 | /// | 345 | /// | 
| 338 | /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError]. | 346 | /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError]. | 
| 347 | + @override | ||
| 339 | int floor() => value.floor(); | 348 | int floor() => value.floor(); | 
| 340 | 349 | ||
| 341 | /// Returns the least integer no smaller than `this`. | 350 | /// Returns the least integer no smaller than `this`. | 
| 342 | /// | 351 | /// | 
| 343 | /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError]. | 352 | /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError]. | 
| 353 | + @override | ||
| 344 | int ceil() => value.ceil(); | 354 | int ceil() => value.ceil(); | 
| 345 | 355 | ||
| 346 | /// Returns the integer obtained by discarding any fractional | 356 | /// Returns the integer obtained by discarding any fractional | 
| 347 | /// digits from `this`. | 357 | /// digits from `this`. | 
| 348 | /// | 358 | /// | 
| 349 | /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError]. | 359 | /// If `this` is not finite (`NaN` or infinity), throws an [UnsupportedError]. | 
| 360 | + @override | ||
| 350 | int truncate() => value.truncate(); | 361 | int truncate() => value.truncate(); | 
| 351 | 362 | ||
| 352 | /// Returns the integer double value closest to `this`. | 363 | /// Returns the integer double value closest to `this`. | 
| @@ -361,6 +372,7 @@ class RxDouble extends _BaseRxNum<double> { | @@ -361,6 +372,7 @@ class RxDouble extends _BaseRxNum<double> { | ||
| 361 | /// and `-0.0` is therefore considered closer to negative numbers than `0.0`. | 372 | /// and `-0.0` is therefore considered closer to negative numbers than `0.0`. | 
| 362 | /// This means that for a value, `d` in the range `-0.5 < d < 0.0`, | 373 | /// This means that for a value, `d` in the range `-0.5 < d < 0.0`, | 
| 363 | /// the result is `-0.0`. | 374 | /// the result is `-0.0`. | 
| 375 | + @override | ||
| 364 | double roundToDouble() => value.roundToDouble(); | 376 | double roundToDouble() => value.roundToDouble(); | 
| 365 | 377 | ||
| 366 | /// Returns the greatest integer double value no greater than `this`. | 378 | /// Returns the greatest integer double value no greater than `this`. | 
| @@ -370,6 +382,7 @@ class RxDouble extends _BaseRxNum<double> { | @@ -370,6 +382,7 @@ class RxDouble extends _BaseRxNum<double> { | ||
| 370 | /// | 382 | /// | 
| 371 | /// For the purpose of rounding, `-0.0` is considered to be below `0.0`. | 383 | /// For the purpose of rounding, `-0.0` is considered to be below `0.0`. | 
| 372 | /// A number `d` in the range `0.0 < d < 1.0` will return `0.0`. | 384 | /// A number `d` in the range `0.0 < d < 1.0` will return `0.0`. | 
| 385 | + @override | ||
| 373 | double floorToDouble() => value.floorToDouble(); | 386 | double floorToDouble() => value.floorToDouble(); | 
| 374 | 387 | ||
| 375 | /// Returns the least integer double value no smaller than `this`. | 388 | /// Returns the least integer double value no smaller than `this`. | 
| @@ -379,6 +392,7 @@ class RxDouble extends _BaseRxNum<double> { | @@ -379,6 +392,7 @@ class RxDouble extends _BaseRxNum<double> { | ||
| 379 | /// | 392 | /// | 
| 380 | /// For the purpose of rounding, `-0.0` is considered to be below `0.0`. | 393 | /// For the purpose of rounding, `-0.0` is considered to be below `0.0`. | 
| 381 | /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`. | 394 | /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`. | 
| 395 | + @override | ||
| 382 | double ceilToDouble() => value.ceilToDouble(); | 396 | double ceilToDouble() => value.ceilToDouble(); | 
| 383 | 397 | ||
| 384 | /// Returns the integer double value obtained by discarding any fractional | 398 | /// Returns the integer double value obtained by discarding any fractional | 
| @@ -390,6 +404,7 @@ class RxDouble extends _BaseRxNum<double> { | @@ -390,6 +404,7 @@ class RxDouble extends _BaseRxNum<double> { | ||
| 390 | /// For the purpose of rounding, `-0.0` is considered to be below `0.0`. | 404 | /// For the purpose of rounding, `-0.0` is considered to be below `0.0`. | 
| 391 | /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and | 405 | /// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and | 
| 392 | /// in the range `0.0 < d < 1.0` it will return 0.0. | 406 | /// in the range `0.0 < d < 1.0` it will return 0.0. | 
| 407 | + @override | ||
| 393 | double truncateToDouble() => value.truncateToDouble(); | 408 | double truncateToDouble() => value.truncateToDouble(); | 
| 394 | } | 409 | } | 
| 395 | 410 | ||
| @@ -578,40 +593,51 @@ class RxInt extends _BaseRxNum<int> { | @@ -578,40 +593,51 @@ class RxInt extends _BaseRxNum<int> { | ||
| 578 | /// | 593 | /// | 
| 579 | /// The result of negating an integer always has the opposite sign, except | 594 | /// The result of negating an integer always has the opposite sign, except | 
| 580 | /// for zero, which is its own negation. | 595 | /// for zero, which is its own negation. | 
| 596 | + @override | ||
| 581 | int operator -() => -value; | 597 | int operator -() => -value; | 
| 582 | 598 | ||
| 583 | /// Returns the absolute value of this integer. | 599 | /// Returns the absolute value of this integer. | 
| 584 | /// | 600 | /// | 
| 585 | /// For any integer `x`, the result is the same as `x < 0 ? -x : x`. | 601 | /// For any integer `x`, the result is the same as `x < 0 ? -x : x`. | 
| 602 | + @override | ||
| 586 | int abs() => value.abs(); | 603 | int abs() => value.abs(); | 
| 587 | 604 | ||
| 588 | /// Returns the sign of this integer. | 605 | /// Returns the sign of this integer. | 
| 589 | /// | 606 | /// | 
| 590 | /// Returns 0 for zero, -1 for values less than zero and | 607 | /// Returns 0 for zero, -1 for values less than zero and | 
| 591 | /// +1 for values greater than zero. | 608 | /// +1 for values greater than zero. | 
| 609 | + @override | ||
| 592 | int get sign => value.sign; | 610 | int get sign => value.sign; | 
| 593 | 611 | ||
| 594 | /// Returns `this`. | 612 | /// Returns `this`. | 
| 613 | + @override | ||
| 595 | int round() => value.round(); | 614 | int round() => value.round(); | 
| 596 | 615 | ||
| 597 | /// Returns `this`. | 616 | /// Returns `this`. | 
| 617 | + @override | ||
| 598 | int floor() => value.floor(); | 618 | int floor() => value.floor(); | 
| 599 | 619 | ||
| 600 | /// Returns `this`. | 620 | /// Returns `this`. | 
| 621 | + @override | ||
| 601 | int ceil() => value.ceil(); | 622 | int ceil() => value.ceil(); | 
| 602 | 623 | ||
| 603 | /// Returns `this`. | 624 | /// Returns `this`. | 
| 625 | + @override | ||
| 604 | int truncate() => value.truncate(); | 626 | int truncate() => value.truncate(); | 
| 605 | 627 | ||
| 606 | /// Returns `this.toDouble()`. | 628 | /// Returns `this.toDouble()`. | 
| 629 | + @override | ||
| 607 | double roundToDouble() => value.roundToDouble(); | 630 | double roundToDouble() => value.roundToDouble(); | 
| 608 | 631 | ||
| 609 | /// Returns `this.toDouble()`. | 632 | /// Returns `this.toDouble()`. | 
| 633 | + @override | ||
| 610 | double floorToDouble() => value.floorToDouble(); | 634 | double floorToDouble() => value.floorToDouble(); | 
| 611 | 635 | ||
| 612 | /// Returns `this.toDouble()`. | 636 | /// Returns `this.toDouble()`. | 
| 637 | + @override | ||
| 613 | double ceilToDouble() => value.ceilToDouble(); | 638 | double ceilToDouble() => value.ceilToDouble(); | 
| 614 | 639 | ||
| 615 | /// Returns `this.toDouble()`. | 640 | /// Returns `this.toDouble()`. | 
| 641 | + @override | ||
| 616 | double truncateToDouble() => value.truncateToDouble(); | 642 | double truncateToDouble() => value.truncateToDouble(); | 
| 617 | } | 643 | } | 
| 1 | +part of rx_types; | ||
| 2 | + | ||
| 3 | +/// Create a list similar to `List<T>` | ||
| 4 | +class RxList<E> extends ListMixin<E> | ||
| 5 | + with RxObjectMixin<List<E>> | ||
| 6 | + implements RxInterface<List<E>> { | ||
| 7 | + RxList([List<E> initial]) { | ||
| 8 | + _value = initial; | ||
| 9 | + } | ||
| 10 | + | ||
| 11 | + @override | ||
| 12 | + Iterator<E> get iterator => value.iterator; | ||
| 13 | + | ||
| 14 | + @override | ||
| 15 | + void operator []=(int index, E val) { | ||
| 16 | + _value[index] = val; | ||
| 17 | + refresh(); | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + /// Special override to push() element(s) in a reactive way | ||
| 21 | + /// inside the List, | ||
| 22 | + @override | ||
| 23 | + RxList<E> operator +(Iterable<E> val) { | ||
| 24 | + addAll(val); | ||
| 25 | + refresh(); | ||
| 26 | + return this; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + @override | ||
| 30 | + E operator [](int index) { | ||
| 31 | + return value[index]; | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + @override | ||
| 35 | + void add(E item) { | ||
| 36 | + _value.add(item); | ||
| 37 | + refresh(); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + @override | ||
| 41 | + void addAll(Iterable<E> item) { | ||
| 42 | + _value.addAll(item); | ||
| 43 | + refresh(); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /// Add [item] to [List<E>] only if [item] is not null. | ||
| 47 | + void addNonNull(E item) { | ||
| 48 | + if (item != null) add(item); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /// Add [Iterable<E>] to [List<E>] only if [Iterable<E>] is not null. | ||
| 52 | + void addAllNonNull(Iterable<E> item) { | ||
| 53 | + if (item != null) addAll(item); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /// Add [item] to [List<E>] only if [condition] is true. | ||
| 57 | + void addIf(dynamic condition, E item) { | ||
| 58 | + if (condition is Condition) condition = condition(); | ||
| 59 | + if (condition is bool && condition) add(item); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + /// Adds [Iterable<E>] to [List<E>] only if [condition] is true. | ||
| 63 | + void addAllIf(dynamic condition, Iterable<E> items) { | ||
| 64 | + if (condition is Condition) condition = condition(); | ||
| 65 | + if (condition is bool && condition) addAll(items); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @override | ||
| 69 | + int get length => value.length; | ||
| 70 | + | ||
| 71 | + /// Replaces all existing items of this list with [item] | ||
| 72 | + void assign(E item) { | ||
| 73 | + clear(); | ||
| 74 | + add(item); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + /// Replaces all existing items of this list with [items] | ||
| 78 | + void assignAll(Iterable<E> items) { | ||
| 79 | + clear(); | ||
| 80 | + addAll(items); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @override | ||
| 84 | + @protected | ||
| 85 | + List<E> get value { | ||
| 86 | + if (getObs != null) { | ||
| 87 | + getObs.addListener(subject); | ||
| 88 | + } | ||
| 89 | + return _value; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + @override | ||
| 93 | + @protected | ||
| 94 | + @Deprecated('List.value is deprecated. use [yourList.assignAll(newList)]') | ||
| 95 | + set value(List<E> val) { | ||
| 96 | + if (_value == val) return; | ||
| 97 | + _value = val; | ||
| 98 | + refresh(); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + @override | ||
| 102 | + set length(int newLength) { | ||
| 103 | + _value.length = newLength; | ||
| 104 | + refresh(); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @override | ||
| 108 | + void insertAll(int index, Iterable<E> iterable) { | ||
| 109 | + _value.insertAll(index, iterable); | ||
| 110 | + refresh(); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + @override | ||
| 114 | + Iterable<E> get reversed => value.reversed; | ||
| 115 | + | ||
| 116 | + @override | ||
| 117 | + Iterable<E> where(bool Function(E) test) { | ||
| 118 | + return value.where(test); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + @override | ||
| 122 | + Iterable<T> whereType<T>() { | ||
| 123 | + return value.whereType<T>(); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + @override | ||
| 127 | + void sort([int compare(E a, E b)]) { | ||
| 128 | + _value.sort(compare); | ||
| 129 | + refresh(); | ||
| 130 | + } | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +// /// Create a list similar to `List<T>` | ||
| 134 | +// class RxList<E> implements List<E>, RxInterface<List<E>> { | ||
| 135 | +// RxList([List<E> initial]) { | ||
| 136 | +// if (initial != null) _value = initial; | ||
| 137 | +// } | ||
| 138 | + | ||
| 139 | +// List<E> _value = <E>[]; | ||
| 140 | + | ||
| 141 | +// @override | ||
| 142 | +// Iterator<E> get iterator => value.iterator; | ||
| 143 | + | ||
| 144 | +// @override | ||
| 145 | +// bool get isEmpty => value.isEmpty; | ||
| 146 | + | ||
| 147 | +// bool get canUpdate { | ||
| 148 | +// return _subscriptions.length > 0; | ||
| 149 | +// } | ||
| 150 | + | ||
| 151 | +// @override | ||
| 152 | +// bool get isNotEmpty => value.isNotEmpty; | ||
| 153 | + | ||
| 154 | +// @override | ||
| 155 | +// StreamController<List<E>> subject = StreamController.broadcast(); | ||
| 156 | + | ||
| 157 | +// final _subscriptions = HashMap<Stream<List<E>>, StreamSubscription>(); | ||
| 158 | + | ||
| 159 | +// void operator []=(int index, E val) { | ||
| 160 | +// _value[index] = val; | ||
| 161 | +// refresh(); | ||
| 162 | +// } | ||
| 163 | + | ||
| 164 | +// void refresh() { | ||
| 165 | +// subject.add(_value); | ||
| 166 | +// } | ||
| 167 | + | ||
| 168 | +// /// Special override to push() element(s) in a reactive way | ||
| 169 | +// /// inside the List, | ||
| 170 | +// RxList<E> operator +(Iterable<E> val) { | ||
| 171 | +// addAll(val); | ||
| 172 | +// refresh(); | ||
| 173 | +// return this; | ||
| 174 | +// } | ||
| 175 | + | ||
| 176 | +// E operator [](int index) { | ||
| 177 | +// return value[index]; | ||
| 178 | +// } | ||
| 179 | + | ||
| 180 | +// void add(E item) { | ||
| 181 | +// _value.add(item); | ||
| 182 | +// refresh(); | ||
| 183 | +// } | ||
| 184 | + | ||
| 185 | +// @override | ||
| 186 | +// void addAll(Iterable<E> item) { | ||
| 187 | +// _value.addAll(item); | ||
| 188 | +// refresh(); | ||
| 189 | +// } | ||
| 190 | + | ||
| 191 | +// /// Add [item] to [List<E>] only if [item] is not null. | ||
| 192 | +// void addNonNull(E item) { | ||
| 193 | +// if (item != null) add(item); | ||
| 194 | +// } | ||
| 195 | + | ||
| 196 | +// /// Add [Iterable<E>] to [List<E>] only if [Iterable<E>] is not null. | ||
| 197 | +// void addAllNonNull(Iterable<E> item) { | ||
| 198 | +// if (item != null) addAll(item); | ||
| 199 | +// } | ||
| 200 | + | ||
| 201 | +// /// Add [item] to [List<E>] only if [condition] is true. | ||
| 202 | +// void addIf(dynamic condition, E item) { | ||
| 203 | +// if (condition is Condition) condition = condition(); | ||
| 204 | +// if (condition is bool && condition) add(item); | ||
| 205 | +// } | ||
| 206 | + | ||
| 207 | +// /// Adds [Iterable<E>] to [List<E>] only if [condition] is true. | ||
| 208 | +// void addAllIf(dynamic condition, Iterable<E> items) { | ||
| 209 | +// if (condition is Condition) condition = condition(); | ||
| 210 | +// if (condition is bool && condition) addAll(items); | ||
| 211 | +// } | ||
| 212 | + | ||
| 213 | +// @override | ||
| 214 | +// void insert(int index, E item) { | ||
| 215 | +// _value.insert(index, item); | ||
| 216 | +// refresh(); | ||
| 217 | +// } | ||
| 218 | + | ||
| 219 | +// @override | ||
| 220 | +// void insertAll(int index, Iterable<E> iterable) { | ||
| 221 | +// _value.insertAll(index, iterable); | ||
| 222 | +// refresh(); | ||
| 223 | +// } | ||
| 224 | + | ||
| 225 | +// @override | ||
| 226 | +// int get length => value.length; | ||
| 227 | + | ||
| 228 | +// /// Removes an item from the list. | ||
| 229 | +// /// | ||
| 230 | +// /// This is O(N) in the number of items in the list. | ||
| 231 | +// /// | ||
| 232 | +// /// Returns whether the item was present in the list. | ||
| 233 | +// @override | ||
| 234 | +// bool remove(Object item) { | ||
| 235 | +// final hasRemoved = _value.remove(item); | ||
| 236 | +// if (hasRemoved) { | ||
| 237 | +// refresh(); | ||
| 238 | +// } | ||
| 239 | +// return hasRemoved; | ||
| 240 | +// } | ||
| 241 | + | ||
| 242 | +// @override | ||
| 243 | +// E removeAt(int index) { | ||
| 244 | +// final item = _value.removeAt(index); | ||
| 245 | +// refresh(); | ||
| 246 | +// return item; | ||
| 247 | +// } | ||
| 248 | + | ||
| 249 | +// @override | ||
| 250 | +// E removeLast() { | ||
| 251 | +// final item = _value.removeLast(); | ||
| 252 | +// refresh(); | ||
| 253 | +// return item; | ||
| 254 | +// } | ||
| 255 | + | ||
| 256 | +// @override | ||
| 257 | +// void removeRange(int start, int end) { | ||
| 258 | +// _value.removeRange(start, end); | ||
| 259 | +// refresh(); | ||
| 260 | +// } | ||
| 261 | + | ||
| 262 | +// @override | ||
| 263 | +// void removeWhere(bool Function(E) test) { | ||
| 264 | +// _value.removeWhere(test); | ||
| 265 | +// refresh(); | ||
| 266 | +// } | ||
| 267 | + | ||
| 268 | +// @override | ||
| 269 | +// void clear() { | ||
| 270 | +// _value.clear(); | ||
| 271 | +// refresh(); | ||
| 272 | +// } | ||
| 273 | + | ||
| 274 | +// @override | ||
| 275 | +// void sort([int compare(E a, E b)]) { | ||
| 276 | +// _value.sort(compare); | ||
| 277 | +// refresh(); | ||
| 278 | +// } | ||
| 279 | + | ||
| 280 | +// @override | ||
| 281 | +// void close() { | ||
| 282 | +// _subscriptions.forEach((observable, subscription) { | ||
| 283 | +// subscription.cancel(); | ||
| 284 | +// }); | ||
| 285 | +// _subscriptions.clear(); | ||
| 286 | +// subject.close(); | ||
| 287 | +// } | ||
| 288 | + | ||
| 289 | +// /// Replaces all existing items of this list with [item] | ||
| 290 | +// void assign(E item) { | ||
| 291 | +// clear(); | ||
| 292 | +// add(item); | ||
| 293 | +// } | ||
| 294 | + | ||
| 295 | +// void update(void fn(Iterable<E> value)) { | ||
| 296 | +// fn(value); | ||
| 297 | +// refresh(); | ||
| 298 | +// } | ||
| 299 | + | ||
| 300 | +// /// Replaces all existing items of this list with [items] | ||
| 301 | +// void assignAll(Iterable<E> items) { | ||
| 302 | +// clear(); | ||
| 303 | +// addAll(items); | ||
| 304 | +// } | ||
| 305 | + | ||
| 306 | +// @protected | ||
| 307 | +// List<E> get value { | ||
| 308 | +// if (getObs != null) { | ||
| 309 | +// getObs.addListener(subject.stream); | ||
| 310 | +// } | ||
| 311 | +// return _value; | ||
| 312 | +// } | ||
| 313 | + | ||
| 314 | +// String get string => value.toString(); | ||
| 315 | + | ||
| 316 | +// void addListener(Stream<List<E>> rxGetX) { | ||
| 317 | +// if (_subscriptions.containsKey(rxGetX)) { | ||
| 318 | +// return; | ||
| 319 | +// } | ||
| 320 | +// _subscriptions[rxGetX] = rxGetX.listen(subject.add); | ||
| 321 | +// } | ||
| 322 | + | ||
| 323 | +// set value(List<E> val) { | ||
| 324 | +// if (_value == val) return; | ||
| 325 | +// _value = val; | ||
| 326 | +// refresh(); | ||
| 327 | +// } | ||
| 328 | + | ||
| 329 | +// Stream<List<E>> get stream => subject.stream; | ||
| 330 | + | ||
| 331 | +// StreamSubscription<List<E>> listen( | ||
| 332 | +// void Function(List<E>) onData, { | ||
| 333 | +// Function onError, | ||
| 334 | +// void Function() onDone, | ||
| 335 | +// bool cancelOnError, | ||
| 336 | +// }) => | ||
| 337 | +// stream.listen(onData, onError: onError, onDone: onDone); | ||
| 338 | + | ||
| 339 | +// /// Binds an existing [Stream<List>] to this [RxList]. | ||
| 340 | +// /// You can bind multiple sources to update the value. | ||
| 341 | +// /// Closing the subscription will happen automatically when the observer | ||
| 342 | +// /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree. | ||
| 343 | +// void bindStream(Stream<List<E>> stream) { | ||
| 344 | +// _subscriptions[stream] = stream.listen((va) => value = va); | ||
| 345 | +// } | ||
| 346 | + | ||
| 347 | +// @override | ||
| 348 | +// E get first => value.first; | ||
| 349 | + | ||
| 350 | +// @override | ||
| 351 | +// E get last => value.last; | ||
| 352 | + | ||
| 353 | +// @override | ||
| 354 | +// bool any(bool Function(E) test) { | ||
| 355 | +// return value.any(test); | ||
| 356 | +// } | ||
| 357 | + | ||
| 358 | +// @override | ||
| 359 | +// Map<int, E> asMap() { | ||
| 360 | +// return value.asMap(); | ||
| 361 | +// } | ||
| 362 | + | ||
| 363 | +// @override | ||
| 364 | +// List<R> cast<R>() { | ||
| 365 | +// return value.cast<R>(); | ||
| 366 | +// } | ||
| 367 | + | ||
| 368 | +// @override | ||
| 369 | +// bool contains(Object element) { | ||
| 370 | +// return value.contains(element); | ||
| 371 | +// } | ||
| 372 | + | ||
| 373 | +// @override | ||
| 374 | +// E elementAt(int index) { | ||
| 375 | +// return value.elementAt(index); | ||
| 376 | +// } | ||
| 377 | + | ||
| 378 | +// @override | ||
| 379 | +// bool every(bool Function(E) test) { | ||
| 380 | +// return value.every(test); | ||
| 381 | +// } | ||
| 382 | + | ||
| 383 | +// @override | ||
| 384 | +// Iterable<T> expand<T>(Iterable<T> Function(E) f) { | ||
| 385 | +// return value.expand(f); | ||
| 386 | +// } | ||
| 387 | + | ||
| 388 | +// @override | ||
| 389 | +// void fillRange(int start, int end, [E fillValue]) { | ||
| 390 | +// _value.fillRange(start, end, fillValue); | ||
| 391 | +// refresh(); | ||
| 392 | +// } | ||
| 393 | + | ||
| 394 | +// @override | ||
| 395 | +// E firstWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 396 | +// return value.firstWhere(test, orElse: orElse); | ||
| 397 | +// } | ||
| 398 | + | ||
| 399 | +// @override | ||
| 400 | +// T fold<T>(T initialValue, T Function(T, E) combine) { | ||
| 401 | +// return value.fold(initialValue, combine); | ||
| 402 | +// } | ||
| 403 | + | ||
| 404 | +// @override | ||
| 405 | +// Iterable<E> followedBy(Iterable<E> other) { | ||
| 406 | +// return value.followedBy(other); | ||
| 407 | +// } | ||
| 408 | + | ||
| 409 | +// @override | ||
| 410 | +// void forEach(void Function(E) f) { | ||
| 411 | +// value.forEach(f); | ||
| 412 | +// } | ||
| 413 | + | ||
| 414 | +// @override | ||
| 415 | +// Iterable<E> getRange(int start, int end) { | ||
| 416 | +// return value.getRange(start, end); | ||
| 417 | +// } | ||
| 418 | + | ||
| 419 | +// @override | ||
| 420 | +// int indexOf(E element, [int start = 0]) { | ||
| 421 | +// return value.indexOf(element, start); | ||
| 422 | +// } | ||
| 423 | + | ||
| 424 | +// @override | ||
| 425 | +// int indexWhere(bool Function(E) test, [int start = 0]) { | ||
| 426 | +// return value.indexWhere(test, start); | ||
| 427 | +// } | ||
| 428 | + | ||
| 429 | +// @override | ||
| 430 | +// String join([String separator = ""]) { | ||
| 431 | +// return value.join(separator); | ||
| 432 | +// } | ||
| 433 | + | ||
| 434 | +// @override | ||
| 435 | +// int lastIndexOf(E element, [int start]) { | ||
| 436 | +// return value.lastIndexOf(element, start); | ||
| 437 | +// } | ||
| 438 | + | ||
| 439 | +// @override | ||
| 440 | +// int lastIndexWhere(bool Function(E) test, [int start]) { | ||
| 441 | +// return value.lastIndexWhere(test, start); | ||
| 442 | +// } | ||
| 443 | + | ||
| 444 | +// @override | ||
| 445 | +// E lastWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 446 | +// return value.lastWhere(test, orElse: orElse); | ||
| 447 | +// } | ||
| 448 | + | ||
| 449 | +// @override | ||
| 450 | +// set length(int newLength) { | ||
| 451 | +// _value.length = newLength; | ||
| 452 | +// refresh(); | ||
| 453 | +// } | ||
| 454 | + | ||
| 455 | +// @override | ||
| 456 | +// Iterable<T> map<T>(T Function(E) f) { | ||
| 457 | +// return value.map(f); | ||
| 458 | +// } | ||
| 459 | + | ||
| 460 | +// @override | ||
| 461 | +// E reduce(E Function(E, E) combine) { | ||
| 462 | +// return value.reduce(combine); | ||
| 463 | +// } | ||
| 464 | + | ||
| 465 | +// @override | ||
| 466 | +// void replaceRange(int start, int end, Iterable<E> replacement) { | ||
| 467 | +// _value.replaceRange(start, end, replacement); | ||
| 468 | +// refresh(); | ||
| 469 | +// } | ||
| 470 | + | ||
| 471 | +// @override | ||
| 472 | +// void retainWhere(bool Function(E) test) { | ||
| 473 | +// _value.retainWhere(test); | ||
| 474 | +// refresh(); | ||
| 475 | +// } | ||
| 476 | + | ||
| 477 | +// @override | ||
| 478 | +// Iterable<E> get reversed => value.reversed; | ||
| 479 | + | ||
| 480 | +// @override | ||
| 481 | +// void setAll(int index, Iterable<E> iterable) { | ||
| 482 | +// _value.setAll(index, iterable); | ||
| 483 | +// refresh(); | ||
| 484 | +// } | ||
| 485 | + | ||
| 486 | +// @override | ||
| 487 | +// void setRange(int start, int end, | ||
| 488 | +// Iterable<E> iterable, [int skipCount = 0],) { | ||
| 489 | +// _value.setRange(start, end, iterable, skipCount); | ||
| 490 | +// refresh(); | ||
| 491 | +// } | ||
| 492 | + | ||
| 493 | +// @override | ||
| 494 | +// void shuffle([Random random]) { | ||
| 495 | +// _value.shuffle(random); | ||
| 496 | +// refresh(); | ||
| 497 | +// } | ||
| 498 | + | ||
| 499 | +// @override | ||
| 500 | +// E get single => value.single; | ||
| 501 | + | ||
| 502 | +// @override | ||
| 503 | +// E singleWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 504 | +// return value.singleWhere(test, orElse: orElse); | ||
| 505 | +// } | ||
| 506 | + | ||
| 507 | +// @override | ||
| 508 | +// Iterable<E> skip(int count) { | ||
| 509 | +// return value.skip(count); | ||
| 510 | +// } | ||
| 511 | + | ||
| 512 | +// @override | ||
| 513 | +// Iterable<E> skipWhile(bool Function(E) test) { | ||
| 514 | +// return value.skipWhile(test); | ||
| 515 | +// } | ||
| 516 | + | ||
| 517 | +// @override | ||
| 518 | +// List<E> sublist(int start, [int end]) { | ||
| 519 | +// return value.sublist(start, end); | ||
| 520 | +// } | ||
| 521 | + | ||
| 522 | +// @override | ||
| 523 | +// Iterable<E> take(int count) { | ||
| 524 | +// return value.take(count); | ||
| 525 | +// } | ||
| 526 | + | ||
| 527 | +// @override | ||
| 528 | +// Iterable<E> takeWhile(bool Function(E) test) { | ||
| 529 | +// return value.takeWhile(test); | ||
| 530 | +// } | ||
| 531 | + | ||
| 532 | +// @override | ||
| 533 | +// List<E> toList({bool growable = true}) { | ||
| 534 | +// return value.toList(growable: growable); | ||
| 535 | +// } | ||
| 536 | + | ||
| 537 | +// @override | ||
| 538 | +// Set<E> toSet() { | ||
| 539 | +// return value.toSet(); | ||
| 540 | +// } | ||
| 541 | + | ||
| 542 | +// @override | ||
| 543 | +// Iterable<E> where(bool Function(E) test) { | ||
| 544 | +// return value.where(test); | ||
| 545 | +// } | ||
| 546 | + | ||
| 547 | +// @override | ||
| 548 | +// Iterable<T> whereType<T>() { | ||
| 549 | +// return value.whereType<T>(); | ||
| 550 | +// } | ||
| 551 | + | ||
| 552 | +// @override | ||
| 553 | +// set first(E value) { | ||
| 554 | +// _value.first = value; | ||
| 555 | +// refresh(); | ||
| 556 | +// } | ||
| 557 | + | ||
| 558 | +// @override | ||
| 559 | +// set last(E value) { | ||
| 560 | +// _value.last = value; | ||
| 561 | +// refresh(); | ||
| 562 | +// } | ||
| 563 | +// } | ||
| 564 | + | ||
| 565 | +extension ListExtension<E> on List<E> { | ||
| 566 | + RxList<E> get obs { | ||
| 567 | + if (this != null) { | ||
| 568 | + return RxList<E>(<E>[])..addAllNonNull(this); | ||
| 569 | + } else { | ||
| 570 | + return RxList<E>(null); | ||
| 571 | + } | ||
| 572 | + } | ||
| 573 | +} | 
| 1 | -import 'dart:async'; | ||
| 2 | -import 'dart:collection'; | ||
| 3 | -import 'package:flutter/foundation.dart'; | ||
| 4 | -import '../rx_core/rx_impl.dart'; | ||
| 5 | -import '../rx_core/rx_interface.dart'; | ||
| 6 | -import '../rx_typedefs/rx_typedefs.dart'; | 1 | +part of rx_types; | 
| 7 | 2 | ||
| 8 | -class RxMap<K, V> implements RxInterface<Map<K, V>>, Map<K, V> { | 3 | +class RxMap<K, V> extends MapMixin<K, V> | 
| 4 | + with RxObjectMixin<Map<K, V>> | ||
| 5 | + implements RxInterface<Map<K, V>> { | ||
| 9 | RxMap([Map<K, V> initial]) { | 6 | RxMap([Map<K, V> initial]) { | 
| 10 | - if (initial != null) _value = initial; | ||
| 11 | - } | ||
| 12 | - | ||
| 13 | - @override | ||
| 14 | - StreamController<Map<K, V>> subject = StreamController<Map<K, V>>.broadcast(); | ||
| 15 | - final _subscriptions = HashMap<Stream<Map<K, V>>, StreamSubscription>(); | ||
| 16 | - | ||
| 17 | - Map<K, V> _value; | ||
| 18 | - | ||
| 19 | - @protected | ||
| 20 | - Map<K, V> get value { | ||
| 21 | - if (getObs != null) { | ||
| 22 | - getObs.addListener(subject.stream); | ||
| 23 | - } | ||
| 24 | - return _value; | ||
| 25 | - } | ||
| 26 | - | ||
| 27 | - void refresh() { | ||
| 28 | - subject.add(_value); | ||
| 29 | - } | ||
| 30 | - | ||
| 31 | - String get string => value.toString(); | ||
| 32 | - | ||
| 33 | - bool get canUpdate { | ||
| 34 | - return _subscriptions.length > 0; | ||
| 35 | - } | ||
| 36 | - | ||
| 37 | - @override | ||
| 38 | - void close() { | ||
| 39 | - _subscriptions.forEach((observable, subscription) { | ||
| 40 | - subscription.cancel(); | ||
| 41 | - }); | ||
| 42 | - _subscriptions.clear(); | ||
| 43 | - subject.close(); | ||
| 44 | - } | ||
| 45 | - | ||
| 46 | - @override | ||
| 47 | - void addListener(Stream<Map<K, V>> rxGetX) { | ||
| 48 | - if (_subscriptions.containsKey(rxGetX)) { | ||
| 49 | - return; | ||
| 50 | - } | ||
| 51 | - _subscriptions[rxGetX] = rxGetX.listen((data) { | ||
| 52 | - subject.add(data); | ||
| 53 | - }); | ||
| 54 | - } | ||
| 55 | - | ||
| 56 | - set value(Map<K, V> val) { | ||
| 57 | - if (_value == val) return; | ||
| 58 | - _value = val; | ||
| 59 | - refresh(); | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - Stream<Map<K, V>> get stream => subject.stream; | ||
| 63 | - | ||
| 64 | - StreamSubscription<Map<K, V>> listen(void Function(Map<K, V>) onData, | ||
| 65 | - {Function onError, void Function() onDone, bool cancelOnError}) => | ||
| 66 | - stream.listen(onData, onError: onError, onDone: onDone); | ||
| 67 | - | ||
| 68 | - /// Binds an existing [Stream<Map>] to this [RxMap]. | ||
| 69 | - /// You can bind multiple sources to update the value. | ||
| 70 | - /// Closing the subscription will happen automatically when the observer | ||
| 71 | - /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree. | ||
| 72 | - void bindStream(Stream<Map<K, V>> stream) { | ||
| 73 | - _subscriptions[stream] = stream.listen((va) => value = va); | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - void add(K key, V value) { | ||
| 77 | - _value[key] = value; | ||
| 78 | - refresh(); | ||
| 79 | - } | ||
| 80 | - | ||
| 81 | - void addIf(dynamic condition, K key, V value) { | ||
| 82 | - if (condition is Condition) condition = condition(); | ||
| 83 | - if (condition is bool && condition) { | ||
| 84 | - _value[key] = value; | ||
| 85 | - refresh(); | ||
| 86 | - } | ||
| 87 | - } | ||
| 88 | - | ||
| 89 | - void addAllIf(dynamic condition, Map<K, V> values) { | ||
| 90 | - if (condition is Condition) condition = condition(); | ||
| 91 | - if (condition is bool && condition) addAll(values); | 7 | + _value = initial; | 
| 92 | } | 8 | } | 
| 93 | 9 | ||
| 94 | @override | 10 | @override | 
| @@ -103,64 +19,15 @@ class RxMap<K, V> implements RxInterface<Map<K, V>>, Map<K, V> { | @@ -103,64 +19,15 @@ class RxMap<K, V> implements RxInterface<Map<K, V>>, Map<K, V> { | ||
| 103 | } | 19 | } | 
| 104 | 20 | ||
| 105 | @override | 21 | @override | 
| 106 | - void addAll(Map<K, V> other) { | ||
| 107 | - _value.addAll(other); | ||
| 108 | - refresh(); | ||
| 109 | - } | ||
| 110 | - | ||
| 111 | - @override | ||
| 112 | - void addEntries(Iterable<MapEntry<K, V>> entries) { | ||
| 113 | - _value.addEntries(entries); | ||
| 114 | - refresh(); | ||
| 115 | - } | ||
| 116 | - | ||
| 117 | - @override | ||
| 118 | void clear() { | 22 | void clear() { | 
| 119 | _value.clear(); | 23 | _value.clear(); | 
| 120 | refresh(); | 24 | refresh(); | 
| 121 | } | 25 | } | 
| 122 | 26 | ||
| 123 | @override | 27 | @override | 
| 124 | - Map<K2, V2> cast<K2, V2>() => value.cast<K2, V2>(); | ||
| 125 | - | ||
| 126 | - @override | ||
| 127 | - bool containsKey(Object key) => value.containsKey(key); | ||
| 128 | - | ||
| 129 | - @override | ||
| 130 | - bool containsValue(Object value) => _value.containsValue(value); | ||
| 131 | - | ||
| 132 | - @override | ||
| 133 | - Iterable<MapEntry<K, V>> get entries => value.entries; | ||
| 134 | - | ||
| 135 | - @override | ||
| 136 | - void forEach(void Function(K, V) f) { | ||
| 137 | - value.forEach(f); | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | - @override | ||
| 141 | - bool get isEmpty => value.isEmpty; | ||
| 142 | - | ||
| 143 | - @override | ||
| 144 | - bool get isNotEmpty => value.isNotEmpty; | ||
| 145 | - | ||
| 146 | - @override | ||
| 147 | Iterable<K> get keys => value.keys; | 28 | Iterable<K> get keys => value.keys; | 
| 148 | 29 | ||
| 149 | @override | 30 | @override | 
| 150 | - int get length => value.length; | ||
| 151 | - | ||
| 152 | - @override | ||
| 153 | - Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> Function(K, V) transform) => | ||
| 154 | - value.map(transform); | ||
| 155 | - | ||
| 156 | - @override | ||
| 157 | - V putIfAbsent(K key, V Function() ifAbsent) { | ||
| 158 | - final val = _value.putIfAbsent(key, ifAbsent); | ||
| 159 | - refresh(); | ||
| 160 | - return val; | ||
| 161 | - } | ||
| 162 | - | ||
| 163 | - @override | ||
| 164 | V remove(Object key) { | 31 | V remove(Object key) { | 
| 165 | final val = _value.remove(key); | 32 | final val = _value.remove(key); | 
| 166 | refresh(); | 33 | refresh(); | 
| @@ -168,37 +35,51 @@ class RxMap<K, V> implements RxInterface<Map<K, V>>, Map<K, V> { | @@ -168,37 +35,51 @@ class RxMap<K, V> implements RxInterface<Map<K, V>>, Map<K, V> { | ||
| 168 | } | 35 | } | 
| 169 | 36 | ||
| 170 | @override | 37 | @override | 
| 171 | - void removeWhere(bool Function(K, V) test) { | ||
| 172 | - _value.removeWhere(test); | ||
| 173 | - refresh(); | 38 | + @protected | 
| 39 | + Map<K, V> get value { | ||
| 40 | + if (getObs != null) { | ||
| 41 | + getObs.addListener(subject); | ||
| 42 | + } | ||
| 43 | + return _value; | ||
| 174 | } | 44 | } | 
| 175 | 45 | ||
| 176 | - @override | ||
| 177 | - Iterable<V> get values => value.values; | ||
| 178 | - | ||
| 179 | - @override | ||
| 180 | - String toString() => _value.toString(); | 46 | + void assign(K key, V val) { | 
| 47 | + _value.clear(); | ||
| 48 | + _value[key] = val; | ||
| 49 | + refresh(); | ||
| 50 | + } | ||
| 181 | 51 | ||
| 182 | - @override | ||
| 183 | - V update(K key, V Function(V) update, {V Function() ifAbsent}) { | ||
| 184 | - final val = _value.update(key, update, ifAbsent: ifAbsent); | 52 | + void assignAll(Map<K, V> val) { | 
| 53 | + if (_value == val) return; | ||
| 54 | + _value = val; | ||
| 185 | refresh(); | 55 | refresh(); | 
| 186 | - return val; | ||
| 187 | } | 56 | } | 
| 188 | 57 | ||
| 189 | @override | 58 | @override | 
| 190 | - void updateAll(V Function(K, V) update) { | ||
| 191 | - _value.updateAll(update); | 59 | + @protected | 
| 60 | + @Deprecated('Map.value is deprecated. use [yourMap.assignAll(newMap)]') | ||
| 61 | + set value(Map<K, V> val) { | ||
| 62 | + if (_value == val) return; | ||
| 63 | + _value = val; | ||
| 192 | refresh(); | 64 | refresh(); | 
| 193 | } | 65 | } | 
| 66 | + | ||
| 67 | + void addIf(dynamic condition, K key, V value) { | ||
| 68 | + if (condition is Condition) condition = condition(); | ||
| 69 | + if (condition is bool && condition) { | ||
| 70 | + _value[key] = value; | ||
| 71 | + refresh(); | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + void addAllIf(dynamic condition, Map<K, V> values) { | ||
| 76 | + if (condition is Condition) condition = condition(); | ||
| 77 | + if (condition is bool && condition) addAll(values); | ||
| 78 | + } | ||
| 194 | } | 79 | } | 
| 195 | 80 | ||
| 196 | extension MapExtension<K, V> on Map<K, V> { | 81 | extension MapExtension<K, V> on Map<K, V> { | 
| 197 | RxMap<K, V> get obs { | 82 | RxMap<K, V> get obs { | 
| 198 | - if (this != null) { | ||
| 199 | - return RxMap<K, V>(<K, V>{})..addAll(this); | ||
| 200 | - } else { | ||
| 201 | - return RxMap<K, V>(null); | ||
| 202 | - } | 83 | + return RxMap<K, V>(this); | 
| 203 | } | 84 | } | 
| 204 | } | 85 | } | 
| 1 | +part of rx_types; | ||
| 2 | + | ||
| 3 | +class RxSet<E> extends SetMixin<E> | ||
| 4 | + with RxObjectMixin<Set<E>> | ||
| 5 | + implements RxInterface<Set<E>> { | ||
| 6 | + RxSet([Set<E> initial]) { | ||
| 7 | + if (initial != null) _value = initial; | ||
| 8 | + } | ||
| 9 | + | ||
| 10 | + /// Adds [item] only if [condition] resolves to true. | ||
| 11 | + void addIf(dynamic condition, E item) { | ||
| 12 | + if (condition is Condition) condition = condition(); | ||
| 13 | + if (condition is bool && condition) add(item); | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + /// Adds all [items] only if [condition] resolves to true. | ||
| 17 | + void addAllIf(dynamic condition, Iterable<E> items) { | ||
| 18 | + if (condition is Condition) condition = condition(); | ||
| 19 | + if (condition is bool && condition) addAll(items); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + /// Special override to push() element(s) in a reactive way | ||
| 23 | + /// inside the List, | ||
| 24 | + RxSet<E> operator +(Set<E> val) { | ||
| 25 | + addAll(val); | ||
| 26 | + refresh(); | ||
| 27 | + return this; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + /// Adds only if [item] is not null. | ||
| 31 | + void addNonNull(E item) { | ||
| 32 | + if (item != null) add(item); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /// Adds only if [item] is not null. | ||
| 36 | + void addAllNonNull(Iterable<E> item) { | ||
| 37 | + if (item != null) addAll(item); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + /// Replaces all existing items of this list with [item] | ||
| 41 | + void assign(E item) { | ||
| 42 | + clear(); | ||
| 43 | + add(item); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + void update(void fn(Iterable<E> value)) { | ||
| 47 | + fn(value); | ||
| 48 | + refresh(); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /// Replaces all existing items of this list with [items] | ||
| 52 | + void assignAll(Iterable<E> items) { | ||
| 53 | + clear(); | ||
| 54 | + addAll(items); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @override | ||
| 58 | + @protected | ||
| 59 | + Set<E> get value { | ||
| 60 | + if (getObs != null) { | ||
| 61 | + getObs.addListener(subject); | ||
| 62 | + } | ||
| 63 | + return _value; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + @override | ||
| 67 | + @protected | ||
| 68 | + set value(Set<E> val) { | ||
| 69 | + if (_value == val) return; | ||
| 70 | + _value = val; | ||
| 71 | + refresh(); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + | ||
| 76 | + @override | ||
| 77 | + bool add(E value) { | ||
| 78 | + final val = _value.add(value); | ||
| 79 | + refresh(); | ||
| 80 | + return val; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @override | ||
| 84 | + bool contains(Object element) { | ||
| 85 | + return value.contains(element); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + @override | ||
| 89 | + Iterator<E> get iterator => value.iterator; | ||
| 90 | + | ||
| 91 | + @override | ||
| 92 | + int get length => value.length; | ||
| 93 | + | ||
| 94 | + @override | ||
| 95 | + E lookup(Object object) { | ||
| 96 | + return value.lookup(object); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + @override | ||
| 100 | + bool remove(Object item) { | ||
| 101 | + var hasRemoved = _value.remove(item); | ||
| 102 | + if (hasRemoved) { | ||
| 103 | + refresh(); | ||
| 104 | + } | ||
| 105 | + return hasRemoved; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + @override | ||
| 109 | + Set<E> toSet() { | ||
| 110 | + return value.toSet(); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + @override | ||
| 114 | + void addAll(Iterable<E> item) { | ||
| 115 | + _value.addAll(item); | ||
| 116 | + refresh(); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + @override | ||
| 120 | + void clear() { | ||
| 121 | + _value.clear(); | ||
| 122 | + refresh(); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + @override | ||
| 126 | + void removeAll(Iterable<Object> elements) { | ||
| 127 | + _value.removeAll(elements); | ||
| 128 | + refresh(); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + @override | ||
| 132 | + void retainAll(Iterable<Object> elements) { | ||
| 133 | + _value.retainAll(elements); | ||
| 134 | + refresh(); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + @override | ||
| 138 | + void retainWhere(bool Function(E) E) { | ||
| 139 | + _value.retainWhere(E); | ||
| 140 | + refresh(); | ||
| 141 | + } | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | +// class RxSet<E> implements Set<E>, RxInterface<Set<E>> { | ||
| 145 | +// RxSet([Set<E> initial]) { | ||
| 146 | +// if (initial != null) _value = initial; | ||
| 147 | +// } | ||
| 148 | + | ||
| 149 | +// Set<E> _value = <E>{}; | ||
| 150 | + | ||
| 151 | +// @override | ||
| 152 | +// Iterator<E> get iterator => value.iterator; | ||
| 153 | + | ||
| 154 | +// @override | ||
| 155 | +// bool get isEmpty => value.isEmpty; | ||
| 156 | + | ||
| 157 | +// bool get canUpdate { | ||
| 158 | +// return _subscriptions.length > 0; | ||
| 159 | +// } | ||
| 160 | + | ||
| 161 | +// @override | ||
| 162 | +// bool get isNotEmpty => value.isNotEmpty; | ||
| 163 | + | ||
| 164 | +// StreamController<Set<E>> subject = StreamController<Set<E>>.broadcast(); | ||
| 165 | +// final _subscriptions = HashMap<Stream<Set<E>>, StreamSubscription>(); | ||
| 166 | + | ||
| 167 | +// /// Adds [item] only if [condition] resolves to true. | ||
| 168 | +// void addIf(dynamic condition, E item) { | ||
| 169 | +// if (condition is Condition) condition = condition(); | ||
| 170 | +// if (condition is bool && condition) add(item); | ||
| 171 | +// } | ||
| 172 | + | ||
| 173 | +// /// Adds all [items] only if [condition] resolves to true. | ||
| 174 | +// void addAllIf(dynamic condition, Iterable<E> items) { | ||
| 175 | +// if (condition is Condition) condition = condition(); | ||
| 176 | +// if (condition is bool && condition) addAll(items); | ||
| 177 | +// } | ||
| 178 | + | ||
| 179 | +// void refresh() { | ||
| 180 | +// subject.add(_value); | ||
| 181 | +// } | ||
| 182 | + | ||
| 183 | +// /// Special override to push() element(s) in a reactive way | ||
| 184 | +// /// inside the List, | ||
| 185 | +// RxSet<E> operator +(Set<E> val) { | ||
| 186 | +// addAll(val); | ||
| 187 | +// refresh(); | ||
| 188 | +// return this; | ||
| 189 | +// } | ||
| 190 | + | ||
| 191 | +// @override | ||
| 192 | +// bool add(E value) { | ||
| 193 | +// final val = _value.add(value); | ||
| 194 | +// refresh(); | ||
| 195 | +// return val; | ||
| 196 | +// } | ||
| 197 | + | ||
| 198 | +// @override | ||
| 199 | +// void addAll(Iterable<E> item) { | ||
| 200 | +// _value.addAll(item); | ||
| 201 | +// refresh(); | ||
| 202 | +// } | ||
| 203 | + | ||
| 204 | +// /// Adds only if [item] is not null. | ||
| 205 | +// void addNonNull(E item) { | ||
| 206 | +// if (item != null) add(item); | ||
| 207 | +// } | ||
| 208 | + | ||
| 209 | +// /// Adds only if [item] is not null. | ||
| 210 | +// void addAllNonNull(Iterable<E> item) { | ||
| 211 | +// if (item != null) addAll(item); | ||
| 212 | +// } | ||
| 213 | + | ||
| 214 | +// int get length => value.length; | ||
| 215 | + | ||
| 216 | +// /// Removes an item from the list. | ||
| 217 | +// /// | ||
| 218 | +// /// This is O(N) in the number of items in the list. | ||
| 219 | +// /// | ||
| 220 | +// /// Returns whether the item was present in the list. | ||
| 221 | +// bool remove(Object item) { | ||
| 222 | +// var hasRemoved = _value.remove(item); | ||
| 223 | +// if (hasRemoved) { | ||
| 224 | +// refresh(); | ||
| 225 | +// } | ||
| 226 | +// return hasRemoved; | ||
| 227 | +// } | ||
| 228 | + | ||
| 229 | +// void removeWhere(bool Function(E) test) { | ||
| 230 | +// _value.removeWhere(test); | ||
| 231 | +// refresh(); | ||
| 232 | +// } | ||
| 233 | + | ||
| 234 | +// void clear() { | ||
| 235 | +// _value.clear(); | ||
| 236 | +// refresh(); | ||
| 237 | +// } | ||
| 238 | + | ||
| 239 | +// void close() { | ||
| 240 | +// _subscriptions.forEach((observable, subscription) { | ||
| 241 | +// subscription.cancel(); | ||
| 242 | +// }); | ||
| 243 | +// _subscriptions.clear(); | ||
| 244 | +// subject.close(); | ||
| 245 | +// } | ||
| 246 | + | ||
| 247 | +// /// Replaces all existing items of this list with [item] | ||
| 248 | +// void assign(E item) { | ||
| 249 | +// clear(); | ||
| 250 | +// add(item); | ||
| 251 | +// } | ||
| 252 | + | ||
| 253 | +// void update(void fn(Iterable<E> value)) { | ||
| 254 | +// fn(value); | ||
| 255 | +// refresh(); | ||
| 256 | +// } | ||
| 257 | + | ||
| 258 | +// /// Replaces all existing items of this list with [items] | ||
| 259 | +// void assignAll(Iterable<E> items) { | ||
| 260 | +// clear(); | ||
| 261 | +// addAll(items); | ||
| 262 | +// } | ||
| 263 | + | ||
| 264 | +// @protected | ||
| 265 | +// Set<E> get value { | ||
| 266 | +// if (getObs != null) { | ||
| 267 | +// getObs.addListener(subject.stream); | ||
| 268 | +// } | ||
| 269 | +// return _value; | ||
| 270 | +// } | ||
| 271 | + | ||
| 272 | +// String get string => value.toString(); | ||
| 273 | + | ||
| 274 | +// void addListener(Stream<Set<E>> rxGetX) { | ||
| 275 | +// if (_subscriptions.containsKey(rxGetX)) { | ||
| 276 | +// return; | ||
| 277 | +// } | ||
| 278 | +// _subscriptions[rxGetX] = rxGetX.listen((data) { | ||
| 279 | +// subject.add(data); | ||
| 280 | +// }); | ||
| 281 | +// } | ||
| 282 | + | ||
| 283 | +// set value(Set<E> val) { | ||
| 284 | +// if (_value == val) return; | ||
| 285 | +// _value = val; | ||
| 286 | +// refresh(); | ||
| 287 | +// } | ||
| 288 | + | ||
| 289 | +// Stream<Set<E>> get stream => subject.stream; | ||
| 290 | + | ||
| 291 | +// StreamSubscription<Set<E>> listen(void Function(Set<E>) onData, | ||
| 292 | +// {Function onError, void Function() onDone, bool cancelOnError}) => | ||
| 293 | +// stream.listen(onData, onError: onError, onDone: onDone); | ||
| 294 | + | ||
| 295 | +// /// Binds an existing [Stream<Set>] to this [RxSet]. | ||
| 296 | +// /// You can bind multiple sources to update the value. | ||
| 297 | +// /// Closing the subscription will happen automatically when the observer | ||
| 298 | +// /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree. | ||
| 299 | +// void bindStream(Stream<Set<E>> stream) { | ||
| 300 | +// _subscriptions[stream] = stream.listen((va) => value = va); | ||
| 301 | +// } | ||
| 302 | + | ||
| 303 | +// @override | ||
| 304 | +// E get first => value.first; | ||
| 305 | + | ||
| 306 | +// @override | ||
| 307 | +// E get last => value.last; | ||
| 308 | + | ||
| 309 | +// @override | ||
| 310 | +// bool any(bool Function(E) test) { | ||
| 311 | +// return value.any(test); | ||
| 312 | +// } | ||
| 313 | + | ||
| 314 | +// @override | ||
| 315 | +// Set<R> cast<R>() { | ||
| 316 | +// return value.cast<R>(); | ||
| 317 | +// } | ||
| 318 | + | ||
| 319 | +// @override | ||
| 320 | +// bool contains(Object element) { | ||
| 321 | +// return value.contains(element); | ||
| 322 | +// } | ||
| 323 | + | ||
| 324 | +// @override | ||
| 325 | +// E elementAt(int index) { | ||
| 326 | +// return value.elementAt(index); | ||
| 327 | +// } | ||
| 328 | + | ||
| 329 | +// @override | ||
| 330 | +// bool every(bool Function(E) test) { | ||
| 331 | +// return value.every(test); | ||
| 332 | +// } | ||
| 333 | + | ||
| 334 | +// @override | ||
| 335 | +// Iterable<T> expand<T>(Iterable<T> Function(E) f) { | ||
| 336 | +// return value.expand(f); | ||
| 337 | +// } | ||
| 338 | + | ||
| 339 | +// @override | ||
| 340 | +// E firstWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 341 | +// return value.firstWhere(test, orElse: orElse); | ||
| 342 | +// } | ||
| 343 | + | ||
| 344 | +// @override | ||
| 345 | +// T fold<T>(T initialValue, T Function(T, E) combine) { | ||
| 346 | +// return value.fold(initialValue, combine); | ||
| 347 | +// } | ||
| 348 | + | ||
| 349 | +// @override | ||
| 350 | +// Iterable<E> followedBy(Iterable<E> other) { | ||
| 351 | +// return value.followedBy(other); | ||
| 352 | +// } | ||
| 353 | + | ||
| 354 | +// @override | ||
| 355 | +// void forEach(void Function(E) f) { | ||
| 356 | +// value.forEach(f); | ||
| 357 | +// } | ||
| 358 | + | ||
| 359 | +// @override | ||
| 360 | +// String join([String separator = ""]) { | ||
| 361 | +// return value.join(separator); | ||
| 362 | +// } | ||
| 363 | + | ||
| 364 | +// @override | ||
| 365 | +// E lastWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 366 | +// return value.lastWhere(test, orElse: orElse); | ||
| 367 | +// } | ||
| 368 | + | ||
| 369 | +// @override | ||
| 370 | +// Iterable<T> map<T>(T Function(E) f) { | ||
| 371 | +// return value.map(f); | ||
| 372 | +// } | ||
| 373 | + | ||
| 374 | +// @override | ||
| 375 | +// E reduce(E Function(E, E) combine) { | ||
| 376 | +// return value.reduce(combine); | ||
| 377 | +// } | ||
| 378 | + | ||
| 379 | +// @override | ||
| 380 | +// E get single => value.single; | ||
| 381 | + | ||
| 382 | +// @override | ||
| 383 | +// E singleWhere(bool Function(E) test, {E Function() orElse}) { | ||
| 384 | +// return value.singleWhere(test, orElse: orElse); | ||
| 385 | +// } | ||
| 386 | + | ||
| 387 | +// @override | ||
| 388 | +// Iterable<E> skip(int count) { | ||
| 389 | +// return value.skip(count); | ||
| 390 | +// } | ||
| 391 | + | ||
| 392 | +// @override | ||
| 393 | +// Iterable<E> skipWhile(bool Function(E) test) { | ||
| 394 | +// return value.skipWhile(test); | ||
| 395 | +// } | ||
| 396 | + | ||
| 397 | +// @override | ||
| 398 | +// Iterable<E> take(int count) { | ||
| 399 | +// return value.take(count); | ||
| 400 | +// } | ||
| 401 | + | ||
| 402 | +// @override | ||
| 403 | +// Iterable<E> takeWhile(bool Function(E) test) { | ||
| 404 | +// return value.takeWhile(test); | ||
| 405 | +// } | ||
| 406 | + | ||
| 407 | +// @override | ||
| 408 | +// List<E> toList({bool growable = true}) { | ||
| 409 | +// return value.toList(growable: growable); | ||
| 410 | +// } | ||
| 411 | + | ||
| 412 | +// @override | ||
| 413 | +// Set<E> toSet() { | ||
| 414 | +// return value.toSet(); | ||
| 415 | +// } | ||
| 416 | + | ||
| 417 | +// @override | ||
| 418 | +// Iterable<E> where(bool Function(E) test) { | ||
| 419 | +// return value.where(test); | ||
| 420 | +// } | ||
| 421 | + | ||
| 422 | +// @override | ||
| 423 | +// Iterable<T> whereType<T>() { | ||
| 424 | +// return value.whereType<T>(); | ||
| 425 | +// } | ||
| 426 | + | ||
| 427 | +// @override | ||
| 428 | +// bool containsAll(Iterable<Object> other) { | ||
| 429 | +// return value.containsAll(other); | ||
| 430 | +// } | ||
| 431 | + | ||
| 432 | +// @override | ||
| 433 | +// Set<E> difference(Set<Object> other) { | ||
| 434 | +// return value.difference(other); | ||
| 435 | +// } | ||
| 436 | + | ||
| 437 | +// @override | ||
| 438 | +// Set<E> intersection(Set<Object> other) { | ||
| 439 | +// return value.intersection(other); | ||
| 440 | +// } | ||
| 441 | + | ||
| 442 | +// @override | ||
| 443 | +// E lookup(Object object) { | ||
| 444 | +// return value.lookup(object); | ||
| 445 | +// } | ||
| 446 | + | ||
| 447 | +// @override | ||
| 448 | +// void removeAll(Iterable<Object> elements) { | ||
| 449 | +// _value.removeAll(elements); | ||
| 450 | +// refresh(); | ||
| 451 | +// } | ||
| 452 | + | ||
| 453 | +// @override | ||
| 454 | +// void retainAll(Iterable<Object> elements) { | ||
| 455 | +// _value.retainAll(elements); | ||
| 456 | +// refresh(); | ||
| 457 | +// } | ||
| 458 | + | ||
| 459 | +// @override | ||
| 460 | +// void retainWhere(bool Function(E) E) { | ||
| 461 | +// _value.retainWhere(E); | ||
| 462 | +// refresh(); | ||
| 463 | +// } | ||
| 464 | + | ||
| 465 | +// @override | ||
| 466 | +// Set<E> union(Set<E> other) { | ||
| 467 | +// return value.union(other); | ||
| 468 | +// } | ||
| 469 | +// } | ||
| 470 | + | ||
| 471 | +extension SetExtension<E> on Set<E> { | ||
| 472 | + RxSet<E> get obs { | ||
| 473 | + if (this != null) { | ||
| 474 | + return RxSet<E>(<E>{})..addAllNonNull(this); | ||
| 475 | + } else { | ||
| 476 | + return RxSet<E>(null); | ||
| 477 | + } | ||
| 478 | + } | ||
| 479 | +} | 
lib/get_rx/src/rx_types/rx_types.dart
0 → 100644
| 1 | +library rx_types; | ||
| 2 | + | ||
| 3 | +import 'dart:async'; | ||
| 4 | +import 'dart:collection'; | ||
| 5 | + | ||
| 6 | +import 'package:flutter/foundation.dart'; | ||
| 7 | +import '../rx_stream/rx_stream.dart'; | ||
| 8 | +import '../rx_typedefs/rx_typedefs.dart'; | ||
| 9 | + | ||
| 10 | +part 'rx_core/rx_impl.dart'; | ||
| 11 | +part 'rx_core/rx_interface.dart'; | ||
| 12 | +part 'rx_core/rx_num.dart'; | ||
| 13 | + | ||
| 14 | +part 'rx_iterables/rx_list.dart'; | ||
| 15 | +part 'rx_iterables/rx_set.dart'; | ||
| 16 | +part 'rx_iterables/rx_map.dart'; | 
| 1 | import 'dart:async'; | 1 | import 'dart:async'; | 
| 2 | + | ||
| 2 | import '../../../get_core/get_core.dart'; | 3 | import '../../../get_core/get_core.dart'; | 
| 3 | -import '../rx_core/rx_interface.dart'; | 4 | +import '../rx_types/rx_types.dart'; | 
| 4 | import 'utils/debouncer.dart'; | 5 | import 'utils/debouncer.dart'; | 
| 5 | 6 | ||
| 6 | bool _conditional(dynamic condition) { | 7 | bool _conditional(dynamic condition) { | 
| @@ -42,7 +43,7 @@ bool _conditional(dynamic condition) { | @@ -42,7 +43,7 @@ bool _conditional(dynamic condition) { | ||
| 42 | /// ``` | 43 | /// ``` | 
| 43 | Worker ever<T>(RxInterface<T> listener, Function(T) callback, | 44 | Worker ever<T>(RxInterface<T> listener, Function(T) callback, | 
| 44 | {dynamic condition = true}) { | 45 | {dynamic condition = true}) { | 
| 45 | - StreamSubscription sub = listener.subject.stream.listen((event) { | 46 | + StreamSubscription sub = listener.subject.listen((event) { | 
| 46 | if (_conditional(condition)) callback(event); | 47 | if (_conditional(condition)) callback(event); | 
| 47 | }); | 48 | }); | 
| 48 | return Worker(sub.cancel, '[ever]'); | 49 | return Worker(sub.cancel, '[ever]'); | 
| @@ -56,7 +57,7 @@ Worker everAll(List<RxInterface> listeners, Function(dynamic) callback, | @@ -56,7 +57,7 @@ Worker everAll(List<RxInterface> listeners, Function(dynamic) callback, | ||
| 56 | {dynamic condition = true}) { | 57 | {dynamic condition = true}) { | 
| 57 | final evers = <StreamSubscription>[]; | 58 | final evers = <StreamSubscription>[]; | 
| 58 | for (var i in listeners) { | 59 | for (var i in listeners) { | 
| 59 | - final sub = i.subject.stream.listen((event) { | 60 | + final sub = i.subject.listen((event) { | 
| 60 | if (_conditional(condition)) callback(event); | 61 | if (_conditional(condition)) callback(event); | 
| 61 | }); | 62 | }); | 
| 62 | evers.add(sub); | 63 | evers.add(sub); | 
| @@ -97,7 +98,7 @@ Worker once<T>(RxInterface<T> listener, Function(T) callback, | @@ -97,7 +98,7 @@ Worker once<T>(RxInterface<T> listener, Function(T) callback, | ||
| 97 | {dynamic condition}) { | 98 | {dynamic condition}) { | 
| 98 | Worker ref; | 99 | Worker ref; | 
| 99 | StreamSubscription sub; | 100 | StreamSubscription sub; | 
| 100 | - sub = listener.subject.stream.listen((event) { | 101 | + sub = listener.subject.listen((event) { | 
| 101 | if (!_conditional(condition)) return; | 102 | if (!_conditional(condition)) return; | 
| 102 | ref._disposed = true; | 103 | ref._disposed = true; | 
| 103 | ref._log('called'); | 104 | ref._log('called'); | 
| @@ -129,7 +130,7 @@ Worker interval<T>(RxInterface<T> listener, Function(T) callback, | @@ -129,7 +130,7 @@ Worker interval<T>(RxInterface<T> listener, Function(T) callback, | ||
| 129 | {Duration time = const Duration(seconds: 1), dynamic condition = true}) { | 130 | {Duration time = const Duration(seconds: 1), dynamic condition = true}) { | 
| 130 | var debounceActive = false; | 131 | var debounceActive = false; | 
| 131 | time ??= const Duration(seconds: 1); | 132 | time ??= const Duration(seconds: 1); | 
| 132 | - StreamSubscription sub = listener.subject.stream.listen((event) async { | 133 | + StreamSubscription sub = listener.subject.listen((event) async { | 
| 133 | if (debounceActive || !_conditional(condition)) return; | 134 | if (debounceActive || !_conditional(condition)) return; | 
| 134 | debounceActive = true; | 135 | debounceActive = true; | 
| 135 | await Future.delayed(time); | 136 | await Future.delayed(time); | 
| @@ -162,7 +163,7 @@ Worker debounce<T>(RxInterface<T> listener, Function(T) callback, | @@ -162,7 +163,7 @@ Worker debounce<T>(RxInterface<T> listener, Function(T) callback, | ||
| 162 | {Duration time}) { | 163 | {Duration time}) { | 
| 163 | final _debouncer = | 164 | final _debouncer = | 
| 164 | Debouncer(delay: time ?? const Duration(milliseconds: 800)); | 165 | Debouncer(delay: time ?? const Duration(milliseconds: 800)); | 
| 165 | - StreamSubscription sub = listener.subject.stream.listen((event) { | 166 | + StreamSubscription sub = listener.subject.listen((event) { | 
| 166 | _debouncer(() { | 167 | _debouncer(() { | 
| 167 | callback(event); | 168 | callback(event); | 
| 168 | }); | 169 | }); | 
| @@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart'; | @@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart'; | ||
| 4 | 4 | ||
| 5 | import '../../../get_core/get_core.dart'; | 5 | import '../../../get_core/get_core.dart'; | 
| 6 | import '../../../get_instance/src/get_instance.dart'; | 6 | import '../../../get_instance/src/get_instance.dart'; | 
| 7 | -import '../../../get_rx/get_rx.dart'; | 7 | +import '../../../get_rx/src/rx_types/rx_types.dart'; | 
| 8 | import '../../get_state_manager.dart'; | 8 | import '../../get_state_manager.dart'; | 
| 9 | 9 | ||
| 10 | typedef GetXControllerBuilder<T extends DisposableInterface> = Widget Function( | 10 | typedef GetXControllerBuilder<T extends DisposableInterface> = Widget Function( | 
| @@ -38,10 +38,11 @@ class GetX<T extends DisposableInterface> extends StatefulWidget { | @@ -38,10 +38,11 @@ class GetX<T extends DisposableInterface> extends StatefulWidget { | ||
| 38 | // this.streamController | 38 | // this.streamController | 
| 39 | }); | 39 | }); | 
| 40 | 40 | ||
| 41 | - GetImplXState<T> createState() => GetImplXState<T>(); | 41 | + @override | 
| 42 | + GetXState<T> createState() => GetXState<T>(); | ||
| 42 | } | 43 | } | 
| 43 | 44 | ||
| 44 | -class GetImplXState<T extends DisposableInterface> extends State<GetX<T>> { | 45 | +class GetXState<T extends DisposableInterface> extends State<GetX<T>> { | 
| 45 | RxInterface _observer; | 46 | RxInterface _observer; | 
| 46 | T controller; | 47 | T controller; | 
| 47 | bool isCreator = false; | 48 | bool isCreator = false; | 
| @@ -76,7 +77,7 @@ class GetImplXState<T extends DisposableInterface> extends State<GetX<T>> { | @@ -76,7 +77,7 @@ class GetImplXState<T extends DisposableInterface> extends State<GetX<T>> { | ||
| 76 | if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) { | 77 | if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) { | 
| 77 | controller?.onStart(); | 78 | controller?.onStart(); | 
| 78 | } | 79 | } | 
| 79 | - subs = _observer.subject.stream.listen((data) => setState(() {})); | 80 | + subs = _observer.subject.listen((data) => setState(() {})); | 
| 80 | super.initState(); | 81 | super.initState(); | 
| 81 | } | 82 | } | 
| 82 | 83 | 
| 1 | import 'dart:async'; | 1 | import 'dart:async'; | 
| 2 | import 'package:flutter/widgets.dart'; | 2 | import 'package:flutter/widgets.dart'; | 
| 3 | -import '../../../get_rx/get_rx.dart'; | 3 | +import '../../../get_rx/src/rx_types/rx_types.dart'; | 
| 4 | 4 | ||
| 5 | typedef WidgetCallback = Widget Function(); | 5 | typedef WidgetCallback = Widget Function(); | 
| 6 | 6 | ||
| @@ -12,6 +12,7 @@ typedef WidgetCallback = Widget Function(); | @@ -12,6 +12,7 @@ typedef WidgetCallback = Widget Function(); | ||
| 12 | abstract class ObxWidget extends StatefulWidget { | 12 | abstract class ObxWidget extends StatefulWidget { | 
| 13 | const ObxWidget({Key key}) : super(key: key); | 13 | const ObxWidget({Key key}) : super(key: key); | 
| 14 | 14 | ||
| 15 | + @override | ||
| 15 | _ObxState createState() => _ObxState(); | 16 | _ObxState createState() => _ObxState(); | 
| 16 | 17 | ||
| 17 | @protected | 18 | @protected | 
| @@ -28,7 +29,7 @@ class _ObxState extends State<ObxWidget> { | @@ -28,7 +29,7 @@ class _ObxState extends State<ObxWidget> { | ||
| 28 | 29 | ||
| 29 | @override | 30 | @override | 
| 30 | void initState() { | 31 | void initState() { | 
| 31 | - subs = _observer.subject.stream.listen((data) => setState(() {})); | 32 | + subs = _observer.subject.listen((data) => setState(() {})); | 
| 32 | super.initState(); | 33 | super.initState(); | 
| 33 | } | 34 | } | 
| 34 | 35 | 
| @@ -21,5 +21,6 @@ import '../../get_state_manager.dart'; | @@ -21,5 +21,6 @@ import '../../get_state_manager.dart'; | ||
| 21 | /// ``` | 21 | /// ``` | 
| 22 | mixin SingleGetTickerProviderMixin on DisposableInterface | 22 | mixin SingleGetTickerProviderMixin on DisposableInterface | 
| 23 | implements TickerProvider { | 23 | implements TickerProvider { | 
| 24 | + @override | ||
| 24 | Ticker createTicker(TickerCallback onTick) => Ticker(onTick); | 25 | Ticker createTicker(TickerCallback onTick) => Ticker(onTick); | 
| 25 | } | 26 | } | 
| 1 | import 'dart:async'; | 1 | import 'dart:async'; | 
| 2 | - | ||
| 3 | import 'package:flutter/foundation.dart'; | 2 | import 'package:flutter/foundation.dart'; | 
| 4 | import 'package:flutter_test/flutter_test.dart'; | 3 | import 'package:flutter_test/flutter_test.dart'; | 
| 5 | import 'package:get/state_manager.dart'; | 4 | import 'package:get/state_manager.dart'; | 
| @@ -7,8 +6,8 @@ import 'package:get/state_manager.dart'; | @@ -7,8 +6,8 @@ import 'package:get/state_manager.dart'; | ||
| 7 | int times = 3; | 6 | int times = 3; | 
| 8 | int get last => times - 1; | 7 | int get last => times - 1; | 
| 9 | 8 | ||
| 10 | -Future<String> valueNotifier() { | ||
| 11 | - final c = Completer<String>(); | 9 | +Future<int> valueNotifier() { | 
| 10 | + final c = Completer<int>(); | ||
| 12 | final value = ValueNotifier<int>(0); | 11 | final value = ValueNotifier<int>(0); | 
| 13 | final timer = Stopwatch(); | 12 | final timer = Stopwatch(); | 
| 14 | timer.start(); | 13 | timer.start(); | 
| @@ -16,8 +15,9 @@ Future<String> valueNotifier() { | @@ -16,8 +15,9 @@ Future<String> valueNotifier() { | ||
| 16 | value.addListener(() { | 15 | value.addListener(() { | 
| 17 | if (last == value.value) { | 16 | if (last == value.value) { | 
| 18 | timer.stop(); | 17 | timer.stop(); | 
| 19 | - c.complete( | ||
| 20 | - """${value.value} listeners notified | [VALUENOTIFIER] objs time: ${timer.elapsedMicroseconds}ms"""); | 18 | + print( | 
| 19 | + """${value.value} listeners notified | [VALUE_NOTIFIER] time: ${timer.elapsedMicroseconds}ms"""); | ||
| 20 | + c.complete(timer.elapsedMicroseconds); | ||
| 21 | } | 21 | } | 
| 22 | }); | 22 | }); | 
| 23 | 23 | ||
| @@ -28,8 +28,8 @@ Future<String> valueNotifier() { | @@ -28,8 +28,8 @@ Future<String> valueNotifier() { | ||
| 28 | return c.future; | 28 | return c.future; | 
| 29 | } | 29 | } | 
| 30 | 30 | ||
| 31 | -Future<String> getValue() { | ||
| 32 | - final c = Completer<String>(); | 31 | +Future<int> getValue() { | 
| 32 | + final c = Completer<int>(); | ||
| 33 | final value = Value<int>(0); | 33 | final value = Value<int>(0); | 
| 34 | final timer = Stopwatch(); | 34 | final timer = Stopwatch(); | 
| 35 | timer.start(); | 35 | timer.start(); | 
| @@ -37,8 +37,9 @@ Future<String> getValue() { | @@ -37,8 +37,9 @@ Future<String> getValue() { | ||
| 37 | value.addListener(() { | 37 | value.addListener(() { | 
| 38 | if (last == value.value) { | 38 | if (last == value.value) { | 
| 39 | timer.stop(); | 39 | timer.stop(); | 
| 40 | - c.complete( | ||
| 41 | - """${value.value} listeners notified | [GETX VALUE] objs time: ${timer.elapsedMicroseconds}ms"""); | 40 | + print( | 
| 41 | + """${value.value} listeners notified | [GETX_VALUE] time: ${timer.elapsedMicroseconds}ms"""); | ||
| 42 | + c.complete(timer.elapsedMicroseconds); | ||
| 42 | } | 43 | } | 
| 43 | }); | 44 | }); | 
| 44 | 45 | ||
| @@ -49,8 +50,8 @@ Future<String> getValue() { | @@ -49,8 +50,8 @@ Future<String> getValue() { | ||
| 49 | return c.future; | 50 | return c.future; | 
| 50 | } | 51 | } | 
| 51 | 52 | ||
| 52 | -Future<String> getStream() { | ||
| 53 | - final c = Completer<String>(); | 53 | +Future<int> stream() { | 
| 54 | + final c = Completer<int>(); | ||
| 54 | 55 | ||
| 55 | final value = StreamController<int>(); | 56 | final value = StreamController<int>(); | 
| 56 | final timer = Stopwatch(); | 57 | final timer = Stopwatch(); | 
| @@ -59,8 +60,55 @@ Future<String> getStream() { | @@ -59,8 +60,55 @@ Future<String> getStream() { | ||
| 59 | value.stream.listen((v) { | 60 | value.stream.listen((v) { | 
| 60 | if (last == v) { | 61 | if (last == v) { | 
| 61 | timer.stop(); | 62 | timer.stop(); | 
| 62 | - c.complete( | ||
| 63 | - """$v listeners notified | [STREAM] objs time: ${timer.elapsedMicroseconds}ms"""); | 63 | + print( | 
| 64 | + """$v listeners notified | [STREAM] time: ${timer.elapsedMicroseconds}ms"""); | ||
| 65 | + c.complete(timer.elapsedMicroseconds); | ||
| 66 | + } | ||
| 67 | + }); | ||
| 68 | + | ||
| 69 | + for (var i = 0; i < times; i++) { | ||
| 70 | + value.add(i); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + return c.future; | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +Future<int> getStream() { | ||
| 77 | + final c = Completer<int>(); | ||
| 78 | + | ||
| 79 | + final value = GetStream<int>(); | ||
| 80 | + final timer = Stopwatch(); | ||
| 81 | + timer.start(); | ||
| 82 | + | ||
| 83 | + value.listen((v) { | ||
| 84 | + if (last == v) { | ||
| 85 | + timer.stop(); | ||
| 86 | + print( | ||
| 87 | + """$v listeners notified | [GET_STREAM] time: ${timer.elapsedMicroseconds}ms"""); | ||
| 88 | + c.complete(timer.elapsedMicroseconds); | ||
| 89 | + } | ||
| 90 | + }); | ||
| 91 | + | ||
| 92 | + for (var i = 0; i < times; i++) { | ||
| 93 | + value.add(i); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + return c.future; | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +Future<int> miniStream() { | ||
| 100 | + final c = Completer<int>(); | ||
| 101 | + | ||
| 102 | + final value = MiniStream<int>(); | ||
| 103 | + final timer = Stopwatch(); | ||
| 104 | + timer.start(); | ||
| 105 | + | ||
| 106 | + value.listen((v) { | ||
| 107 | + if (last == v) { | ||
| 108 | + timer.stop(); | ||
| 109 | + print( | ||
| 110 | + """$v listeners notified | [MINI_STREAM] time: ${timer.elapsedMicroseconds}ms"""); | ||
| 111 | + c.complete(timer.elapsedMicroseconds); | ||
| 64 | } | 112 | } | 
| 65 | }); | 113 | }); | 
| 66 | 114 | ||
| @@ -72,15 +120,43 @@ Future<String> getStream() { | @@ -72,15 +120,43 @@ Future<String> getStream() { | ||
| 72 | } | 120 | } | 
| 73 | 121 | ||
| 74 | void main() async { | 122 | void main() async { | 
| 75 | - test('run benchmarks', () async { | ||
| 76 | - print(await getValue()); | ||
| 77 | - print(await valueNotifier()); | ||
| 78 | - print(await getStream()); | 123 | + test('run benchmarks from ValueNotifier', () async { | 
| 124 | + await getValue(); | ||
| 125 | + await valueNotifier(); | ||
| 126 | + | ||
| 127 | + times = 30000; | ||
| 128 | + await getValue(); | ||
| 129 | + await valueNotifier(); | ||
| 130 | + }); | ||
| 131 | + | ||
| 132 | + test('percentage test', () { | ||
| 133 | + final referenceValue = 200; | ||
| 134 | + final requestedValue = 100; | ||
| 135 | + | ||
| 136 | + print(''' | ||
| 137 | +referenceValue is ${calculePercentage(referenceValue, requestedValue)}% more than requestedValue'''); | ||
| 138 | + expect(calculePercentage(referenceValue, requestedValue), 100); | ||
| 139 | + }); | ||
| 140 | + | ||
| 141 | + test('run benchmarks from Streams', () async { | ||
| 142 | + var dart = await stream(); | ||
| 143 | + var getx = await getStream(); | ||
| 144 | + var mini = await miniStream(); | ||
| 145 | + print(''' | ||
| 146 | +GetStream is ${calculePercentage(dart, getx).round()}% more fast than Default Stream with $last listeners'''); | ||
| 79 | times = 30000; | 147 | times = 30000; | 
| 80 | - print(await getValue()); | ||
| 81 | - print(await valueNotifier()); | ||
| 82 | - print(await getStream()); | 148 | + dart = await stream(); | 
| 149 | + getx = await getStream(); | ||
| 150 | + mini = await miniStream(); | ||
| 151 | + | ||
| 152 | + print('dart is $dart'); | ||
| 153 | + print('getx is $getx'); | ||
| 154 | + print('mini is $mini'); | ||
| 155 | + print(''' | ||
| 156 | +GetStream is ${calculePercentage(dart, getx).round()}% more fast than Default Stream with $last listeners'''); | ||
| 83 | }); | 157 | }); | 
| 84 | } | 158 | } | 
| 85 | 159 | ||
| 86 | -typedef VoidCallback = void Function(); | 160 | +int calculePercentage(int dart, int getx) { | 
| 161 | + return (dart / getx * 100).round() - 100; | ||
| 162 | +} | 
- 
Please register or login to post a comment