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