diff --git a/.vscode/launch.json b/.vscode/launch.json index 90c289b0..c2ed9e15 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -24,14 +24,14 @@ "SERVER_URL=https://app.pal-plugin.tech/api" ] }, - // { - // "name": "Dart: Run all Tests", - // "type": "dart", - // "request": "launch", - // "program": "./test/", - // "presentation": { - // "clear": true, - // } - // }, + { + "name": "Run all Tests", + "type": "dart", + "request": "launch", + "program": "./test/", + "presentation": { + "clear": true, + } + }, ] } \ No newline at end of file diff --git a/README.md b/README.md index 719390f6..fa7358fc 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ class MyApp extends StatelessWidget { appToken: 'REPLACE_WITH_YOUR_APP_TOKEN', // -------------------- // YOUR APP IS HERE - child: MaterialApp( + childApp: MaterialApp( navigatorKey: _navigatorKey, navigatorObservers: [PalNavigatorObserver.instance()], home: YourApp(), diff --git a/example/.vscode/launch.json b/example/.vscode/launch.json new file mode 100644 index 00000000..035204ca --- /dev/null +++ b/example/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. + // Pointez pour afficher la description des attributs existants. + // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "example", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/example/android/app/src/main/kotlin/io/apparence/example/MainActivity.kt b/example/android/app/src/main/kotlin/io/apparence/example/MainActivity.kt new file mode 100644 index 00000000..8e8edfab --- /dev/null +++ b/example/android/app/src/main/kotlin/io/apparence/example/MainActivity.kt @@ -0,0 +1,6 @@ +package io.apparence.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..449a9f93 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index ebbb63cd..acde3456 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,11 +1,9 @@ PODS: - - application_icon (0.0.1): - - Flutter - Flutter (1.0.0) - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - package_info (0.0.1): + - package_info_plus (0.4.5): - Flutter - path_provider (0.0.1): - Flutter @@ -14,9 +12,8 @@ PODS: - FMDB (>= 2.7.5) DEPENDENCIES: - - application_icon (from `.symlinks/plugins/application_icon/ios`) - Flutter (from `Flutter`) - - package_info (from `.symlinks/plugins/package_info/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) @@ -25,22 +22,19 @@ SPEC REPOS: - FMDB EXTERNAL SOURCES: - application_icon: - :path: ".symlinks/plugins/application_icon/ios" Flutter: :path: Flutter - package_info: - :path: ".symlinks/plugins/package_info/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" path_provider: :path: ".symlinks/plugins/path_provider/ios" sqflite: :path: ".symlinks/plugins/sqflite/ios" SPEC CHECKSUMS: - application_icon: 6c882fd954934784443dad48a169cadb5f326cb1 Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 + package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 diff --git a/example/lib/main.dart b/example/lib/main.dart index 6f5a9dcc..ea85f688 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -16,7 +16,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Pal( - editorModeEnabled: true, + editorModeEnabled: false, appToken: APPLICATION_TOKEN, // don't forget to give us a token (create it from the web dashboard configuration tab) // --- your app is here -- childApp: MaterialApp( diff --git a/example/linux/.gitignore b/example/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/example/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/example/linux/CMakeLists.txt b/example/linux/CMakeLists.txt new file mode 100644 index 00000000..33ccce35 --- /dev/null +++ b/example/linux/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") +set(APPLICATION_ID "io.apparence.example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/example/linux/flutter/CMakeLists.txt b/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..a1da1b9e --- /dev/null +++ b/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,91 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) +pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid) +pkg_check_modules(LZMA REQUIRED IMPORTED_TARGET liblzma) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO + PkgConfig::BLKID + PkgConfig::LZMA +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/example/linux/flutter/generated_plugin_registrant.cc b/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..d38195aa --- /dev/null +++ b/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,9 @@ +// +// Generated file. Do not edit. +// + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/example/linux/flutter/generated_plugin_registrant.h b/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..9bf74789 --- /dev/null +++ b/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/example/linux/flutter/generated_plugins.cmake b/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..51436ae8 --- /dev/null +++ b/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,15 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/example/linux/main.cc b/example/linux/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/example/linux/my_application.cc b/example/linux/my_application.cc new file mode 100644 index 00000000..543eaca7 --- /dev/null +++ b/example/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen *screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } + else { + gtk_window_set_title(window, "example"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject *object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + nullptr)); +} diff --git a/example/linux/my_application.h b/example/linux/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/example/macos/.gitignore b/example/macos/.gitignore new file mode 100644 index 00000000..d2fd3772 --- /dev/null +++ b/example/macos/.gitignore @@ -0,0 +1,6 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/xcuserdata/ diff --git a/example/macos/Flutter/Flutter-Debug.xcconfig b/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Flutter/Flutter-Release.xcconfig b/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..4672798d --- /dev/null +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,16 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import package_info_plus_macos +import path_provider_macos +import sqflite + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) +} diff --git a/example/macos/Podfile b/example/macos/Podfile new file mode 100644 index 00000000..dade8dfa --- /dev/null +++ b/example/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.11' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock new file mode 100644 index 00000000..0dd021c2 --- /dev/null +++ b/example/macos/Podfile.lock @@ -0,0 +1,43 @@ +PODS: + - FlutterMacOS (1.0.0) + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - package_info_plus_macos (0.0.1): + - FlutterMacOS + - path_provider_macos (0.0.1): + - FlutterMacOS + - sqflite (0.0.2): + - FlutterMacOS + - FMDB (>= 2.7.5) + +DEPENDENCIES: + - FlutterMacOS (from `Flutter/ephemeral`) + - package_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos`) + - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) + - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) + +SPEC REPOS: + trunk: + - FMDB + +EXTERNAL SOURCES: + FlutterMacOS: + :path: Flutter/ephemeral + package_info_plus_macos: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos + path_provider_macos: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos + sqflite: + :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos + +SPEC CHECKSUMS: + FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + package_info_plus_macos: f010621b07802a241d96d01876d6705f15e77c1c + path_provider_macos: a0a3fd666cb7cd0448e936fb4abad4052961002b + sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea + +PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c + +COCOAPODS: 1.10.1 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..ad6728b4 --- /dev/null +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,632 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 9F498F859A9279828D3FBE78 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE95350ACD4E6445C318ADA /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 2CD3FFE0F91528435C4C851E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 6CE95350ACD4E6445C318ADA /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + B601654DBD4EEB5D84BA5DE5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + B9C866C279310E498ADDA59B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9F498F859A9279828D3FBE78 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2ABB582C6CFEC18E5F1C71E8 /* Pods */ = { + isa = PBXGroup; + children = ( + 2CD3FFE0F91528435C4C851E /* Pods-Runner.debug.xcconfig */, + B601654DBD4EEB5D84BA5DE5 /* Pods-Runner.release.xcconfig */, + B9C866C279310E498ADDA59B /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 2ABB582C6CFEC18E5F1C71E8 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* example.app */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6CE95350ACD4E6445C318ADA /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 7A6CD897E70519F7AE6626D0 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 51DDADD1DF5337608B81A755 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 51DDADD1DF5337608B81A755 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 7A6CD897E70519F7AE6626D0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..ae8ff59d --- /dev/null +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/macos/Runner/AppDelegate.swift b/example/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..d53ef643 --- /dev/null +++ b/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 00000000..3c4935a7 Binary files /dev/null and b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 00000000..ed4cc164 Binary files /dev/null and b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 00000000..483be613 Binary files /dev/null and b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 00000000..bcbf36df Binary files /dev/null and b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 00000000..9c0a6528 Binary files /dev/null and b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 00000000..e71a7261 Binary files /dev/null and b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 00000000..8a31fe2d Binary files /dev/null and b/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/example/macos/Runner/Base.lproj/MainMenu.xib b/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 00000000..537341ab --- /dev/null +++ b/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/macos/Runner/Configs/AppInfo.xcconfig b/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..c4854ec7 --- /dev/null +++ b/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = io.apparence.example + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2021 io.apparence. All rights reserved. diff --git a/example/macos/Runner/Configs/Debug.xcconfig b/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/example/macos/Runner/Configs/Release.xcconfig b/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/example/macos/Runner/Configs/Warnings.xcconfig b/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/example/macos/Runner/DebugProfile.entitlements b/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..08c3ab17 --- /dev/null +++ b/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + com.apple.security.network.client + + + diff --git a/example/macos/Runner/Info.plist b/example/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/example/macos/Runner/MainFlutterWindow.swift b/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..2722837e --- /dev/null +++ b/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController.init() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/example/macos/Runner/Release.entitlements b/example/macos/Runner/Release.entitlements new file mode 100644 index 00000000..ee95ab7e --- /dev/null +++ b/example/macos/Runner/Release.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + + diff --git a/example/pubspec.lock b/example/pubspec.lock index 0308daa9..cb39e4fc 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,27 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "19.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - application_icon: - dependency: transitive - description: - name: application_icon - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" archive: dependency: transitive description: @@ -50,20 +29,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" cached_network_image: dependency: transitive description: name: cached_network_image url: "https://pub.dartlang.org" source: hosted - version: "2.5.1" + version: "3.0.0" characters: dependency: transitive description: @@ -78,13 +50,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.0" clock: dependency: transitive description: @@ -99,13 +64,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" crypto: dependency: transitive description: @@ -119,21 +77,14 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" + version: "1.0.3" dotted_border: dependency: transitive description: name: dotted_border url: "https://pub.dartlang.org" source: hosted - version: "1.0.7" + version: "2.0.0" fake_async: dependency: transitive description: @@ -166,14 +117,14 @@ packages: name: flutter_blurhash url: "https://pub.dartlang.org" source: hosted - version: "0.5.0" + version: "0.6.0" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "3.0.1" flutter_colorpicker: dependency: transitive description: @@ -198,13 +149,11 @@ packages: description: flutter source: sdk version: "0.0.0" - glob: + flutter_web_plugins: dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" + description: flutter + source: sdk + version: "0.0.0" google_fonts: dependency: transitive description: @@ -218,7 +167,7 @@ packages: name: hive url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.4" hive_flutter: dependency: transitive description: @@ -226,20 +175,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" - hive_generator: - dependency: transitive - description: - name: hive_generator - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" http: dependency: transitive description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.1" + version: "0.13.3" http_parser: dependency: transitive description: @@ -261,13 +203,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.0" - logging: + js: dependency: transitive description: - name: logging + name: js url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "0.6.3" matcher: dependency: transitive description: @@ -288,35 +230,63 @@ packages: name: mvvm_builder url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.0-null.safety" octo_image: dependency: transitive description: name: octo_image url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" - package_config: + version: "1.0.0+1" + package_info_plus: dependency: transitive description: - name: package_config + name: package_info_plus url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" - package_info: + version: "1.0.1" + package_info_plus_linux: dependency: transitive description: - name: package_info + name: package_info_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "1.0.1" + package_info_plus_macos: + dependency: transitive + description: + name: package_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + package_info_plus_web: + dependency: transitive + description: + name: package_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + package_info_plus_windows: + dependency: transitive + description: + name: package_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" pal: dependency: "direct main" description: path: ".." relative: true source: path - version: "1.0.0+1" + version: "2.0.0+1" path: dependency: transitive description: @@ -330,14 +300,14 @@ packages: name: path_drawing url: "https://pub.dartlang.org" source: hosted - version: "0.4.1+1" + version: "0.5.1" path_parsing: dependency: transitive description: name: path_parsing url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.2.1" path_provider: dependency: transitive description: @@ -408,32 +378,18 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.1.0" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" rxdart: dependency: transitive description: name: rxdart url: "https://pub.dartlang.org" source: hosted - version: "0.25.0" + version: "0.26.0" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" source_span: dependency: transitive description: @@ -447,14 +403,14 @@ packages: name: sqflite url: "https://pub.dartlang.org" source: hosted - version: "1.3.2+2" + version: "2.0.0+3" sqflite_common: dependency: transitive description: name: sqflite_common url: "https://pub.dartlang.org" source: hosted - version: "1.0.3+1" + version: "2.0.0+2" stack_trace: dependency: transitive description: @@ -482,7 +438,7 @@ packages: name: synchronized url: "https://pub.dartlang.org" source: hosted - version: "2.2.0+2" + version: "3.0.0" term_glyph: dependency: transitive description: @@ -518,13 +474,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" win32: dependency: transitive description: @@ -555,4 +504,4 @@ packages: version: "3.1.0" sdks: dart: ">=2.12.0 <3.0.0" - flutter: ">=1.26.0-17.5.pre" + flutter: ">=1.24.0-10.2.pre" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c8d7376c..882e369d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -26,10 +26,10 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.3 - pal: + cupertino_icons: ^1.0.3 + pal: #1.0.0+1 path: ../ - mvvm_builder: ^2.1.5 + mvvm_builder: ^3.0.0-null.safety intl: 0.17.0 dev_dependencies: diff --git a/example/test/main_test.dart b/example/test/main_test.dart deleted file mode 100644 index 2da53e41..00000000 --- a/example/test/main_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:pal_example/main.dart'; - -main() { - _before(WidgetTester tester) async { - TestWidgetsFlutterBinding.ensureInitialized(); - - MyApp myApp = MyApp(); - await tester.pumpWidget(myApp); - } - - group('Hosted app integration', () { - testWidgets('should be visible', (tester) async { - await _before(tester); - - expect(find.byKey(ValueKey('pal_MainStack')), findsOneWidget); - - Finder hostedApp = find.byKey(ValueKey('hostedApp')); - expect(hostedApp, findsOneWidget); - await tester.ensureVisible(hostedApp); - - expect(find.byKey(ValueKey('demo_HomePage')), findsOneWidget); - }); - }); - - group('Pal integration', () { - testWidgets('should be visible', (tester) async { - await _before(tester); - - expect(find.byKey(ValueKey('pal_MainStack')), findsOneWidget); - - Finder palBubble = find.byKey(ValueKey('palBubbleOverlay')); - expect(palBubble, findsOneWidget); - await tester.ensureVisible(palBubble); - }); - - // FIXME: Test can't pass because a network call is called from HelpersListModalLoader - // need to mock HelpersListModal - // testWidgets('floating bubble should be tappable', (tester) async { - // await before(tester); - // await tester.pumpAndSettle(); - - // Finder floatingBubble = find.byKey(ValueKey('palBubbleOverlay')); - // await tester.ensureVisible(floatingBubble); - // await tester.tap(floatingBubble); - // await tester.pumpAndSettle(); - - // // Helpers list modal should be visible - // Finder palHelpersListModal = find.byKey(ValueKey('palHelpersListModal')); - // expect(palHelpersListModal, findsOneWidget); - // await tester.ensureVisible(palHelpersListModal); - - // // Hosted app should be visible - // Finder hostedApp = find.byKey(ValueKey('hostedApp')); - // expect(hostedApp, findsOneWidget); - // await tester.ensureVisible(hostedApp); - - // // Close the modal - // Finder closeButton = find.byKey(ValueKey('palHelpersListModalClose')); - // expect(closeButton, findsOneWidget); - // await tester.ensureVisible(closeButton); - // await tester.tap(closeButton); - // await tester.pumpAndSettle(); - - // // Helpers modal should not be visible - // expect(find.byKey(ValueKey('palHelpersListModal')), findsNothing); - // }); - - testWidgets('floating bubble should be draggable', (tester) async { - await _before(tester); - - // Check if the floating bubble exist & be visible - Finder floatingBubble = find.byKey(ValueKey('palBubbleOverlay')); - await tester.ensureVisible(floatingBubble); - Offset oldBubblePosition = tester.getCenter(floatingBubble); - - // Fling the widget to given offset - Offset dragOffset = Offset(10.0, -40.0); - await tester.fling(floatingBubble, dragOffset, 3); - await tester.pumpAndSettle(); - - // Test if the position of the bubble was modified by the offset - Offset newBubblePosition = - tester.getCenter(find.byKey(ValueKey('palBubbleOverlay'))); - expect( - newBubblePosition.dx, equals(oldBubblePosition.dx + dragOffset.dx)); - expect( - newBubblePosition.dy, equals(oldBubblePosition.dy + dragOffset.dy)); - }); - }); -} diff --git a/example/test/ui/pages/home_test.dart b/example/test/ui/pages/home_test.dart deleted file mode 100644 index 801aae04..00000000 --- a/example/test/ui/pages/home_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:pal_example/ui/pages/home/home_page.dart'; - -main() { - group('Home page', () { - HomePage homePage = HomePage(); - - before(WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: homePage, - routes: { - '/route1': (context) => Scaffold(body: Text('Welcome to route 1')), - '/route2': (context) => Scaffold(body: Text('Welcome to route 2')), - }, - ), - ); - } - - testWidgets('should display properly', (tester) async { - await before(tester); - await tester.pumpAndSettle(); - - expect(find.byKey(ValueKey('demo_HomePage')), findsOneWidget); - - expect(find.text('Pal demo'), findsOneWidget); - - expect(find.text('Trending now'), findsOneWidget); - - expect(find.text('Get a look here'), findsOneWidget); - - expect(find.text('One more'), findsOneWidget); - expect(find.text('Second one'), findsOneWidget); - - expect(find.byKey(ValueKey('demo_HomePage_Cards_Truman')), findsOneWidget); - expect(find.byKey(ValueKey('demo_HomePage_Cards_Gump')), findsOneWidget); - expect(find.byKey(ValueKey('demo_HomePage_Cards_Joker')), findsOneWidget); - }); - - group('child navigation should work', () { - testWidgets('should push to route 1', (tester) async { - await before(tester); - await tester.pumpAndSettle(); - - Finder child1RouteButton = find.byKey(ValueKey('demo_HomePage_Cards_Joker')); - await tester.ensureVisible(child1RouteButton); - await tester.tap(child1RouteButton); - await tester.pumpAndSettle(); - - expect(find.text('Welcome to route 1'), findsOneWidget); - }); - - testWidgets('should push to route 2', (tester) async { - await before(tester); - await tester.pumpAndSettle(); - - Finder child1RouteButton = find.byKey(ValueKey('demo_HomePage_Cards_Gump')); - await tester.ensureVisible(child1RouteButton); - await tester.tap(child1RouteButton); - await tester.pumpAndSettle(); - - expect(find.text('Welcome to route 2'), findsOneWidget); - }); - }); - }); -} diff --git a/example/test/ui/pages/route1_test.dart b/example/test/ui/pages/route1_test.dart deleted file mode 100644 index 0cdea2f8..00000000 --- a/example/test/ui/pages/route1_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:pal_example/ui/pages/route1/route1_page.dart'; - -main() { - group('Route 1 page', () { - Route1Page route1page = Route1Page(); - - before(WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: route1page, - routes: { - '/route2': (context) => Scaffold(body: Text('Welcome to route 2')), - }, - ), - ); - } - - testWidgets('should display properly', (tester) async { - await before(tester); - await tester.pumpAndSettle(); - - expect(find.byKey(ValueKey('Route1')), findsOneWidget); - expect(find.text('Route 1'), findsOneWidget); - - expect(find.byKey(ValueKey('childRoute2Push2')), findsOneWidget); - }); - - testWidgets('should push to route 2', (tester) async { - await before(tester); - await tester.pumpAndSettle(); - - Finder child1RouteButton = find.byKey(ValueKey('childRoute2Push2')); - await tester.ensureVisible(child1RouteButton); - await tester.tap(child1RouteButton); - await tester.pumpAndSettle(); - - expect(find.text('Welcome to route 2'), findsOneWidget); - }); - }); -} diff --git a/example/test/ui/pages/route2_test.dart b/example/test/ui/pages/route2_test.dart deleted file mode 100644 index c45c0d65..00000000 --- a/example/test/ui/pages/route2_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:pal_example/ui/pages/route2/route2_page.dart'; - -main() { - group('Route 2 page', () { - Route2Page route2page = Route2Page(); - - before(WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: route2page, - ), - ); - } - - testWidgets('should display properly', (tester) async { - await before(tester); - await tester.pumpAndSettle(); - - expect(find.byKey(ValueKey('Route2')), findsOneWidget); - expect(find.text('Route 2'), findsOneWidget); - - expect(find.byKey(ValueKey('childRoutePop')), findsOneWidget); - }); - }); -} diff --git a/example/test/ui/widgets/.gitkeep b/example/test/ui/widgets/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/example/web/favicon.png b/example/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/example/web/favicon.png differ diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/example/web/icons/Icon-192.png differ diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/example/web/icons/Icon-512.png differ diff --git a/example/web/index.html b/example/web/index.html new file mode 100644 index 00000000..1460b5e9 --- /dev/null +++ b/example/web/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + + + diff --git a/example/web/manifest.json b/example/web/manifest.json new file mode 100644 index 00000000..8c012917 --- /dev/null +++ b/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/example/windows/.gitignore b/example/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/example/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/example/windows/CMakeLists.txt b/example/windows/CMakeLists.txt new file mode 100644 index 00000000..abf90408 --- /dev/null +++ b/example/windows/CMakeLists.txt @@ -0,0 +1,95 @@ +cmake_minimum_required(VERSION 3.15) +project(example LANGUAGES CXX) + +set(BINARY_NAME "example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() + +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build +add_subdirectory("runner") + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/example/windows/flutter/CMakeLists.txt b/example/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..b02c5485 --- /dev/null +++ b/example/windows/flutter/CMakeLists.txt @@ -0,0 +1,103 @@ +cmake_minimum_required(VERSION 3.15) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..4bfa0f3a --- /dev/null +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,9 @@ +// +// Generated file. Do not edit. +// + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/example/windows/flutter/generated_plugin_registrant.h b/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..9846246b --- /dev/null +++ b/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..4d10c251 --- /dev/null +++ b/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,15 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/example/windows/runner/CMakeLists.txt b/example/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..977e38b5 --- /dev/null +++ b/example/windows/runner/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.15) +project(runner LANGUAGES CXX) + +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "run_loop.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) +apply_standard_settings(${BINARY_NAME}) +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/example/windows/runner/Runner.rc b/example/windows/runner/Runner.rc new file mode 100644 index 00000000..ad519398 --- /dev/null +++ b/example/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef FLUTTER_BUILD_NUMBER +#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#else +#define VERSION_AS_NUMBER 1,0,0 +#endif + +#ifdef FLUTTER_BUILD_NAME +#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "io.apparence" "\0" + VALUE "FileDescription", "A new Flutter project." "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2021 io.apparence. All rights reserved." "\0" + VALUE "OriginalFilename", "example.exe" "\0" + VALUE "ProductName", "example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/example/windows/runner/flutter_window.cpp b/example/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..c4227230 --- /dev/null +++ b/example/windows/runner/flutter_window.cpp @@ -0,0 +1,64 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(RunLoop* run_loop, + const flutter::DartProject& project) + : run_loop_(run_loop), project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opporutunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/example/windows/runner/flutter_window.h b/example/windows/runner/flutter_window.h new file mode 100644 index 00000000..b663ddd5 --- /dev/null +++ b/example/windows/runner/flutter_window.h @@ -0,0 +1,39 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "run_loop.h" +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow driven by the |run_loop|, hosting a + // Flutter view running |project|. + explicit FlutterWindow(RunLoop* run_loop, + const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The run loop driving events for this window. + RunLoop* run_loop_; + + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/example/windows/runner/main.cpp b/example/windows/runner/main.cpp new file mode 100644 index 00000000..b637809b --- /dev/null +++ b/example/windows/runner/main.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "run_loop.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + RunLoop run_loop; + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(&run_loop, project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + run_loop.Run(); + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/example/windows/runner/resource.h b/example/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/example/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/example/windows/runner/resources/app_icon.ico b/example/windows/runner/resources/app_icon.ico new file mode 100644 index 00000000..c04e20ca Binary files /dev/null and b/example/windows/runner/resources/app_icon.ico differ diff --git a/example/windows/runner/run_loop.cpp b/example/windows/runner/run_loop.cpp new file mode 100644 index 00000000..2d6636ab --- /dev/null +++ b/example/windows/runner/run_loop.cpp @@ -0,0 +1,66 @@ +#include "run_loop.h" + +#include + +#include + +RunLoop::RunLoop() {} + +RunLoop::~RunLoop() {} + +void RunLoop::Run() { + bool keep_running = true; + TimePoint next_flutter_event_time = TimePoint::clock::now(); + while (keep_running) { + std::chrono::nanoseconds wait_duration = + std::max(std::chrono::nanoseconds(0), + next_flutter_event_time - TimePoint::clock::now()); + ::MsgWaitForMultipleObjects( + 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), + QS_ALLINPUT); + bool processed_events = false; + MSG message; + // All pending Windows messages must be processed; MsgWaitForMultipleObjects + // won't return again for items left in the queue after PeekMessage. + while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { + processed_events = true; + if (message.message == WM_QUIT) { + keep_running = false; + break; + } + ::TranslateMessage(&message); + ::DispatchMessage(&message); + // Allow Flutter to process messages each time a Windows message is + // processed, to prevent starvation. + next_flutter_event_time = + std::min(next_flutter_event_time, ProcessFlutterMessages()); + } + // If the PeekMessage loop didn't run, process Flutter messages. + if (!processed_events) { + next_flutter_event_time = + std::min(next_flutter_event_time, ProcessFlutterMessages()); + } + } +} + +void RunLoop::RegisterFlutterInstance( + flutter::FlutterEngine* flutter_instance) { + flutter_instances_.insert(flutter_instance); +} + +void RunLoop::UnregisterFlutterInstance( + flutter::FlutterEngine* flutter_instance) { + flutter_instances_.erase(flutter_instance); +} + +RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { + TimePoint next_event_time = TimePoint::max(); + for (auto instance : flutter_instances_) { + std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); + if (wait_duration != std::chrono::nanoseconds::max()) { + next_event_time = + std::min(next_event_time, TimePoint::clock::now() + wait_duration); + } + } + return next_event_time; +} diff --git a/example/windows/runner/run_loop.h b/example/windows/runner/run_loop.h new file mode 100644 index 00000000..000d3624 --- /dev/null +++ b/example/windows/runner/run_loop.h @@ -0,0 +1,40 @@ +#ifndef RUNNER_RUN_LOOP_H_ +#define RUNNER_RUN_LOOP_H_ + +#include + +#include +#include + +// A runloop that will service events for Flutter instances as well +// as native messages. +class RunLoop { + public: + RunLoop(); + ~RunLoop(); + + // Prevent copying + RunLoop(RunLoop const&) = delete; + RunLoop& operator=(RunLoop const&) = delete; + + // Runs the run loop until the application quits. + void Run(); + + // Registers the given Flutter instance for event servicing. + void RegisterFlutterInstance( + flutter::FlutterEngine* flutter_instance); + + // Unregisters the given Flutter instance from event servicing. + void UnregisterFlutterInstance( + flutter::FlutterEngine* flutter_instance); + + private: + using TimePoint = std::chrono::steady_clock::time_point; + + // Processes all currently pending messages for registered Flutter instances. + TimePoint ProcessFlutterMessages(); + + std::set flutter_instances_; +}; + +#endif // RUNNER_RUN_LOOP_H_ diff --git a/example/windows/runner/runner.exe.manifest b/example/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..c977c4a4 --- /dev/null +++ b/example/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/example/windows/runner/utils.cpp b/example/windows/runner/utils.cpp new file mode 100644 index 00000000..d19bdbbc --- /dev/null +++ b/example/windows/runner/utils.cpp @@ -0,0 +1,64 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr); + if (target_length == 0) { + return std::string(); + } + std::string utf8_string; + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, utf8_string.data(), + target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/example/windows/runner/utils.h b/example/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/example/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/example/windows/runner/win32_window.cpp b/example/windows/runner/win32_window.cpp new file mode 100644 index 00000000..c10f08dc --- /dev/null +++ b/example/windows/runner/win32_window.cpp @@ -0,0 +1,245 @@ +#include "win32_window.h" + +#include + +#include "resource.h" + +namespace { + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); + } +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + return OnCreate(); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} diff --git a/example/windows/runner/win32_window.h b/example/windows/runner/win32_window.h new file mode 100644 index 00000000..17ba4311 --- /dev/null +++ b/example/windows/runner/win32_window.h @@ -0,0 +1,98 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates and shows a win32 window with |title| and position and size using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size to will treat the width height passed in to this function + // as logical pixels and scale to appropriate for the default monitor. Returns + // true if the window was created successfully. + bool CreateAndShow(const std::wstring& title, + const Point& origin, + const Size& size); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responsponds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/lib/generated/i18n.dart b/lib/generated/i18n.dart index 30fdb7a4..7f9b4d58 100644 --- a/lib/generated/i18n.dart +++ b/lib/generated/i18n.dart @@ -11,12 +11,12 @@ import 'package:flutter/material.dart'; class S implements WidgetsLocalizations { const S(); - static S current; + static S? current; static const GeneratedLocalizationsDelegate delegate = GeneratedLocalizationsDelegate(); - static S of(BuildContext context) => Localizations.of(context, S); + static S? of(BuildContext context) => Localizations.of(context, S); @override TextDirection get textDirection => TextDirection.ltr; @@ -27,7 +27,7 @@ class $en extends S { const $en(); } -class GeneratedLocalizationsDelegate extends LocalizationsDelegate { +class GeneratedLocalizationsDelegate extends LocalizationsDelegate { const GeneratedLocalizationsDelegate(); List get supportedLocales { @@ -36,8 +36,8 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { ]; } - LocaleListResolutionCallback listResolution({Locale fallback, bool withCountry = true}) { - return (List locales, Iterable supported) { + LocaleListResolutionCallback listResolution({Locale? fallback, bool withCountry = true}) { + return (List? locales, Iterable supported) { if (locales == null || locales.isEmpty) { return fallback ?? supported.first; } else { @@ -46,26 +46,26 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { }; } - LocaleResolutionCallback resolution({Locale fallback, bool withCountry = true}) { - return (Locale locale, Iterable supported) { + LocaleResolutionCallback resolution({Locale? fallback, bool withCountry = true}) { + return (Locale? locale, Iterable supported) { return _resolve(locale, fallback, supported, withCountry); }; } @override - Future load(Locale locale) { + Future load(Locale locale) { final String lang = getLang(locale); if (lang != null) { switch (lang) { case "en": S.current = const $en(); - return SynchronousFuture(S.current); + return SynchronousFuture(S.current); default: // NO-OP. } } S.current = const S(); - return SynchronousFuture(S.current); + return SynchronousFuture(S.current); } @override @@ -77,7 +77,7 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { /// /// Internal method to resolve a locale from a list of locales. /// - Locale _resolve(Locale locale, Locale fallback, Iterable supported, bool withCountry) { + Locale _resolve(Locale? locale, Locale? fallback, Iterable supported, bool withCountry) { if (locale == null || !_isSupported(locale, withCountry)) { return fallback ?? supported.first; } @@ -110,7 +110,7 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { } // If no country requirement is requested, check if this locale has no country. - if (true != withCountry && (supportedLocale.countryCode == null || supportedLocale.countryCode.isEmpty)) { + if (true != withCountry && (supportedLocale.countryCode == null || supportedLocale.countryCode!.isEmpty)) { return true; } } @@ -119,8 +119,5 @@ class GeneratedLocalizationsDelegate extends LocalizationsDelegate { } } -String getLang(Locale l) => l == null - ? null - : l.countryCode != null && l.countryCode.isEmpty - ? l.languageCode - : l.toString(); +String getLang(Locale? l) => l?.countryCode != null && l!.countryCode!.isEmpty + ? l.languageCode : l.toString(); diff --git a/lib/src/database/adapter/app_icon_entity.dart b/lib/src/database/adapter/app_icon_entity.dart index e9445f5a..9aba1dd3 100644 --- a/lib/src/database/adapter/app_icon_entity.dart +++ b/lib/src/database/adapter/app_icon_entity.dart @@ -3,9 +3,9 @@ import 'generic_adapter.dart'; class AppIconEntityAdapter extends GenericEntityAdapter { @override - AppIconEntity parseMap(Map map) { + AppIconEntity parseMap(Map? map) { return AppIconEntity( - id: map['id'], + id: map!['id'], url: map['url'], ); } diff --git a/lib/src/database/adapter/generic_adapter.dart b/lib/src/database/adapter/generic_adapter.dart index fedc0bec..5356dc02 100644 --- a/lib/src/database/adapter/generic_adapter.dart +++ b/lib/src/database/adapter/generic_adapter.dart @@ -11,7 +11,7 @@ abstract class GenericEntityAdapter { String toJson(T model) => json.encode(model); T parse(String value) { - Map map = json.decode(value); + Map? map = json.decode(value); try { return parseMap(map); } catch (e) { @@ -46,11 +46,11 @@ abstract class GenericEntityAdapter { result.entities = this.parseArray(json.encode(page['content'])); return result; } catch (err) { - throw "Error while parsing data " + err; + throw "Error while parsing data $err"; } } - Map decode(String value) { + Map? decode(String value) { return json.decode(value); } @@ -58,7 +58,7 @@ abstract class GenericEntityAdapter { return json.encode(object); } - T parseMap(Map map); + T parseMap(Map? map); static checkKey(Map map, String key) { return map.containsKey(key) && map[key] != null && map[key] != ''; diff --git a/lib/src/database/adapter/helper_entity_adapter.dart b/lib/src/database/adapter/helper_entity_adapter.dart index 8b9204ef..4ebcb66a 100644 --- a/lib/src/database/adapter/helper_entity_adapter.dart +++ b/lib/src/database/adapter/helper_entity_adapter.dart @@ -4,8 +4,8 @@ import 'package:pal/src/database/entity/helper/helper_type.dart'; class HelperEntityAdapter extends GenericEntityAdapter { @override - HelperEntity parseMap(Map map) { - final HelperType helperType = map.containsKey('type') ? getHelperType(map['type']) : null; + HelperEntity parseMap(Map? map) { + final HelperType? helperType = map!.containsKey('type') ? getHelperType(map['type']) : null; return HelperEntity( id: map['id'], name: map['name'], @@ -27,9 +27,9 @@ class HelperEntityAdapter extends GenericEntityAdapter { class HelperBorderEntityAdapter extends GenericEntityAdapter { @override - HelperBorderEntity parseMap(Map map) { + HelperBorderEntity parseMap(Map? map) { return HelperBorderEntity( - id: map['id'], + id: map!['id'], key: map['key'], color: map['color'], style: map['style'], @@ -40,9 +40,9 @@ class HelperBorderEntityAdapter extends GenericEntityAdapter class HelperImageEntityAdapter extends GenericEntityAdapter { @override - HelperImageEntity parseMap(Map map) { + HelperImageEntity parseMap(Map? map) { return HelperImageEntity( - id: map['id'], + id: map!['id'], key: map['key'], url: map['url'], ); @@ -51,9 +51,9 @@ class HelperImageEntityAdapter extends GenericEntityAdapter { class HelperTextEntityAdapter extends GenericEntityAdapter { @override - HelperTextEntity parseMap(Map map) { + HelperTextEntity parseMap(Map? map) { return HelperTextEntity( - id: map['id'], + id: map!['id'], fontColor: map['fontColor'], fontFamily: map['fontFamily'], fontWeight: map['fontWeight'], @@ -66,9 +66,9 @@ class HelperTextEntityAdapter extends GenericEntityAdapter { class HelperBoxEntityAdapter extends GenericEntityAdapter { @override - HelperBoxEntity parseMap(Map map) { + HelperBoxEntity parseMap(Map? map) { return HelperBoxEntity( - id: map['id'], + id: map!['id'], key: map['key'], backgroundColor: map['backgroundColor'], ); diff --git a/lib/src/database/adapter/helper_group_entity_adapter.dart b/lib/src/database/adapter/helper_group_entity_adapter.dart index b70754e1..67f4cbeb 100644 --- a/lib/src/database/adapter/helper_group_entity_adapter.dart +++ b/lib/src/database/adapter/helper_group_entity_adapter.dart @@ -8,8 +8,8 @@ import 'generic_adapter.dart'; class HelperGroupEntityAdapter extends GenericEntityAdapter { @override - HelperGroupEntity parseMap(Map map) { - final HelperTriggerType helperTriggerType = map.containsKey('triggerType') + HelperGroupEntity parseMap(Map? map) { + final HelperTriggerType? helperTriggerType = map!.containsKey('triggerType') ? getHelperTriggerType(map['triggerType']) : null; return HelperGroupEntity( id: map['id'], diff --git a/lib/src/database/adapter/helper_group_visit_entity_adapter.dart b/lib/src/database/adapter/helper_group_visit_entity_adapter.dart index 14f3fcfb..aa44bb60 100644 --- a/lib/src/database/adapter/helper_group_visit_entity_adapter.dart +++ b/lib/src/database/adapter/helper_group_visit_entity_adapter.dart @@ -4,9 +4,9 @@ import 'generic_adapter.dart'; class HelperGroupUserVisitEntityAdapter extends GenericEntityAdapter { @override - HelperGroupUserVisitEntity parseMap(Map map) { + HelperGroupUserVisitEntity parseMap(Map? map) { return HelperGroupUserVisitEntity( - helperGroupId: map["helperGroupId"], + helperGroupId: map!["helperGroupId"], pageId: map["pageId"], visitDate: DateTime.parse(map['time']).toLocal() , visitVersion: map["version"], diff --git a/lib/src/database/adapter/in_app_user_storage_adapter.dart b/lib/src/database/adapter/in_app_user_storage_adapter.dart index 18a9723e..fb2fc147 100644 --- a/lib/src/database/adapter/in_app_user_storage_adapter.dart +++ b/lib/src/database/adapter/in_app_user_storage_adapter.dart @@ -1,11 +1,11 @@ import 'package:pal/src/database/adapter/generic_adapter.dart'; import 'package:pal/src/database/entity/in_app_user_entity.dart'; -class InAppUserEntityAdapter extends GenericEntityAdapter { +class InAppUserEntityStorageAdapter extends GenericEntityAdapter { @override - InAppUserEntity parseMap(Map map) { + InAppUserEntity parseMap(Map? map) { return InAppUserEntity( - id: map["id"], + id: map!["id"], inAppId: map["inAppId"], anonymous: map["anonymous"], disabledHelpers: map["disabledHelpers"], diff --git a/lib/src/database/adapter/page_entity_adapter.dart b/lib/src/database/adapter/page_entity_adapter.dart index e26e1ff7..06ddb4cd 100644 --- a/lib/src/database/adapter/page_entity_adapter.dart +++ b/lib/src/database/adapter/page_entity_adapter.dart @@ -3,9 +3,9 @@ import 'package:pal/src/database/entity/page_entity.dart'; class PageEntityAdapter extends GenericEntityAdapter { @override - PageEntity parseMap(Map map) { + PageEntity parseMap(Map? map) { return PageEntity( - id: map['id'], + id: map!['id'], creationDate: map['creationDate'] != null ? DateTime.parse(map['creationDate']).toLocal() : null, lastUpdateDate: map['lastUpdateDate'] != null ? DateTime.parse(map['lastUpdateDate']).toLocal() : null, route: map['route'], diff --git a/lib/src/database/adapter/project_gallery_entity_adapter.dart b/lib/src/database/adapter/project_gallery_entity_adapter.dart index e9f766b0..54185c82 100644 --- a/lib/src/database/adapter/project_gallery_entity_adapter.dart +++ b/lib/src/database/adapter/project_gallery_entity_adapter.dart @@ -3,9 +3,9 @@ import 'generic_adapter.dart'; class ProjectGalleryEntityAdapter extends GenericEntityAdapter { @override - GraphicEntity parseMap(Map map) { + GraphicEntity parseMap(Map? map) { return GraphicEntity( - id: map['id'], + id: map!['id'], url: map['url'], uploadedDate: DateTime.parse(map['uploadedDate']).toLocal(), ); diff --git a/lib/src/database/adapter/schema_entity_adapter.dart b/lib/src/database/adapter/schema_entity_adapter.dart index 06403b9f..cfc36148 100644 --- a/lib/src/database/adapter/schema_entity_adapter.dart +++ b/lib/src/database/adapter/schema_entity_adapter.dart @@ -6,9 +6,9 @@ import 'generic_adapter.dart'; class SchemaEntityAdapter extends GenericEntityAdapter { @override - SchemaEntity parseMap(Map map) { + SchemaEntity parseMap(Map? map) { return SchemaEntity( - projectId: map['projectId'], + projectId: map!['projectId'], groups: new HelperGroupEntityAdapter().parseDynamicArray(map['groups']), schemaVersion: map['schemaVersion'], ); diff --git a/lib/src/database/adapter/version_entity_adapter.dart b/lib/src/database/adapter/version_entity_adapter.dart index ab2bdd33..e3d2f811 100644 --- a/lib/src/database/adapter/version_entity_adapter.dart +++ b/lib/src/database/adapter/version_entity_adapter.dart @@ -4,9 +4,9 @@ import 'generic_adapter.dart'; class VersionEntityAdapter extends GenericEntityAdapter { @override - VersionEntity parseMap(Map map) { + VersionEntity parseMap(Map? map) { return VersionEntity( - id: map['id'], + id: map!['id'], name: map['name'] ); } diff --git a/lib/src/database/entity/app_icon_entity.dart b/lib/src/database/entity/app_icon_entity.dart index 466f476f..af8e090c 100644 --- a/lib/src/database/entity/app_icon_entity.dart +++ b/lib/src/database/entity/app_icon_entity.dart @@ -1,6 +1,6 @@ class AppIconEntity { - String id; - String url; + String? id; + String? url; AppIconEntity({ this.id, diff --git a/lib/src/database/entity/graphic_entity.dart b/lib/src/database/entity/graphic_entity.dart index 8e93689e..8f4f760b 100644 --- a/lib/src/database/entity/graphic_entity.dart +++ b/lib/src/database/entity/graphic_entity.dart @@ -1,7 +1,7 @@ class GraphicEntity { - String id; - String url; - DateTime uploadedDate; + String? id; + String? url; + DateTime? uploadedDate; GraphicEntity({ this.id, diff --git a/lib/src/database/entity/helper/helper_entity.dart b/lib/src/database/entity/helper/helper_entity.dart index d8fe68e5..12b16431 100644 --- a/lib/src/database/entity/helper/helper_entity.dart +++ b/lib/src/database/entity/helper/helper_entity.dart @@ -8,37 +8,37 @@ part 'helper_entity.g.dart'; @HiveType(typeId: 3) class HelperEntity with Comparable { @HiveField(0) - String id; + String? id; @HiveField(1) - DateTime creationDate; + DateTime? creationDate; @HiveField(2) - DateTime lastUpdateDate; + DateTime? lastUpdateDate; @HiveField(3) - String name; + String? name; @HiveField(4) - int priority; + int? priority; @HiveField(5) - HelperType type; + HelperType? type; @HiveField(6) - HelperTriggerType triggerType; + HelperTriggerType? triggerType; @HiveField(11) - List helperBorders; + List? helperBorders; @HiveField(12) - List helperImages; + List? helperImages; @HiveField(13) - List helperTexts; + List? helperTexts; @HiveField(14) - List helperBoxes; + List? helperBoxes; HelperEntity( {this.id, @@ -63,21 +63,21 @@ class HelperEntity with Comparable { lastUpdateDate: from.lastUpdateDate, priority: from.priority, helperBorders: - from.helperBorders != null ? [...from.helperBorders] : null, - helperImages: from.helperImages != null ? [...from.helperImages] : null, - helperTexts: from.helperTexts != null ? [...from.helperTexts] : null, - helperBoxes: from.helperBoxes != null ? [...from.helperBoxes] : null, + from.helperBorders != null ? [...from.helperBorders!] : null, + helperImages: from.helperImages != null ? [...from.helperImages!] : null, + helperTexts: from.helperTexts != null ? [...from.helperTexts!] : null, + helperBoxes: from.helperBoxes != null ? [...from.helperBoxes!] : null, ); } Map toJson() => { 'id': id, 'name': name, - 'type': type?.toString()?.split('.')[1], + 'type': type?.toString().split('.')[1], 'creationDate': - creationDate != null ? creationDate.toIso8601String() : null, + creationDate != null ? creationDate!.toIso8601String() : null, 'lastUpdateDate': - lastUpdateDate != null ? lastUpdateDate.toIso8601String() : null, + lastUpdateDate != null ? lastUpdateDate!.toIso8601String() : null, 'priority': priority, 'helperBorders': helperBorders, 'helperImages': helperImages, @@ -104,7 +104,7 @@ class HelperEntity with Comparable { @override int compareTo(HelperEntity other) { return other != null && this != null - ? other.priority < this.priority + ? other.priority! < this.priority! ? 1 : -1 : 0; @@ -127,19 +127,19 @@ class HelperEntity with Comparable { @HiveType(typeId: 4) class HelperBorderEntity { @HiveField(0) - int id; + int? id; @HiveField(1) - String color; + String? color; @HiveField(2) - String key; + String? key; @HiveField(3) - String style; + String? style; @HiveField(4) - double width; + double? width; HelperBorderEntity({this.id, this.color, this.key, this.style, this.width}); @@ -181,13 +181,13 @@ class HelperBorderEntity { @HiveType(typeId: 5) class HelperImageEntity { @HiveField(0) - int id; + int? id; @HiveField(1) - String key; + String? key; @HiveField(2) - String url; + String? url; Map toJson() => { 'id': id, @@ -195,7 +195,7 @@ class HelperImageEntity { 'url': url, }; - HelperImageEntity({this.id, this.key, @required this.url}); + HelperImageEntity({this.id, this.key, required this.url}); HelperImageEntity copy() => HelperImageEntity(id: id, key: key, url: url); @@ -214,25 +214,25 @@ class HelperImageEntity { @HiveType(typeId: 6) class HelperTextEntity { @HiveField(0) - int id; + int? id; @HiveField(1) - String fontColor; + String? fontColor; @HiveField(2) - String fontFamily; + String? fontFamily; @HiveField(3) - String fontWeight; + String? fontWeight; @HiveField(4) - String key; + String? key; @HiveField(5) - String value; + String? value; @HiveField(6) - int fontSize; + int? fontSize; HelperTextEntity({ this.id, @@ -289,17 +289,17 @@ class HelperTextEntity { @HiveType(typeId: 7) class HelperBoxEntity { @HiveField(0) - int id; + int? id; @HiveField(1) - String backgroundColor; + String? backgroundColor; @HiveField(2) - String key; + String? key; HelperBoxEntity({ this.id, - @required this.backgroundColor, + required this.backgroundColor, this.key, }); diff --git a/lib/src/database/entity/helper/helper_entity.g.dart b/lib/src/database/entity/helper/helper_entity.g.dart index 6a44894b..8610fbc9 100644 --- a/lib/src/database/entity/helper/helper_entity.g.dart +++ b/lib/src/database/entity/helper/helper_entity.g.dart @@ -17,17 +17,17 @@ class HelperEntityAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return HelperEntity( - id: fields[0] as String, - name: fields[3] as String, - type: fields[5] as HelperType, - triggerType: fields[6] as HelperTriggerType, - creationDate: fields[1] as DateTime, - lastUpdateDate: fields[2] as DateTime, - priority: fields[4] as int, - helperBorders: (fields[11] as List)?.cast(), - helperImages: (fields[12] as List)?.cast(), - helperTexts: (fields[13] as List)?.cast(), - helperBoxes: (fields[14] as List)?.cast(), + id: fields[0] as String?, + name: fields[3] as String?, + type: fields[5] as HelperType?, + triggerType: fields[6] as HelperTriggerType?, + creationDate: fields[1] as DateTime?, + lastUpdateDate: fields[2] as DateTime?, + priority: fields[4] as int?, + helperBorders: (fields[11] as List?)?.cast(), + helperImages: (fields[12] as List?)?.cast(), + helperTexts: (fields[13] as List?)?.cast(), + helperBoxes: (fields[14] as List?)?.cast(), ); } @@ -81,11 +81,11 @@ class HelperBorderEntityAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return HelperBorderEntity( - id: fields[0] as int, - color: fields[1] as String, - key: fields[2] as String, - style: fields[3] as String, - width: fields[4] as double, + id: fields[0] as int?, + color: fields[1] as String?, + key: fields[2] as String?, + style: fields[3] as String?, + width: fields[4] as double?, ); } @@ -127,9 +127,9 @@ class HelperImageEntityAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return HelperImageEntity( - id: fields[0] as int, - key: fields[1] as String, - url: fields[2] as String, + id: fields[0] as int?, + key: fields[1] as String?, + url: fields[2] as String?, ); } @@ -167,13 +167,13 @@ class HelperTextEntityAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return HelperTextEntity( - id: fields[0] as int, - fontColor: fields[1] as String, - fontFamily: fields[2] as String, - fontWeight: fields[3] as String, - key: fields[4] as String, - value: fields[5] as String, - fontSize: fields[6] as int, + id: fields[0] as int?, + fontColor: fields[1] as String?, + fontFamily: fields[2] as String?, + fontWeight: fields[3] as String?, + key: fields[4] as String?, + value: fields[5] as String?, + fontSize: fields[6] as int?, ); } @@ -219,9 +219,9 @@ class HelperBoxEntityAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return HelperBoxEntity( - id: fields[0] as int, - backgroundColor: fields[1] as String, - key: fields[2] as String, + id: fields[0] as int?, + backgroundColor: fields[1] as String?, + key: fields[2] as String?, ); } diff --git a/lib/src/database/entity/helper/helper_group_entity.dart b/lib/src/database/entity/helper/helper_group_entity.dart index 32af80a7..96a9bd59 100644 --- a/lib/src/database/entity/helper/helper_group_entity.dart +++ b/lib/src/database/entity/helper/helper_group_entity.dart @@ -12,31 +12,31 @@ part 'helper_group_entity.g.dart'; class HelperGroupEntity with Comparable { @HiveField(0) - String id; + String? id; @HiveField(1) - int priority; + int? priority; @HiveField(2) - List helpers; + List? helpers; @HiveField(3) - PageEntity page; + PageEntity? page; @HiveField(4) - String name; + String? name; @HiveField(5) - HelperTriggerType triggerType; + HelperTriggerType? triggerType; @HiveField(6) - DateTime creationDate; + DateTime? creationDate; @HiveField(7) - String minVersion; + String? minVersion; @HiveField(8) - String maxVersion; + String? maxVersion; HelperGroupEntity({ this.id, @@ -53,7 +53,7 @@ class HelperGroupEntity with Comparable { @override int compareTo(HelperGroupEntity other) { if(other.triggerType == this.triggerType) { - return other.priority < this.priority ? 1 : -1; + return other.priority! < this.priority! ? 1 : -1; } return other.triggerType.typePriority < this.triggerType.typePriority ? 1 : -1; } diff --git a/lib/src/database/entity/helper/helper_group_entity.g.dart b/lib/src/database/entity/helper/helper_group_entity.g.dart index dc184bcc..efe9491f 100644 --- a/lib/src/database/entity/helper/helper_group_entity.g.dart +++ b/lib/src/database/entity/helper/helper_group_entity.g.dart @@ -17,15 +17,15 @@ class HelperGroupEntityAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return HelperGroupEntity( - id: fields[0] as String, - priority: fields[1] as int, - helpers: (fields[2] as List)?.cast(), - page: fields[3] as PageEntity, - name: fields[4] as String, - triggerType: fields[5] as HelperTriggerType, - creationDate: fields[6] as DateTime, - minVersion: fields[7] as String, - maxVersion: fields[8] as String, + id: fields[0] as String?, + priority: fields[1] as int?, + helpers: (fields[2] as List?)?.cast(), + page: fields[3] as PageEntity?, + name: fields[4] as String?, + triggerType: fields[5] as HelperTriggerType?, + creationDate: fields[6] as DateTime?, + minVersion: fields[7] as String?, + maxVersion: fields[8] as String?, ); } diff --git a/lib/src/database/entity/helper/helper_trigger_type.dart b/lib/src/database/entity/helper/helper_trigger_type.dart index b7ff39e3..6f82d38d 100644 --- a/lib/src/database/entity/helper/helper_trigger_type.dart +++ b/lib/src/database/entity/helper/helper_trigger_type.dart @@ -11,14 +11,14 @@ enum HelperTriggerType { ON_NEW_UPDATE, } -HelperTriggerType getHelperTriggerType(final String value) => +HelperTriggerType getHelperTriggerType(final String? value) => HelperTriggerType.values .firstWhere((element) => element.toString().split('.')[1] == value); -String helperTriggerTypeToString(final HelperTriggerType helperTriggerType) => +String helperTriggerTypeToString(final HelperTriggerType? helperTriggerType) => helperTriggerType.toString().split('.')[1]; -extension HelperTriggerTypeExt on HelperTriggerType { +extension HelperTriggerTypeExt on HelperTriggerType? { String get description { switch (this) { case HelperTriggerType.ON_SCREEN_VISIT: @@ -41,9 +41,9 @@ extension HelperTriggerTypeExt on HelperTriggerType { } // FIXME replace by extension -String getHelperTriggerTypeDescription( +String? getHelperTriggerTypeDescription( final HelperTriggerType helperTriggerType) { - String description; + String? description; switch (helperTriggerType) { case HelperTriggerType.ON_SCREEN_VISIT: description = 'On screen visit'; diff --git a/lib/src/database/entity/helper/helper_trigger_type.g.dart b/lib/src/database/entity/helper/helper_trigger_type.g.dart index a581f7db..6b2fad82 100644 --- a/lib/src/database/entity/helper/helper_trigger_type.g.dart +++ b/lib/src/database/entity/helper/helper_trigger_type.g.dart @@ -18,7 +18,7 @@ class HelperTriggerTypeAdapter extends TypeAdapter { case 1: return HelperTriggerType.ON_NEW_UPDATE; default: - return null; + return HelperTriggerType.ON_SCREEN_VISIT; } } diff --git a/lib/src/database/entity/helper/helper_type.dart b/lib/src/database/entity/helper/helper_type.dart index bff2c4a4..6c18b91e 100644 --- a/lib/src/database/entity/helper/helper_type.dart +++ b/lib/src/database/entity/helper/helper_type.dart @@ -18,7 +18,7 @@ enum HelperType { UPDATE_HELPER, } -HelperType getHelperType(final String value) { +HelperType getHelperType(final String? value) { return HelperType.values .firstWhere((element) => element.toString().split('.')[1] == value); } @@ -27,8 +27,8 @@ String helperTypeToString(final HelperType helperType) { return helperType.toString().split('.')[1]; } -String helperTypeToAsset(final HelperType helperType) { - String asset; +String? helperTypeToAsset(final HelperType? helperType) { + String? asset; switch (helperType) { case HelperType.HELPER_FULL_SCREEN: asset = 'helper_type_fullscreen.png'; @@ -47,8 +47,8 @@ String helperTypeToAsset(final HelperType helperType) { return asset; } -String getHelperTypeDescription(final HelperType helperType) { - String description; +String? getHelperTypeDescription(final HelperType? helperType) { + String? description; switch (helperType) { case HelperType.HELPER_FULL_SCREEN: description = 'Fullscreen'; diff --git a/lib/src/database/entity/helper/helper_type.g.dart b/lib/src/database/entity/helper/helper_type.g.dart index 2a726740..bad72ab6 100644 --- a/lib/src/database/entity/helper/helper_type.g.dart +++ b/lib/src/database/entity/helper/helper_type.g.dart @@ -22,7 +22,7 @@ class HelperTypeAdapter extends TypeAdapter { case 3: return HelperType.UPDATE_HELPER; default: - return null; + return HelperType.HELPER_FULL_SCREEN; } } diff --git a/lib/src/database/entity/helper/schema_entity.dart b/lib/src/database/entity/helper/schema_entity.dart index 98855773..9831ba63 100644 --- a/lib/src/database/entity/helper/schema_entity.dart +++ b/lib/src/database/entity/helper/schema_entity.dart @@ -8,13 +8,13 @@ part 'schema_entity.g.dart'; class SchemaEntity { @HiveField(0) - String projectId; + String? projectId; @HiveField(1) - List groups; + List? groups; @HiveField(2) - int schemaVersion; + int? schemaVersion; SchemaEntity({this.projectId, this.groups, this.schemaVersion}); } \ No newline at end of file diff --git a/lib/src/database/entity/helper/schema_entity.g.dart b/lib/src/database/entity/helper/schema_entity.g.dart index ace51c59..0089f4a1 100644 --- a/lib/src/database/entity/helper/schema_entity.g.dart +++ b/lib/src/database/entity/helper/schema_entity.g.dart @@ -17,9 +17,9 @@ class SchemaEntityAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return SchemaEntity( - projectId: fields[0] as String, - groups: (fields[1] as List)?.cast(), - schemaVersion: fields[2] as int, + projectId: fields[0] as String?, + groups: (fields[1] as List?)?.cast(), + schemaVersion: fields[2] as int?, ); } diff --git a/lib/src/database/entity/in_app_user_entity.dart b/lib/src/database/entity/in_app_user_entity.dart index 1947455c..3b2da1bb 100644 --- a/lib/src/database/entity/in_app_user_entity.dart +++ b/lib/src/database/entity/in_app_user_entity.dart @@ -1,8 +1,17 @@ +import 'package:hive/hive.dart'; + +part 'in_app_user_entity.g.dart'; + +@HiveType(typeId: 12) class InAppUserEntity { - String id; - String inAppId; - bool disabledHelpers; - bool anonymous; + @HiveField(0) + String? id; + @HiveField(1) + String? inAppId; + @HiveField(2) + bool? disabledHelpers; + @HiveField(3) + bool? anonymous; InAppUserEntity( {this.id, this.inAppId, this.disabledHelpers, this.anonymous}); diff --git a/lib/src/database/entity/in_app_user_entity.g.dart b/lib/src/database/entity/in_app_user_entity.g.dart new file mode 100644 index 00000000..9bdee99a --- /dev/null +++ b/lib/src/database/entity/in_app_user_entity.g.dart @@ -0,0 +1,50 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'in_app_user_entity.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class InAppUserEntityAdapter extends TypeAdapter { + @override + final int typeId = 12; + + @override + InAppUserEntity read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return InAppUserEntity( + id: fields[0] as String?, + inAppId: fields[1] as String?, + disabledHelpers: fields[2] as bool?, + anonymous: fields[3] as bool?, + ); + } + + @override + void write(BinaryWriter writer, InAppUserEntity obj) { + writer + ..writeByte(4) + ..writeByte(0) + ..write(obj.id) + ..writeByte(1) + ..write(obj.inAppId) + ..writeByte(2) + ..write(obj.disabledHelpers) + ..writeByte(3) + ..write(obj.anonymous); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is InAppUserEntityAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/src/database/entity/page_entity.dart b/lib/src/database/entity/page_entity.dart index da7be535..cec72abe 100644 --- a/lib/src/database/entity/page_entity.dart +++ b/lib/src/database/entity/page_entity.dart @@ -6,16 +6,16 @@ part 'page_entity.g.dart'; class PageEntity { @HiveField(0) - String id; + String? id; @HiveField(1) - DateTime creationDate; + DateTime? creationDate; @HiveField(2) - DateTime lastUpdateDate; + DateTime? lastUpdateDate; @HiveField(3) - String route; + String? route; PageEntity({ this.id, @@ -26,8 +26,8 @@ class PageEntity { Map toJson() => { 'id': id ?? "", - 'creationDate': creationDate != null ? creationDate.toIso8601String() : null, - 'lastUpdateDate': lastUpdateDate != null ? lastUpdateDate.toIso8601String() : null, + 'creationDate': creationDate != null ? creationDate!.toIso8601String() : null, + 'lastUpdateDate': lastUpdateDate != null ? lastUpdateDate!.toIso8601String() : null, 'route': route }; } diff --git a/lib/src/database/entity/page_entity.g.dart b/lib/src/database/entity/page_entity.g.dart index 09ff1dfa..fd8d1615 100644 --- a/lib/src/database/entity/page_entity.g.dart +++ b/lib/src/database/entity/page_entity.g.dart @@ -17,10 +17,10 @@ class PageEntityAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return PageEntity( - id: fields[0] as String, - creationDate: fields[1] as DateTime, - lastUpdateDate: fields[2] as DateTime, - route: fields[3] as String, + id: fields[0] as String?, + creationDate: fields[1] as DateTime?, + lastUpdateDate: fields[2] as DateTime?, + route: fields[3] as String?, ); } diff --git a/lib/src/database/entity/page_user_visit_entity.dart b/lib/src/database/entity/page_user_visit_entity.dart index 092b5b71..95d6a10f 100644 --- a/lib/src/database/entity/page_user_visit_entity.dart +++ b/lib/src/database/entity/page_user_visit_entity.dart @@ -7,20 +7,20 @@ part 'page_user_visit_entity.g.dart'; class HelperGroupUserVisitEntity { @HiveField(0) - String pageId; + String? pageId; @HiveField(1) - String helperGroupId; + String? helperGroupId; @HiveField(2) - DateTime visitDate; + DateTime? visitDate; @HiveField(3) - String visitVersion; + String? visitVersion; HelperGroupUserVisitEntity({ - @required this.pageId, - @required this.helperGroupId, - @required this.visitDate, - @required this.visitVersion}); + required this.pageId, + required this.helperGroupId, + required this.visitDate, + required this.visitVersion}); } \ No newline at end of file diff --git a/lib/src/database/entity/page_user_visit_entity.g.dart b/lib/src/database/entity/page_user_visit_entity.g.dart index e0508961..baf0148d 100644 --- a/lib/src/database/entity/page_user_visit_entity.g.dart +++ b/lib/src/database/entity/page_user_visit_entity.g.dart @@ -18,10 +18,10 @@ class HelperGroupUserVisitEntityAdapter for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return HelperGroupUserVisitEntity( - pageId: fields[0] as String, - helperGroupId: fields[1] as String, - visitDate: fields[2] as DateTime, - visitVersion: fields[3] as String, + pageId: fields[0] as String?, + helperGroupId: fields[1] as String?, + visitDate: fields[2] as DateTime?, + visitVersion: fields[3] as String?, ); } diff --git a/lib/src/database/entity/pageable.dart b/lib/src/database/entity/pageable.dart index 6ca8adc5..e21c6770 100644 --- a/lib/src/database/entity/pageable.dart +++ b/lib/src/database/entity/pageable.dart @@ -1,13 +1,13 @@ class Pageable { - int pageNumber; - int offset; - int pageSize; - int totalPages; - int totalElements; - int numberOfElements; - bool last; - bool first; - List entities; + int? pageNumber; + int? offset; + int? pageSize; + int? totalPages; + int? totalElements; + int? numberOfElements; + bool? last; + bool? first; + List? entities; Pageable({ this.pageNumber, diff --git a/lib/src/database/entity/version_entity.dart b/lib/src/database/entity/version_entity.dart index e8ed2c00..d9f01ecc 100644 --- a/lib/src/database/entity/version_entity.dart +++ b/lib/src/database/entity/version_entity.dart @@ -1,7 +1,7 @@ /// User Application version class VersionEntity { - int id; - String name; + int? id; + String? name; VersionEntity({this.id, this.name}); diff --git a/lib/src/database/hive_client.dart b/lib/src/database/hive_client.dart index f79eb056..d4610c39 100644 --- a/lib/src/database/hive_client.dart +++ b/lib/src/database/hive_client.dart @@ -2,13 +2,13 @@ import 'package:flutter/cupertino.dart'; import 'package:hive/hive.dart'; import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; +import 'package:pal/src/database/entity/in_app_user_entity.dart'; import 'entity/helper/helper_entity.dart'; import 'entity/helper/helper_group_entity.dart'; import 'entity/helper/helper_type.dart'; import 'entity/helper/schema_entity.dart'; import 'entity/page_user_visit_entity.dart'; import 'entity/page_entity.dart'; -import 'package:hive_flutter/hive_flutter.dart'; typedef Future> LocalDbOpener(); @@ -22,7 +22,6 @@ class HiveClient { @visibleForTesting init() async { - await Hive.initFlutter(); initAdapters(); } @@ -34,17 +33,18 @@ class HiveClient { @visibleForTesting initAdapters() { - Hive.registerAdapter(SchemaEntityAdapter()); - Hive.registerAdapter(HelperGroupEntityAdapter()); - Hive.registerAdapter(HelperEntityAdapter()); - Hive.registerAdapter(PageEntityAdapter()); - Hive.registerAdapter(HelperGroupUserVisitEntityAdapter()); - Hive.registerAdapter(HelperTypeAdapter()); - Hive.registerAdapter(HelperTriggerTypeAdapter()); - Hive.registerAdapter(HelperTextEntityAdapter()); - Hive.registerAdapter(HelperImageEntityAdapter()); - Hive.registerAdapter(HelperBorderEntityAdapter()); - Hive.registerAdapter(HelperBoxEntityAdapter()); + Hive.registerAdapter(SchemaEntityAdapter(), override: true); + Hive.registerAdapter(HelperGroupEntityAdapter(), override: true); + Hive.registerAdapter(HelperEntityAdapter(), override: true); + Hive.registerAdapter(PageEntityAdapter(), override: true); + Hive.registerAdapter(HelperGroupUserVisitEntityAdapter(), override: true); + Hive.registerAdapter(HelperTypeAdapter(), override: true); + Hive.registerAdapter(HelperTriggerTypeAdapter(), override: true); + Hive.registerAdapter(HelperTextEntityAdapter(), override: true); + Hive.registerAdapter(HelperImageEntityAdapter(), override: true); + Hive.registerAdapter(HelperBorderEntityAdapter(), override: true); + Hive.registerAdapter(HelperBoxEntityAdapter(), override: true); + Hive.registerAdapter(InAppUserEntityAdapter(), override: true); } LocalDbOpener get openSchemaBox => @@ -53,6 +53,9 @@ class HiveClient { LocalDbOpener get openVisitsBox => () => Hive.openBox('visits'); + LocalDbOpener get openInAppUserBox => + () => Hive.openBox('inAppUser'); + close() => Hive.close(); } \ No newline at end of file diff --git a/lib/src/database/repository/base_repository.dart b/lib/src/database/repository/base_repository.dart index a8fa780c..dcb20c0c 100644 --- a/lib/src/database/repository/base_repository.dart +++ b/lib/src/database/repository/base_repository.dart @@ -3,5 +3,5 @@ import 'package:pal/src/services/http_client/base_client.dart'; class BaseHttpRepository { final HttpClient httpClient; - const BaseHttpRepository({this.httpClient}); + const BaseHttpRepository({required this.httpClient}); } diff --git a/lib/src/database/repository/client/helper_repository.dart b/lib/src/database/repository/client/helper_repository.dart index 7814a228..a33022f5 100644 --- a/lib/src/database/repository/client/helper_repository.dart +++ b/lib/src/database/repository/client/helper_repository.dart @@ -11,10 +11,10 @@ class ClientHelperRepository extends BaseHttpRepository { final EntityAdapter.HelperEntityAdapter _adapter = EntityAdapter.HelperEntityAdapter(); - ClientHelperRepository({@required HttpClient httpClient}) + ClientHelperRepository({required HttpClient httpClient}) : super(httpClient: httpClient); - Future> getAllHelpers({final int version}) { + Future> getAllHelpers({final int? version}) { throw "not implemented yet"; } diff --git a/lib/src/database/repository/client/page_user_visit_repository.dart b/lib/src/database/repository/client/page_user_visit_repository.dart index 6c5226b9..bd517208 100644 --- a/lib/src/database/repository/client/page_user_visit_repository.dart +++ b/lib/src/database/repository/client/page_user_visit_repository.dart @@ -1,7 +1,6 @@ import 'dart:convert'; -import 'package:flutter/material.dart'; import 'package:http/http.dart'; import 'package:pal/src/database/adapter/helper_group_visit_entity_adapter.dart' as Adapter; import 'package:pal/src/database/entity/helper/helper_entity.dart'; @@ -14,16 +13,16 @@ import '../base_repository.dart'; abstract class HelperGroupUserVisitRepository { - Future> get(String userId, String minAppVersion); + Future> get(String? userId, String? minAppVersion); Future saveAll(List visits); Future add(HelperGroupUserVisitEntity visit, { - bool isLast, - bool feedback, - String inAppUserId, - HelperEntity helper, - String languageCode + required bool isLast, + required bool feedback, + required String inAppUserId, + required String languageCode, + required HelperEntity helper }); Future clear(); @@ -34,11 +33,11 @@ class HelperGroupUserVisitHttpRepository extends BaseHttpRepository implements H Adapter.HelperGroupUserVisitEntityAdapter _adapter = Adapter.HelperGroupUserVisitEntityAdapter(); - HelperGroupUserVisitHttpRepository({@required HttpClient httpClient}) + HelperGroupUserVisitHttpRepository({required HttpClient httpClient}) : super(httpClient: httpClient); - Future> get(String userId, String minAppVersion) async { + Future> get(String? userId, String? minAppVersion) async { final Response response = await this .httpClient .get(Uri.parse('pal-analytic/users/$userId/groups')); @@ -58,11 +57,11 @@ class HelperGroupUserVisitHttpRepository extends BaseHttpRepository implements H @override Future add(HelperGroupUserVisitEntity visit, { - @required bool isLast, - @required bool feedback, - @required String inAppUserId, - @required String languageCode, - @required HelperEntity helper + required bool isLast, + required bool feedback, + required String inAppUserId, + required String languageCode, + required HelperEntity helper }) async { var url = Uri.parse('pal-analytic/users/$inAppUserId/groups/${visit.helperGroupId}/helpers/${helper.id}'); var body = jsonEncode({ @@ -70,7 +69,7 @@ class HelperGroupUserVisitHttpRepository extends BaseHttpRepository implements H 'isLast': isLast, 'language': languageCode }); - return httpClient.post(url, body: body, headers: {"inAppUserId": inAppUserId}); + await httpClient.post(url, body: body, headers: {"inAppUserId": inAppUserId}); } } @@ -79,10 +78,10 @@ class HelperGroupUserVisitLocalRepository implements HelperGroupUserVisitReposit LocalDbOpener _hiveBoxOpener; - HelperGroupUserVisitLocalRepository({@required LocalDbOpener hiveBoxOpener}) + HelperGroupUserVisitLocalRepository({required LocalDbOpener hiveBoxOpener}) : _hiveBoxOpener = hiveBoxOpener; - Future> get(String userId, String minAppVersion) + Future> get(String? userId, String? minAppVersion) => _hiveBoxOpener().then((res) => res.values.toList()); @override @@ -94,11 +93,11 @@ class HelperGroupUserVisitLocalRepository implements HelperGroupUserVisitReposit @override Future add(HelperGroupUserVisitEntity visit, { - bool isLast, - bool feedback, - String inAppUserId, - HelperEntity helper, - String languageCode, + bool? isLast, + bool? feedback, + String? inAppUserId, + HelperEntity? helper, + String? languageCode, }) => _hiveBoxOpener().then((res) => res.add(visit)); } \ No newline at end of file diff --git a/lib/src/database/repository/client/schema_repository.dart b/lib/src/database/repository/client/schema_repository.dart index e6927723..fc7f23ea 100644 --- a/lib/src/database/repository/client/schema_repository.dart +++ b/lib/src/database/repository/client/schema_repository.dart @@ -15,7 +15,7 @@ abstract class ClientSchemaRepository { /// if [schemaVersion] is provided and repository contains a lower or equal version returns nothing /// if [language] is null, returns the default language /// if [appVersion] must be provided, current application version in user pubspec.yml - Future get({int schemaVersion, String language, String appVersion}); + Future get({int? schemaVersion, String? language, String? appVersion}); } @@ -24,11 +24,11 @@ class ClientSchemaRemoteRepository extends BaseHttpRepository implements ClientS GenericEntityAdapter _adapter = Adapter.SchemaEntityAdapter(); - ClientSchemaRemoteRepository({@required HttpClient httpClient}) + ClientSchemaRemoteRepository({required HttpClient httpClient}) : super(httpClient: httpClient); @override - Future get({int schemaVersion, String language, @required String appVersion}) async { + Future get({int? schemaVersion, String? language, String? appVersion}) async { final Response response = await this .httpClient .get(Uri.parse('pal-business/client/schema'), headers: { @@ -46,27 +46,27 @@ class ClientSchemaRemoteRepository extends BaseHttpRepository implements ClientS class ClientSchemaLocalRepository implements ClientSchemaRepository { - final LocalDbOpener _hiveBoxOpener; + final LocalDbOpener? _hiveBoxOpener; - ClientSchemaLocalRepository({ LocalDbOpener hiveBoxOpener}) + ClientSchemaLocalRepository({ LocalDbOpener? hiveBoxOpener}) : this._hiveBoxOpener = hiveBoxOpener; @override - Future get({int schemaVersion, String language, String appVersion}) async { - var _hiveBox = await _hiveBoxOpener(); + Future get({int? schemaVersion, String? language, String? appVersion}) async { + var _hiveBox = await _hiveBoxOpener!(); if(_hiveBox.isEmpty) return null; return _hiveBox.values.first; } Future save(SchemaEntity schema) async { - var _hiveBox = await _hiveBoxOpener(); + var _hiveBox = await _hiveBoxOpener!(); await _hiveBox.clear(); await _hiveBox.add(schema); } Future clear() async { - var _hiveBox = await _hiveBoxOpener(); + var _hiveBox = await _hiveBoxOpener!(); await _hiveBox.clear(); } diff --git a/lib/src/database/repository/editor/helper_editor_repository.dart b/lib/src/database/repository/editor/helper_editor_repository.dart index ba0a7b34..9eb6e3d0 100644 --- a/lib/src/database/repository/editor/helper_editor_repository.dart +++ b/lib/src/database/repository/editor/helper_editor_repository.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:io'; -import 'package:flutter/material.dart'; import 'package:http/http.dart'; import 'package:pal/src/database/adapter/helper_entity_adapter.dart' as EntityAdapter; @@ -15,31 +14,31 @@ class EditorHelperRepository extends BaseHttpRepository { EntityAdapter.HelperEntityAdapter(); EditorHelperRepository({ - @required HttpClient httpClient, + required HttpClient httpClient, }) : super(httpClient: httpClient); - Future createHelper(final String pageId, final String groupId, + Future createHelper(final String? pageId, final String? groupId, final HelperEntity createHelper) async { final payload = jsonEncode(createHelper); final Response response = await this.httpClient.post( Uri.parse('pal-business/editor/groups/$groupId/helpers'), body: payload, ); - if (response == null || response.body == null) + if (response.body.isEmpty) throw new UnknownHttpError("NO_RESULT"); return this._adapter.parse(response.body); } - Future updateHelper( - final String pageId, + Future updateHelper( + final String? pageId, final HelperEntity updatedHelper, ) async { final payload = jsonEncode(updatedHelper); final Response response = await this.httpClient.put( - Uri.parse('pal-business/editor/helpers/${updatedHelper?.id}'), + Uri.parse('pal-business/editor/helpers/${updatedHelper.id}'), body: payload); - if (response == null || response.body == null) - throw new UnknownHttpError('NO_RESULT'); + // if (response.body.isEmpty) + // throw new UnknownHttpError('NO_RESULT'); return response.body.length == 0 ? null : this._adapter.parse(response.body); @@ -52,7 +51,7 @@ class EditorHelperRepository extends BaseHttpRepository { return this._adapter.parsePage(response.body); } - Future> getGroupHelpers(String groupId) async { + Future> getGroupHelpers(String? groupId) async { final Response response = await this.httpClient.get(Uri.parse('pal-business/editor/groups/$groupId/helpers')); return this._adapter.parseArray(response.body); @@ -76,7 +75,7 @@ class EditorHelperRepository extends BaseHttpRepository { ); } - Future getHelper(String helperId) async { + Future getHelper(String? helperId) async { Response res = await this.httpClient.get(Uri.parse('pal-business/editor/helpers/$helperId')); return this._adapter.parse(res.body); diff --git a/lib/src/database/repository/editor/helper_group_repository.dart b/lib/src/database/repository/editor/helper_group_repository.dart index f768ccb5..0bc6c22e 100644 --- a/lib/src/database/repository/editor/helper_group_repository.dart +++ b/lib/src/database/repository/editor/helper_group_repository.dart @@ -12,24 +12,18 @@ import 'package:pal/src/database/adapter/helper_group_entity_adapter.dart' as GroupEntityAdapter; class EditorHelperGroupRepository extends BaseHttpRepository { - final GroupEntityAdapter.HelperGroupEntityAdapter _groupAdapter = - GroupEntityAdapter.HelperGroupEntityAdapter(); - final HelperEntityAdapter.HelperEntityAdapter _helperAdapter = - HelperEntityAdapter.HelperEntityAdapter(); + final GroupEntityAdapter.HelperGroupEntityAdapter _groupAdapter = GroupEntityAdapter.HelperGroupEntityAdapter(); + final HelperEntityAdapter.HelperEntityAdapter _helperAdapter = HelperEntityAdapter.HelperEntityAdapter(); EditorHelperGroupRepository({ - @required HttpClient httpClient, + required HttpClient httpClient, }) : super(httpClient: httpClient); - Future> listHelperGroups(String pageId) async { + Future> listHelperGroups(String? pageId) async { var response; - try { - response = await httpClient.get(Uri.parse('pal-business/editor/pages/$pageId/groups')); - if (response == null || response.body == null) - throw new UnknownHttpError("NO_RESULT"); - } catch (e) { - throw new UnknownHttpError("NETWORK ERROR $e"); - } + response = await httpClient.get(Uri.parse('pal-business/editor/pages/$pageId/groups')); + if (response == null || response.body == null) + throw new UnknownHttpError("NO_RESULT"); try { return _groupAdapter.parseArray(response.body); } catch (e) { @@ -37,8 +31,8 @@ class EditorHelperGroupRepository extends BaseHttpRepository { } } - Future create(String pageId, String name, int minVersionId, - int maxVersionId, String triggerType) async { + Future create(String? pageId, String? name, int? minVersionId, + int? maxVersionId, String? triggerType) async { var payload = jsonEncode({ "name": name, "triggerType": triggerType, @@ -46,9 +40,7 @@ class EditorHelperGroupRepository extends BaseHttpRepository { "versionMaxId": maxVersionId, }); var response = await httpClient - .post(Uri.parse('pal-business/editor/pages/$pageId/groups'), body: payload); - if (response == null || response.body == null) - throw new UnknownHttpError("NO_RESULT"); + .post(Uri.parse('pal-business/editor/pages/$pageId/groups'), body: payload); try { return _groupAdapter.parse(response.body); } catch (e) { @@ -56,11 +48,10 @@ class EditorHelperGroupRepository extends BaseHttpRepository { } } - Future> listGroupHelpers(String groupId) async { + Future> listGroupHelpers(String? groupId) async { var response; try { - response = - await httpClient.get(Uri.parse('pal-business/editor/groups/$groupId/helpers')); + response = await httpClient.get(Uri.parse('pal-business/editor/groups/$groupId/helpers')); if (response == null || response.body == null) throw new UnknownHttpError("NO_RESULT"); } catch (e) { @@ -73,7 +64,7 @@ class EditorHelperGroupRepository extends BaseHttpRepository { } } - Future getGroupDetails(String groupId) async { + Future getGroupDetails(String? groupId) async { var response; try { response = await httpClient.get(Uri.parse('pal-business/editor/groups/$groupId')); @@ -84,12 +75,13 @@ class EditorHelperGroupRepository extends BaseHttpRepository { } try { return _groupAdapter.parse(response.body); - } catch (e) { + } catch (e,stacktrace) { + debugPrintStack(stackTrace: stacktrace); throw "UNPARSABLE RESPONSE $e"; } } - Future updateGroup(String id, int maxVersionId, int minVersionId, String name, + Future updateGroup(String? id, int? maxVersionId, int? minVersionId, String? name, String type) async { var response; try { @@ -108,7 +100,7 @@ class EditorHelperGroupRepository extends BaseHttpRepository { return; } - Future deleteGroup(String groupId) async { + Future deleteGroup(String? groupId) async { try { return await httpClient.delete(Uri.parse('pal-business/editor/groups/$groupId')); } catch (e) { diff --git a/lib/src/database/repository/in_app_user_repository.dart b/lib/src/database/repository/in_app_user_repository.dart index a192041f..e6d22721 100644 --- a/lib/src/database/repository/in_app_user_repository.dart +++ b/lib/src/database/repository/in_app_user_repository.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:http/http.dart'; import 'package:pal/src/database/adapter/in_app_user_storage_adapter.dart'; import 'package:pal/src/database/entity/in_app_user_entity.dart'; @@ -6,21 +5,15 @@ import 'package:pal/src/database/repository/base_repository.dart'; import 'package:pal/src/services/http_client/base_client.dart'; class InAppUserRepository extends BaseHttpRepository { - InAppUserRepository({@required HttpClient httpClient}) + InAppUserRepository({required HttpClient httpClient}) : super(httpClient: httpClient); Future create(final InAppUserEntity inAppUser) async { try { - final Response response = await this - .httpClient - .post(Uri.parse("pal-analytic/in-app-users"), - body: InAppUserEntityAdapter().toJson(inAppUser)) - .catchError( - (err) { - return null; - }, - ); - return InAppUserEntityAdapter().parse(response.body); + final Response response = await this.httpClient.post( + Uri.parse("pal-analytic/in-app-users"), + body: InAppUserEntityStorageAdapter().toJson(inAppUser)); + return InAppUserEntityStorageAdapter().parse(response.body); } catch (e) { throw InternalHttpError('ERROR WHILE CREATING InAppUser $e'); } @@ -29,7 +22,7 @@ class InAppUserRepository extends BaseHttpRepository { Future update(final InAppUserEntity inAppUser) async { final Response response = await this.httpClient.put( Uri.parse("pal-analytic/in-app-users/${inAppUser.id}"), - body: InAppUserEntityAdapter().toJson(inAppUser)); - return InAppUserEntityAdapter().parse(response.body); + body: InAppUserEntityStorageAdapter().toJson(inAppUser)); + return InAppUserEntityStorageAdapter().parse(response.body); } } diff --git a/lib/src/database/repository/page_repository.dart b/lib/src/database/repository/page_repository.dart index 5f115522..29c582a8 100644 --- a/lib/src/database/repository/page_repository.dart +++ b/lib/src/database/repository/page_repository.dart @@ -1,6 +1,5 @@ import 'dart:convert'; -import 'package:flutter/cupertino.dart'; import 'package:http/http.dart'; import 'package:pal/src/database/adapter/page_entity_adapter.dart' as Adapter; import 'package:pal/src/database/entity/page_entity.dart'; @@ -12,7 +11,7 @@ class PageRepository extends BaseHttpRepository { final Adapter.PageEntityAdapter _adapter = Adapter.PageEntityAdapter(); - PageRepository({@required HttpClient httpClient}) + PageRepository({required HttpClient httpClient}) : super(httpClient: httpClient); Future createPage( @@ -31,16 +30,19 @@ class PageRepository extends BaseHttpRepository { return _adapter.parsePage(response.body); } - Future getPage(final String route) { + Future getPage(final String route) { return this .httpClient .get(Uri.parse('pal-business/editor/pages?route=$route&pageSize=1')) .then((res) { - Pageable pages = _adapter.parsePage(res.body); - return (pages.entities != null && pages.entities.length > 0) - ? pages.entities.first - : null; - }); + if(res.body.isEmpty) { + return null; + } + Pageable? pages = _adapter.parsePage(res.body); + if(pages.entities!.length > 0) + return pages.entities?.first; + return null; + }); } Future> getClientPage(final String route) async { diff --git a/lib/src/database/repository/project_gallery_repository.dart b/lib/src/database/repository/project_gallery_repository.dart index 5f26225e..1f43ef7f 100644 --- a/lib/src/database/repository/project_gallery_repository.dart +++ b/lib/src/database/repository/project_gallery_repository.dart @@ -19,7 +19,7 @@ class ProjectGalleryHttpRepository extends BaseHttpRepository final ProjectGalleryEntityAdapter _adapter = ProjectGalleryEntityAdapter(); final HttpClient httpClient; - ProjectGalleryHttpRepository({@required this.httpClient}) + ProjectGalleryHttpRepository({required this.httpClient}) : super(httpClient: httpClient); @override diff --git a/lib/src/database/repository/project_repository.dart b/lib/src/database/repository/project_repository.dart index a06a6c8f..40a24bc2 100644 --- a/lib/src/database/repository/project_repository.dart +++ b/lib/src/database/repository/project_repository.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:flutter/cupertino.dart'; import 'package:http/http.dart'; import 'package:pal/src/database/adapter/app_icon_entity.dart'; import 'package:pal/src/database/entity/app_icon_entity.dart'; @@ -11,7 +10,7 @@ import 'package:pal/src/services/http_client/base_client.dart'; class ProjectRepository extends BaseHttpRepository { final AppIconEntityAdapter _adapter = AppIconEntityAdapter(); - ProjectRepository({@required HttpClient httpClient}) + ProjectRepository({required HttpClient httpClient}) : super(httpClient: httpClient); Future createAppIcon( @@ -40,7 +39,7 @@ class ProjectRepository extends BaseHttpRepository { } Future updateAppIcon( - String appIconId, + String? appIconId, Uint8List imageData, String imageType, ) async { diff --git a/lib/src/database/repository/version_repository.dart b/lib/src/database/repository/version_repository.dart index 529cc124..3028c9e1 100644 --- a/lib/src/database/repository/version_repository.dart +++ b/lib/src/database/repository/version_repository.dart @@ -1,6 +1,5 @@ import 'dart:convert'; -import 'package:flutter/material.dart'; import 'package:pal/src/database/adapter/version_entity_adapter.dart'; import 'package:pal/src/database/entity/pageable.dart'; import 'package:pal/src/database/entity/version_entity.dart'; @@ -9,9 +8,9 @@ import 'package:pal/src/services/http_client/base_client.dart'; abstract class VersionRepository { - Future> getVersions({String name, int pageSize = 10}) => throw "not implemented yet"; + Future> getVersions({String? name, int pageSize = 10}) => throw "not implemented yet"; - Future getVersion({String name = ''}) => throw "not implemented yet"; + Future getVersion({String name = ''}) => throw "not implemented yet"; Future createVersion(final VersionEntity createVersion) => throw "not implemented yet"; } @@ -21,12 +20,12 @@ class VersionHttpRepository extends BaseHttpRepository final VersionEntityAdapter _versionEntityAdapter = VersionEntityAdapter(); final HttpClient httpClient; - VersionHttpRepository({@required this.httpClient}) + VersionHttpRepository({required this.httpClient}) : super(httpClient: httpClient); @override Future> getVersions({ - String name = '', + String? name = '', int pageSize = 10, }) { return this @@ -36,16 +35,19 @@ class VersionHttpRepository extends BaseHttpRepository } @override - Future getVersion({String name = ''}) { + Future getVersion({String name = ''}) { return this .httpClient .get(Uri.parse('pal-business/editor/versions?versionName=$name&pageSize=1')) .then((res) { - Pageable pages = _versionEntityAdapter.parsePage(res.body); - return (pages.entities != null && pages.entities.length > 0) - ? pages.entities.first - : null; - }); + if(res.body.isEmpty) { + return null; + } + Pageable pages = _versionEntityAdapter.parsePage(res.body); + if(pages.entities!.length == 0) + return null; + return pages.entities!.first; + }); } Future createVersion( diff --git a/lib/src/extensions/color_extension.dart b/lib/src/extensions/color_extension.dart index d3ed6093..675a3441 100644 --- a/lib/src/extensions/color_extension.dart +++ b/lib/src/extensions/color_extension.dart @@ -13,7 +13,9 @@ extension HexColor on Color { '${green.toRadixString(16).padLeft(2, '0')}' '${blue.toRadixString(16).padLeft(2, '0')}'; - static bool isHexColor(String hexString) { + static bool isHexColor(String? hexString) { + if(hexString == null) + return false; RegExp hexColor = RegExp(r'(^((0x){0,1}|#{0,1})([0-9A-F]{8}|[0-9A-F]{6})$)'); return hexColor.hasMatch(hexString); } diff --git a/lib/src/in_app_user_manager.dart b/lib/src/in_app_user_manager.dart index f4592549..b399b770 100644 --- a/lib/src/in_app_user_manager.dart +++ b/lib/src/in_app_user_manager.dart @@ -10,7 +10,7 @@ class InAppUserManager { static InAppUserManager _instance = InAppUserManager._(); - InAppUserClientService _inAppUserClientService; + InAppUserClientService? _inAppUserClientService; InAppUserManager._(); @@ -20,7 +20,7 @@ class InAppUserManager { if (this._inAppUserClientService == null) { // TODO change with config return true; } - await this._inAppUserClientService.onConnect(inAppUserId); + await this._inAppUserClientService!.onConnect(inAppUserId); return true; } catch (e){ return false; @@ -33,7 +33,7 @@ class InAppUserManager { if (this._inAppUserClientService == null) { // TODO change with config return true; } - await this._inAppUserClientService.onDisconnect(); + await this._inAppUserClientService!.onDisconnect(); return true; } catch (e){ return false; diff --git a/lib/src/injectors/editor_app/editor_app_context.dart b/lib/src/injectors/editor_app/editor_app_context.dart index af814b2e..03bba4e0 100644 --- a/lib/src/injectors/editor_app/editor_app_context.dart +++ b/lib/src/injectors/editor_app/editor_app_context.dart @@ -9,9 +9,9 @@ import 'package:pal/src/services/http_client/base_client.dart'; class EditorAppContext { - static EditorAppContext _instance; + static EditorAppContext? _instance; - static init({@required url, @required String token}) { + static init({required url, required String token}) { if(_instance == null) { _instance = HttpEditorAppContext.create(url: url, token: token); } @@ -22,7 +22,7 @@ class EditorAppContext { _instance = editorAppContext; } - static EditorAppContext get instance { + static EditorAppContext? get instance { if(_instance == null) { throw "init needs to be called"; } @@ -58,26 +58,22 @@ class HttpEditorAppContext implements EditorAppContext { final EditorHelperGroupRepository _editorHelperGroupRepository; - factory HttpEditorAppContext.create( - {@required url, @required String token,}) - => HttpEditorAppContext.private( - httpClient: url == null || token == null ? null : HttpClient.create(url, token), - ); + factory HttpEditorAppContext.create({required url, required String token}) + => HttpEditorAppContext.private(httpClient: HttpClient.create(url, token)); @visibleForTesting HttpEditorAppContext.private({ - @required HttpClient httpClient, - }) : assert(httpClient != null), - this._editorHelperGroupRepository = EditorHelperGroupRepository(httpClient: httpClient), + required HttpClient httpClient, + }) : this._editorHelperGroupRepository = EditorHelperGroupRepository(httpClient: httpClient), this._pageRepository = PageRepository(httpClient: httpClient), this._projectRepository = ProjectRepository(httpClient: httpClient), this._editorHelperRepository = EditorHelperRepository(httpClient: httpClient), this._projectGalleryRepository = ProjectGalleryHttpRepository(httpClient: httpClient), this._versionRepository = VersionHttpRepository(httpClient: httpClient); - EditorHelperRepository get helperRepository => this._editorHelperRepository; + EditorHelperRepository get helperRepository => _editorHelperRepository; - PageRepository get pageRepository => this._pageRepository; + PageRepository get pageRepository => _pageRepository; VersionRepository get versionRepository => _versionRepository; diff --git a/lib/src/injectors/editor_app/editor_app_injector.dart b/lib/src/injectors/editor_app/editor_app_injector.dart index 8053108d..3dffc1e8 100644 --- a/lib/src/injectors/editor_app/editor_app_injector.dart +++ b/lib/src/injectors/editor_app/editor_app_injector.dart @@ -34,22 +34,21 @@ class EditorInjector extends InheritedWidget { final ProjectGalleryEditorService _projectGalleryEditorService; - final PalRouteObserver routeObserver; + final PalRouteObserver? routeObserver; - final GlobalKey hostedAppNavigatorKey; + final GlobalKey? hostedAppNavigatorKey; - final GlobalKey palNavigatorKey; + final GlobalKey? palNavigatorKey; EditorInjector({ - Key key, - @required EditorAppContext appContext, - @required this.routeObserver, - @required Widget child, - @required GlobalKey boundaryChildKey, + Key? key, + required EditorAppContext appContext, + required this.routeObserver, + required Widget child, + required GlobalKey? boundaryChildKey, this.hostedAppNavigatorKey, this.palNavigatorKey - }) : assert(child != null && appContext != null), - this._pageEditorService = PageEditorService.build(boundaryChildKey, appContext.pageRepository), + }) : this._pageEditorService = PageEditorService.build(boundaryChildKey, appContext.pageRepository), this._projectEditorService = ProjectEditorService.build( appContext.projectRepository, appContext.editorHelperGroupRepository, @@ -57,7 +56,7 @@ class EditorInjector extends InheritedWidget { ), this._helperService = EditorHelperService.build(appContext), this._helperGroupService = EditorHelperGroupService.build(appContext), - this._finderService = FinderService(observer: routeObserver), + this._finderService = FinderService(observer: routeObserver as PalNavigatorObserver?), this._projectGalleryEditorService = ProjectGalleryEditorService.build( projectGalleryRepository: appContext.projectGalleryRepository), this._packageVersionReader = PackageVersionReader(), @@ -68,7 +67,7 @@ class EditorInjector extends InheritedWidget { this._palEditModeStateService = PalEditModeStateService.build(), super(key: key, child: child); - static EditorInjector of(BuildContext context) => + static EditorInjector? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType(); @override diff --git a/lib/src/injectors/user_app/user_app_context.dart b/lib/src/injectors/user_app/user_app_context.dart index 0ba23d88..145bf411 100644 --- a/lib/src/injectors/user_app/user_app_context.dart +++ b/lib/src/injectors/user_app/user_app_context.dart @@ -6,15 +6,14 @@ import 'package:pal/src/database/repository/client/schema_repository.dart'; import 'package:pal/src/database/repository/in_app_user_repository.dart'; import 'package:pal/src/database/repository/page_repository.dart'; import 'package:pal/src/database/repository/version_repository.dart'; +import 'package:pal/src/services/client/in_app_user/in_app_user_client_storage.dart'; import 'package:pal/src/services/http_client/base_client.dart'; - class UserAppContext { + static UserAppContext? _instance; - static UserAppContext _instance; - - static init({@required url, @required String token}) { - if(_instance == null) { + static init({required url, required String token}) { + if (_instance == null) { _instance = HttpUserAppContext.create(url: url, token: token); } } @@ -24,8 +23,16 @@ class UserAppContext { _instance = userAppContext; } - static UserAppContext get instance { - if(_instance == null) { + @visibleForTesting + static createTest(HttpClient client) => + { + if (_instance == null) { + _instance = HttpUserAppContext.test(client) + } + }; + + static UserAppContext? get instance { + if (_instance == null) { throw "init needs to be called"; } return _instance; @@ -39,50 +46,66 @@ class UserAppContext { InAppUserRepository get inAppUserRepository => throw "not implemented"; - ClientSchemaRepository get localClientSchemaRepository => throw "not implemented"; + InAppUserLocalRepository get inAppUserLocalRepository => + throw "not implemented"; - ClientSchemaRepository get remoteClientSchemaRepository => throw "not implemented"; + ClientSchemaRepository get localClientSchemaRepository => + throw "not implemented"; - HelperGroupUserVisitRepository get pageUserVisitRemoteRepository => throw "not implemented"; + ClientSchemaRepository get remoteClientSchemaRepository => + throw "not implemented"; - HelperGroupUserVisitRepository get pageUserVisitLocalRepository => throw "not implemented"; + HelperGroupUserVisitRepository get pageUserVisitRemoteRepository => + throw "not implemented"; + HelperGroupUserVisitRepository get pageUserVisitLocalRepository => + throw "not implemented"; } /// [UserAppContext] inherited class to provide some context to all childs /// - this class will retain [HttpClient] to pass to all childs class HttpUserAppContext implements UserAppContext { - final PageRepository _pageRepository; final ClientHelperRepository _helperRepository; final InAppUserRepository _inAppUserRepository; + final InAppUserLocalRepository _inAppUserLocalRepository; + final VersionRepository _versionRepository; - final HelperGroupUserVisitRepository _pageUserVisitRemoteRepository, _pageUserVisitLocalRepository; + final HelperGroupUserVisitRepository _pageUserVisitRemoteRepository, + _pageUserVisitLocalRepository; + + final ClientSchemaRepository _clientSchemaLocalRepository, + _clientSchemaRemoteRepository; - final ClientSchemaRepository _clientSchemaLocalRepository, _clientSchemaRemoteRepository; + factory HttpUserAppContext.create({required url, required String token}) => + HttpUserAppContext._private( + hiveClient: HiveClient(), httpClient: HttpClient.create(url, token)); - factory HttpUserAppContext.create({@required url, @required String token}) - => HttpUserAppContext._private( - hiveClient: HiveClient(), - httpClient: url == null || token == null ? null : HttpClient.create(url, token) - ); + factory HttpUserAppContext.test(HttpClient client) => + HttpUserAppContext._private(hiveClient: HiveClient(), httpClient: client); HttpUserAppContext._private({ - @required HiveClient hiveClient, - @required HttpClient httpClient, - }) : assert(httpClient != null), - this._pageUserVisitRemoteRepository = HelperGroupUserVisitHttpRepository(httpClient: httpClient), - this._pageUserVisitLocalRepository = HelperGroupUserVisitLocalRepository(hiveBoxOpener: hiveClient.openVisitsBox), - this._clientSchemaLocalRepository = ClientSchemaLocalRepository(hiveBoxOpener: hiveClient.openSchemaBox), - this._clientSchemaRemoteRepository = ClientSchemaRemoteRepository(httpClient: httpClient), - this._pageRepository = PageRepository(httpClient: httpClient), - this._helperRepository = ClientHelperRepository(httpClient: httpClient), - this._versionRepository = VersionHttpRepository(httpClient: httpClient), - this._inAppUserRepository = InAppUserRepository(httpClient: httpClient); + required HiveClient hiveClient, + required HttpClient httpClient, + }) : this._pageUserVisitRemoteRepository = + HelperGroupUserVisitHttpRepository(httpClient: httpClient), + this._pageUserVisitLocalRepository = + HelperGroupUserVisitLocalRepository( + hiveBoxOpener: hiveClient.openVisitsBox), + this._clientSchemaLocalRepository = ClientSchemaLocalRepository( + hiveBoxOpener: hiveClient.openSchemaBox), + this._clientSchemaRemoteRepository = + ClientSchemaRemoteRepository(httpClient: httpClient), + this._pageRepository = PageRepository(httpClient: httpClient), + this._helperRepository = ClientHelperRepository(httpClient: httpClient), + this._versionRepository = VersionHttpRepository(httpClient: httpClient), + this._inAppUserRepository = InAppUserRepository(httpClient: httpClient), + this._inAppUserLocalRepository = + InAppUserLocalRepository(hiveClient.openInAppUserBox); @override PageRepository get pageRepository => _pageRepository; @@ -97,14 +120,22 @@ class HttpUserAppContext implements UserAppContext { InAppUserRepository get inAppUserRepository => _inAppUserRepository; @override - ClientSchemaRepository get localClientSchemaRepository => _clientSchemaLocalRepository; + InAppUserLocalRepository get inAppUserLocalRepository => + _inAppUserLocalRepository; + + @override + ClientSchemaRepository get localClientSchemaRepository => + _clientSchemaLocalRepository; @override - ClientSchemaRepository get remoteClientSchemaRepository => _clientSchemaRemoteRepository; + ClientSchemaRepository get remoteClientSchemaRepository => + _clientSchemaRemoteRepository; @override - HelperGroupUserVisitRepository get pageUserVisitRemoteRepository => _pageUserVisitRemoteRepository; + HelperGroupUserVisitRepository get pageUserVisitRemoteRepository => + _pageUserVisitRemoteRepository; @override - HelperGroupUserVisitRepository get pageUserVisitLocalRepository => _pageUserVisitLocalRepository; + HelperGroupUserVisitRepository get pageUserVisitLocalRepository => + _pageUserVisitLocalRepository; } diff --git a/lib/src/injectors/user_app/user_app_injector.dart b/lib/src/injectors/user_app/user_app_injector.dart index 06b8005b..9d2540dc 100644 --- a/lib/src/injectors/user_app/user_app_injector.dart +++ b/lib/src/injectors/user_app/user_app_injector.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:pal/src/database/repository/client/schema_repository.dart'; import 'package:pal/src/injectors/user_app/user_app_context.dart'; import 'package:pal/src/services/client/in_app_user/in_app_user_client_service.dart'; import 'package:pal/src/services/client/helper_client_service.dart'; @@ -20,7 +21,7 @@ class UserInjector extends InheritedWidget { final PackageVersionReader _packageVersionReader; - final PalRouteObserver routeObserver; + final PalRouteObserver? routeObserver; final HelpersSynchronizer _helperSynchronizeService; @@ -29,13 +30,12 @@ class UserInjector extends InheritedWidget { final LocaleService _userLocale; UserInjector( - {Key key, - @required UserAppContext appContext, - @required this.routeObserver, - @required Widget child, - @required LocaleService userLocale}) - : assert(child != null && appContext != null), - this._userLocale = userLocale, + {Key? key, + required UserAppContext appContext, + required this.routeObserver, + required Widget child, + required LocaleService userLocale}) + : this._userLocale = userLocale, this._pageService = PageClientService.build(appContext.pageRepository), this._helperService = HelperClientService.build( clientSchemaRepository: appContext.localClientSchemaRepository, @@ -44,7 +44,7 @@ class UserInjector extends InheritedWidget { remoteVisitRepository: appContext.pageUserVisitRemoteRepository, userLocale: userLocale), this._helperSynchronizeService = new HelpersSynchronizer( - schemaLocalRepository: appContext.localClientSchemaRepository, + schemaLocalRepository: appContext.localClientSchemaRepository as ClientSchemaLocalRepository, schemaRemoteRepository: appContext.remoteClientSchemaRepository, pageUserVisitLocalRepository: appContext.pageUserVisitLocalRepository, pageUserVisitRemoteRepository: @@ -53,13 +53,13 @@ class UserInjector extends InheritedWidget { ), this._packageVersionReader = PackageVersionReader(), this._clientInAppUserService = - InAppUserClientService.build(appContext.inAppUserRepository), - this._finderService = FinderService(observer: routeObserver), + InAppUserClientService.build(appContext.inAppUserRepository,appContext.inAppUserLocalRepository), + this._finderService = FinderService(observer: routeObserver as PalNavigatorObserver?), super(key: key, child: child) { setInAppUserManagerService(this.inAppUserClientService); } - static UserInjector of(BuildContext context) => + static UserInjector? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType(); @override diff --git a/lib/src/pal.dart b/lib/src/pal.dart index 265d15f0..a7ba16ab 100644 --- a/lib/src/pal.dart +++ b/lib/src/pal.dart @@ -5,6 +5,7 @@ import 'package:pal/src/injectors/editor_app/editor_app_context.dart'; import 'package:pal/src/injectors/editor_app/editor_app_injector.dart'; import 'package:pal/src/injectors/user_app/user_app_context.dart'; import 'package:pal/src/injectors/user_app/user_app_injector.dart'; +import 'package:pal/src/pal_database_initializer.dart'; import 'package:pal/src/services/locale_service/locale_service.dart'; import 'package:pal/src/ui/client/helper_orchestrator.dart'; import 'package:pal/src/ui/editor/pal_editmode_wrapper.dart'; @@ -24,16 +25,16 @@ typedef ChildAppBuilder = Widget Function(BuildContext context); // Pal top widget class Pal extends StatelessWidget { /// application child to display Pal over it. - final MaterialApp childApp; + final MaterialApp? childApp; /// build application child dynamically to display Pal over it. (used for GetX or other plugins) - final ChildAppBuilder childAppBuilder; + final ChildAppBuilder? childAppBuilder; /// reference to the Navigator state of the child app - final GlobalKey navigatorKey; + final GlobalKey? navigatorKey; /// used to manage state of current page - final PalNavigatorObserver navigatorObserver; + final PalNavigatorObserver? navigatorObserver; /// disable or enable the editor mode. final bool editorModeEnabled; @@ -45,10 +46,10 @@ class Pal extends StatelessWidget { final String appToken; Pal({ - Key key, - this.childApp, + Key? key, + required MaterialApp this.childApp, this.childAppBuilder, - @required this.appToken, + required this.appToken, this.editorModeEnabled = true, this.textDirection = TextDirection.ltr, }) : assert(childApp != null, 'Pal must embed a client application'), @@ -57,8 +58,9 @@ class Pal extends StatelessWidget { assert( childApp.navigatorKey != null, 'Pal navigatorKey must not be null'), navigatorKey = childApp.navigatorKey, - navigatorObserver = childApp.navigatorObservers - .firstWhere((element) => element is PalNavigatorObserver), + navigatorObserver = childApp.navigatorObservers! + .firstWhere((element) => element is PalNavigatorObserver) + as PalNavigatorObserver?, super(key: key) { assert(navigatorObserver != null, 'your app navigatorObservers must contain PalNavigatorObserver like this: navigatorObservers: [PalNavigatorObserver.instance()]'); @@ -66,12 +68,12 @@ class Pal extends StatelessWidget { } Pal._({ - Key key, + Key? key, this.childApp, this.childAppBuilder, this.navigatorKey, this.navigatorObserver, - @required this.appToken, + required this.appToken, this.editorModeEnabled = true, this.textDirection = TextDirection.ltr, }) : super(key: key) { @@ -84,10 +86,10 @@ class Pal extends StatelessWidget { /// - onGenerateRoute: routes, /// - navigatorObservers: [PalNavigatorObserver.instance()], factory Pal.fromAppBuilder( - {@required ChildAppBuilder childAppBuilder, - @required String appToken, - @required bool editorModeEnabled, - @required GlobalKey navigatorKey}) => + {required ChildAppBuilder childAppBuilder, + required String appToken, + required bool editorModeEnabled, + required GlobalKey navigatorKey}) => Pal._( childAppBuilder: childAppBuilder, appToken: appToken, @@ -97,12 +99,12 @@ class Pal extends StatelessWidget { ); Pal.fromRouterApp({ - Key key, + Key? key, this.childApp, this.childAppBuilder, - @required this.appToken, + required this.appToken, this.editorModeEnabled = true, - this.navigatorKey, + required GlobalKey this.navigatorKey, this.textDirection = TextDirection.ltr, }) : assert(childApp != null || childAppBuilder != null, 'Pal must embed a client application'), @@ -129,15 +131,28 @@ class Pal extends StatelessWidget { Widget build(BuildContext context) { return Directionality( textDirection: textDirection, - child: (editorModeEnabled) - ? buildEditorApp( - childApp == null ? childAppBuilder(context) : childApp) - : buildUserApp( - childApp == null ? childAppBuilder(context) : childApp), + // load asynchronous stuff in this class + child: PalDatabaseInitializer( + builder: (BuildContext context, snapshot) { + if (snapshot.hasData) { + // return client app WITH Pal if already loaded + return (editorModeEnabled) + ? buildEditorApp( + childApp == null ? childAppBuilder!(context) : childApp, + ) + : buildUserApp( + childApp == null ? childAppBuilder!(context) : childApp, + ); + } else { + // return client app WITHOUT Pal if not already loaded + return childApp!; + } + }, + ), ); } - Widget buildEditorApp(Widget childApp) { + Widget buildEditorApp(Widget? childApp) { return EditorInjector( routeObserver: navigatorObserver, hostedAppNavigatorKey: navigatorKey, @@ -147,23 +162,26 @@ class Pal extends StatelessWidget { hostedAppNavigatorKey: navigatorKey, ), boundaryChildKey: navigatorKey, - appContext: EditorAppContext.instance); + appContext: EditorAppContext.instance!); } - Widget buildUserApp(Widget childApp) { + Widget buildUserApp(Widget? childApp) { return UserInjector( - appContext: UserAppContext.instance, + appContext: UserAppContext.instance!, routeObserver: navigatorObserver, userLocale: LocaleService(hostedKey: navigatorKey), child: Builder(builder: (context) { HelperOrchestrator.getInstance( - helperClientService: UserInjector.of(context).helperService, - inAppUserClientService: UserInjector.of(context).inAppUserClientService, - helpersSynchronizer: UserInjector.of(context).helpersSynchronizerService, + helperClientService: UserInjector.of(context)!.helperService, + inAppUserClientService: + UserInjector.of(context)!.inAppUserClientService, + helpersSynchronizer: + UserInjector.of(context)!.helpersSynchronizerService, routeObserver: navigatorObserver, - packageVersionReader: UserInjector.of(context).packageVersionReader, + packageVersionReader: + UserInjector.of(context)!.packageVersionReader, navigatorKey: navigatorKey); - return Overlayed(child: childApp); + return Overlayed(child: childApp!); }), ); } diff --git a/lib/src/pal_database_initializer.dart b/lib/src/pal_database_initializer.dart new file mode 100644 index 00000000..d5e3c9fd --- /dev/null +++ b/lib/src/pal_database_initializer.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:hive/hive.dart'; +import 'package:hive_flutter/hive_flutter.dart'; +import 'package:pal/src/pal_utils.dart'; + +// this is used to load pal in asynchronous mode, +// can be used to call some asynchronous stuff like migrations, init etc. +class PalDatabaseInitializer extends StatefulWidget { + final Widget Function(BuildContext, AsyncSnapshot) builder; + + const PalDatabaseInitializer({Key? key, required this.builder}) : super(key: key); + + @override + _PalDatabaseInitializerState createState() => _PalDatabaseInitializerState(); +} + +class _PalDatabaseInitializerState extends State { + bool _isLoaded = false; + + @override + Widget build(BuildContext context) { + return FutureBuilder( + builder: this.widget.builder, + future: !PalUtils.isRunningInTestEnv() + ? asynchronousLoading() + : Future.value(true), + ); + } + + Future asynchronousLoading() async { + if (!_isLoaded) { + await Hive.initFlutter(); + + // migrations... + // async stuff goes here + _isLoaded = true; + } + + return _isLoaded; + } +} diff --git a/lib/src/pal_navigator_observer.dart b/lib/src/pal_navigator_observer.dart index a456916f..24bf7392 100644 --- a/lib/src/pal_navigator_observer.dart +++ b/lib/src/pal_navigator_observer.dart @@ -9,7 +9,7 @@ class PalRouteObserver { class PalNavigatorObserver extends RouteObserver> implements PalRouteObserver { - static PalNavigatorObserver _instance; + static PalNavigatorObserver? _instance; Subject _routeSettingsSubject = BehaviorSubject(); @@ -21,21 +21,21 @@ class PalNavigatorObserver extends RouteObserver> implements if(_instance == null) { _instance = PalNavigatorObserver._(); } - return _instance; + return _instance!; } _notify(RouteSettings route) => _routeSettingsSubject.add(route); _notifyRoute(PageRoute route) => _routeSubject.add(route); - void changePage(String route, {Map arguments}) { + void changePage(String route, {Map? arguments}) { if(route != null && route.isNotEmpty) { _notify(RouteSettings(name: route, arguments: arguments)); } } @override - void didPush(Route route, Route previousRoute) { + void didPush(Route route, Route? previousRoute) { super.didPush(route, previousRoute); if(route.settings == null || route.settings.name == null) { debugPrint("Pal Warning ------------------"); @@ -54,7 +54,7 @@ class PalNavigatorObserver extends RouteObserver> implements } @override - void didReplace({Route newRoute, Route oldRoute}) { + void didReplace({Route? newRoute, Route? oldRoute}) { super.didReplace(newRoute: newRoute, oldRoute: oldRoute); if (newRoute is PageRoute) { _notify(newRoute.settings); @@ -63,7 +63,7 @@ class PalNavigatorObserver extends RouteObserver> implements } @override - void didPop(Route route, Route previousRoute) { + void didPop(Route route, Route? previousRoute) { super.didPop(route, previousRoute); if (previousRoute is PageRoute && route is PageRoute) { _notify(previousRoute.settings); diff --git a/lib/src/pal_utils.dart b/lib/src/pal_utils.dart new file mode 100644 index 00000000..5a0119da --- /dev/null +++ b/lib/src/pal_utils.dart @@ -0,0 +1,8 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; + +class PalUtils { + static bool isRunningInTestEnv() => + !kIsWeb ? Platform.environment.containsKey('FLUTTER_TEST') : false; +} \ No newline at end of file diff --git a/lib/src/router.dart b/lib/src/router.dart index 5e515a1c..ef762aa1 100644 --- a/lib/src/router.dart +++ b/lib/src/router.dart @@ -13,49 +13,48 @@ GlobalKey palNavigatorGlobalKey = new GlobalKey(); Route route(RouteSettings settings) { - print("root router... ${settings.name}"); switch (settings.name) { case '/settings': return MaterialPageRoute( builder: (context) => AppSettingsPage(), ); case '/editor/new': - CreateHelperPageArguments args = settings.arguments; + CreateHelperPageArguments? args = settings.arguments as CreateHelperPageArguments?; return MaterialPageRoute( builder: (context) => CreateHelperPage( - pageId: args.pageId, + pageId: args!.pageId, hostedAppNavigatorKey: args.hostedAppNavigatorKey, ), ); case '/editor/group/details': - String groupId = (settings.arguments as Map)["id"]; - String pageRoute = (settings.arguments as Map)["route"]; - PageStep startPage = (settings.arguments as Map)["page"]; + String? groupId = (settings.arguments as Map)["id"]; + String? pageRoute = (settings.arguments as Map)["route"]; + PageStep? startPage = (settings.arguments as Map)["page"]; return PageRouteBuilder( opaque: false, pageBuilder: (context, a, b) => GroupDetailsPage( groupId: groupId, routeName: pageRoute, page: startPage), ); case '/editor/new/font-family': - FontFamilyPickerArguments args = settings.arguments; + FontFamilyPickerArguments? args = settings.arguments as FontFamilyPickerArguments?; return MaterialPageRoute( builder: (context) => FontFamilyPickerPage( arguments: args, )); case '/editor/new/font-weight': - FontWeightPickerArguments args = settings.arguments; + FontWeightPickerArguments? args = settings.arguments as FontWeightPickerArguments?; return MaterialPageRoute( builder: (context) => FontWeightPickerPage( arguments: args, )); case '/editor/media-gallery': - MediaGalleryPageArguments args = settings.arguments; + MediaGalleryPageArguments? args = settings.arguments as MediaGalleryPageArguments?; return MaterialPageRoute( builder: (context) => MediaGalleryPage( - mediaId: args.mediaId, + mediaId: args!.mediaId, )); case '/editor/preview': - EditorPreviewArguments args = settings.arguments; + EditorPreviewArguments? args = settings.arguments as EditorPreviewArguments?; return PageRouteBuilder( maintainState: true, opaque: false, @@ -71,22 +70,22 @@ Route route(RouteSettings settings) { //shows a page as overlay for our editor showOverlayed( GlobalKey hostedAppNavigatorKey, WidgetBuilder builder, - {OverlayKeys key, Function onPop}) { + {OverlayKeys? key, Function? onPop}) { EditorOverlayEntry helperOverlay = EditorOverlayEntry( onPop, opaque: false, builder: builder, ); - Overlayed.of(hostedAppNavigatorKey.currentContext).entries.putIfAbsent( + Overlayed.of(hostedAppNavigatorKey.currentContext!)!.entries.putIfAbsent( key ?? OverlayKeys.EDITOR_OVERLAY_KEY, () => helperOverlay, ); - hostedAppNavigatorKey.currentState.overlay.insert(helperOverlay); + hostedAppNavigatorKey.currentState!.overlay!.insert(helperOverlay); } showOverlayedInContext(WidgetBuilder builder, - {OverlayKeys key, Function onPop}) { - if (Overlayed.of(palNavigatorGlobalKey.currentState.context) + {OverlayKeys? key, Function? onPop}) { + if (Overlayed.of(palNavigatorGlobalKey.currentState!.context)! .entries .containsKey(key ?? OverlayKeys.EDITOR_OVERLAY_KEY)) { return; @@ -96,16 +95,16 @@ showOverlayedInContext(WidgetBuilder builder, opaque: false, builder: builder, ); - Overlayed.of(palNavigatorGlobalKey.currentState.context).entries.putIfAbsent( + Overlayed.of(palNavigatorGlobalKey.currentState!.context)!.entries.putIfAbsent( key ?? OverlayKeys.EDITOR_OVERLAY_KEY, () => helperOverlay, ); - palNavigatorGlobalKey.currentState.overlay.insert(helperOverlay); + palNavigatorGlobalKey.currentState!.overlay!.insert(helperOverlay); } closeOverlayed(OverlayKeys key) { - Overlayed.of(palNavigatorGlobalKey.currentState.context) - .entries[key] + Overlayed.of(palNavigatorGlobalKey.currentState!.context)! + .entries[key]! .remove(); - Overlayed.of(palNavigatorGlobalKey.currentState.context).entries.remove(key); + Overlayed.of(palNavigatorGlobalKey.currentState!.context)!.entries.remove(key); } diff --git a/lib/src/services/app_events.dart b/lib/src/services/app_events.dart index cad23cc3..51a3f580 100644 --- a/lib/src/services/app_events.dart +++ b/lib/src/services/app_events.dart @@ -2,7 +2,7 @@ import 'package:pal/src/pal_navigator_observer.dart'; class PalEvents { - static PalEvents _instance; + static PalEvents? _instance; PalEvents._(); @@ -10,10 +10,10 @@ class PalEvents { if(_instance == null) { _instance = PalEvents._(); } - return _instance; + return _instance!; } - void pushPage(String routeName, {Map arguments}) + void pushPage(String routeName, {Map? arguments}) => PalNavigatorObserver.instance().changePage(routeName, arguments: arguments); diff --git a/lib/src/services/client/helper_client_service.dart b/lib/src/services/client/helper_client_service.dart index fb1847d0..6d360122 100644 --- a/lib/src/services/client/helper_client_service.dart +++ b/lib/src/services/client/helper_client_service.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:pal/src/database/entity/helper/helper_entity.dart'; import 'package:pal/src/database/entity/helper/helper_group_entity.dart'; import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; @@ -13,11 +12,11 @@ import 'package:pal/src/services/locale_service/locale_service.dart'; class HelperClientService { factory HelperClientService.build({ - HelperGroupUserVisitRepository localVisitRepository, - HelperGroupUserVisitRepository remoteVisitRepository, - ClientSchemaRepository clientSchemaRepository, - ClientHelperRepository helperRemoteRepository, - LocaleService userLocale, + required HelperGroupUserVisitRepository localVisitRepository, + required HelperGroupUserVisitRepository remoteVisitRepository, + required ClientSchemaRepository clientSchemaRepository, + required ClientHelperRepository helperRemoteRepository, + required LocaleService userLocale, }) => _HelperClientService( clientSchemaRepository: clientSchemaRepository, helperRemoteRepository: helperRemoteRepository, @@ -26,49 +25,51 @@ class HelperClientService { userLocale: userLocale ); - Future getPageNextHelper( - final String route, - final String inAppUserId, + Future getPageNextHelper( + final String? route, + final String? inAppUserId, final AppVersion appVersion) => throw "not implemented"; - Future onHelperTrigger( - final String pageId, + Future onHelperTrigger( + final String? pageId, final HelperGroupEntity helperGroup, final HelperEntity helper, - final String inAppUserId, + final String? inAppUserId, final bool positiveFeedback, final String inAppVersion) => throw "not implemented"; } class _HelperClientService implements HelperClientService { - final ClientSchemaRepository _clientSchemaRepository; + late final ClientSchemaRepository _clientSchemaRepository; - final HelperGroupUserVisitRepository _localVisitRepository, _remoteVisitRepository; // ignore: unused_field + late final HelperGroupUserVisitRepository _localVisitRepository, _remoteVisitRepository; // ignore: unused_field - final LocaleService _userLocale; + late final LocaleService _userLocale; _HelperClientService({ - @required HelperGroupUserVisitRepository localVisitRepository, - @required HelperGroupUserVisitRepository remoteVisitRepository, - @required ClientSchemaRepository clientSchemaRepository, - @required ClientHelperRepository helperRemoteRepository, - @required LocaleService userLocale, + required HelperGroupUserVisitRepository localVisitRepository, + required HelperGroupUserVisitRepository remoteVisitRepository, + required ClientSchemaRepository clientSchemaRepository, + required ClientHelperRepository helperRemoteRepository, + required LocaleService userLocale, }) : this._clientSchemaRepository = clientSchemaRepository, this._localVisitRepository = localVisitRepository, this._remoteVisitRepository = remoteVisitRepository, this._userLocale = userLocale; @override - Future getPageNextHelper( - String route, - String inAppUserId, + Future getPageNextHelper( + String? route, + String? inAppUserId, AppVersion inAppVersion ) async { - SchemaEntity currentSchema = await _clientSchemaRepository.get(); + SchemaEntity? currentSchema = await _clientSchemaRepository.get(); + if(currentSchema == null) + return null; List userVisits = await _localVisitRepository.get(inAppUserId, null); - List group = currentSchema.groups - .where((element) => element.page.route == route) + List group = currentSchema.groups! + .where((element) => element.page!.route == route) .where((element) => inAppVersion.isGreaterOrEqual(AppVersion.fromString(element.minVersion))) .where((element) => inAppVersion.isLowerOrEqual(AppVersion.fromString(element.maxVersion))) .where((element) => userVisits.where((visit) => visit.helperGroupId == element.id).isEmpty) @@ -78,34 +79,34 @@ class _HelperClientService implements HelperClientService { var firstVisit = userVisits.isNotEmpty ? userVisits.first : null; var firstVisitVersion = userVisits.isNotEmpty ? AppVersion.fromString(firstVisit?.visitVersion) : null; int i = -1; - HelperGroupEntity selectedGroup; + HelperGroupEntity? selectedGroup; while(i < group.length - 1 && selectedGroup == null) { i++; if(group[i].triggerType == HelperTriggerType.ON_NEW_UPDATE - && (firstVisit == null || firstVisitVersion.isLower(inAppVersion))) { + && (firstVisit == null || firstVisitVersion!.isLower(inAppVersion))) { selectedGroup = group[i]; } else if (group[i].triggerType == HelperTriggerType.ON_SCREEN_VISIT) { selectedGroup = group[i]; } } if(selectedGroup!=null) - return selectedGroup..helpers.sort(); + return selectedGroup..helpers!.sort(); } return null; } @override - Future onHelperTrigger( - String pageId, + Future onHelperTrigger( + String? pageId, HelperGroupEntity helperGroup, HelperEntity helper, - String inAppUserId, + String? inAppUserId, bool positiveFeedback, String inAppVersion ) async { try { - var helperIndex = helperGroup.helpers.indexWhere((element) => element.id == helper.id); - bool isLast = helperIndex == helperGroup.helpers.length - 1; + var helperIndex = helperGroup.helpers!.indexWhere((element) => element.id == helper.id); + bool isLast = helperIndex == helperGroup.helpers!.length - 1; var visit = HelperGroupUserVisitEntity( pageId: pageId, helperGroupId: helperGroup.id, @@ -116,14 +117,20 @@ class _HelperClientService implements HelperClientService { visit, isLast: isLast, feedback: positiveFeedback, - inAppUserId: inAppUserId, + inAppUserId: inAppUserId!, helper: helper, languageCode: _userLocale.languageCode, - ); - await _localVisitRepository.add(visit); // we only store locally that he already visited - } catch(err) { - print("error occured while sending visits "); + await _localVisitRepository.add( + visit, + isLast: isLast, + feedback: positiveFeedback, + inAppUserId: inAppUserId, + helper: helper, + languageCode: _userLocale.languageCode + ); // we only store locally that he already visited + } catch(err,stack) { + print("error occured while sending visits $err => $stack"); print(err); } } diff --git a/lib/src/services/client/in_app_user/in_app_user_client_service.dart b/lib/src/services/client/in_app_user/in_app_user_client_service.dart index ac7c1f30..4261f4b3 100644 --- a/lib/src/services/client/in_app_user/in_app_user_client_service.dart +++ b/lib/src/services/client/in_app_user/in_app_user_client_service.dart @@ -5,28 +5,27 @@ import 'package:pal/src/services/client/in_app_user/in_app_user_client_storage.d abstract class InAppUserClientService { Future getOrCreate(); - Future onConnect(String inAppUserId); + Future onConnect(String inAppUserId); - Future update(bool inAppUserId); + Future update(bool inAppUserId); - Future onDisconnect(); + Future onDisconnect(); factory InAppUserClientService.build( - InAppUserRepository inAppUserRepository, {final InAppUserStorageClientManager inAppUserStorageClientManager}) => - _ClientInAppUserHttpService(inAppUserRepository, inAppUserStorageClientManager: inAppUserStorageClientManager); + InAppUserRepository inAppUserRepository, final InAppUserLocalRepository inAppUserStorageClientManager) => + _ClientInAppUserHttpService(inAppUserRepository, inAppUserStorageClientManager); } class _ClientInAppUserHttpService implements InAppUserClientService { final InAppUserRepository _inAppUserRepository; - final InAppUserStorageClientManager _clientInAppUserStorageManager; + final InAppUserLocalRepository _clientInAppUserStorageManager; - _ClientInAppUserHttpService(this._inAppUserRepository, {final InAppUserStorageClientManager inAppUserStorageClientManager}) - : this._clientInAppUserStorageManager = inAppUserStorageClientManager ?? InAppUserStorageClientManager.build(); + _ClientInAppUserHttpService(this._inAppUserRepository, final InAppUserLocalRepository inAppUserStorageClientManager) + : this._clientInAppUserStorageManager = inAppUserStorageClientManager; @override Future getOrCreate() async { - InAppUserEntity inAppUser = - await this._clientInAppUserStorageManager.readInAppUser(); + InAppUserEntity? inAppUser = await this._clientInAppUserStorageManager.readInAppUser(); if (inAppUser != null) { return inAppUser; } @@ -37,10 +36,9 @@ class _ClientInAppUserHttpService implements InAppUserClientService { } @override - Future onConnect(final String inAppUserId) async { - InAppUserEntity inAppUser = - await this._clientInAppUserStorageManager.readInAppUser(); - if (inAppUser == null || !inAppUser.anonymous) { + Future onConnect(final String inAppUserId) async { + InAppUserEntity? inAppUser = await this._clientInAppUserStorageManager.readInAppUser(); + if (inAppUser == null || !inAppUser.anonymous!) { return inAppUser; } @@ -48,17 +46,14 @@ class _ClientInAppUserHttpService implements InAppUserClientService { id: inAppUser.id, inAppId: inAppUserId )); - await this._clientInAppUserStorageManager.clearInAppUser(); await this._clientInAppUserStorageManager.storeInAppUser(inAppUser); return inAppUser; } @override - Future update(final bool disabledHelpers) async { - InAppUserEntity inAppUser = - await this._clientInAppUserStorageManager.readInAppUser(); - + Future update(final bool disabledHelpers) async { + InAppUserEntity? inAppUser = await this._clientInAppUserStorageManager.readInAppUser(); if (inAppUser == null) { return inAppUser; } @@ -67,28 +62,23 @@ class _ClientInAppUserHttpService implements InAppUserClientService { id: inAppUser.id, disabledHelpers: disabledHelpers )); - await this._clientInAppUserStorageManager.clearInAppUser(); await this._clientInAppUserStorageManager.storeInAppUser(inAppUser); return inAppUser; } @override - Future onDisconnect() async { - InAppUserEntity inAppUser = - await this._clientInAppUserStorageManager.readInAppUser(); - if (inAppUser == null || inAppUser.anonymous) { + Future onDisconnect() async { + InAppUserEntity? inAppUser = await this._clientInAppUserStorageManager.readInAppUser(); + if (inAppUser == null || inAppUser.anonymous!) { return inAppUser; } await this._clientInAppUserStorageManager.clearInAppUser(); - inAppUser = await this ._inAppUserRepository .create(InAppUserEntity(disabledHelpers: false)); - await this._clientInAppUserStorageManager.storeInAppUser(inAppUser); - return inAppUser; } } diff --git a/lib/src/services/client/in_app_user/in_app_user_client_storage.dart b/lib/src/services/client/in_app_user/in_app_user_client_storage.dart index bd5dd992..bfdfcea0 100644 --- a/lib/src/services/client/in_app_user/in_app_user_client_storage.dart +++ b/lib/src/services/client/in_app_user/in_app_user_client_storage.dart @@ -1,45 +1,35 @@ -import 'package:pal/src/database/adapter/in_app_user_storage_adapter.dart'; import 'package:pal/src/database/entity/in_app_user_entity.dart'; -import 'package:pal/src/services/local_storage/local_storage_manager.dart'; +import 'package:pal/src/database/hive_client.dart'; -class InAppUserStorageClientManager { - final StorageManager _localStorageManager; - final InAppUserEntityAdapter _adapter; - InAppUserEntity _inAppUser; +class InAppUserLocalRepository { + late LocalDbOpener _boxOpener; + InAppUserEntity? _inAppUser; - factory InAppUserStorageClientManager.build() => - InAppUserStorageClientManager._private( - LocalStorageManager("in_app_user"), InAppUserEntityAdapter()); - - InAppUserStorageClientManager._private( - this._localStorageManager, this._adapter); + InAppUserLocalRepository(this._boxOpener); Future storeInAppUser(final InAppUserEntity inAppUser) async { this._inAppUser = inAppUser; - await this._localStorageManager.store(this._adapter.toJson(inAppUser)); + await this._boxOpener().then((box) async { + await box.put("user", inAppUser); + }); } - Future readInAppUser() { + Future readInAppUser() async { if (this._inAppUser != null) { return Future.value(this._inAppUser); } - return this._localStorageManager.read().then((res) { - if (res != null && res.length > 0) { - try { - this._inAppUser = this._adapter.parse(res); - return this._inAppUser; - } catch (e) { - return null; - } - } - return null; + + return await this._boxOpener().then((box) { + return box.get("user"); }); } - Future clearInAppUser() async { - await this._localStorageManager.deleteFile(); - InAppUserEntity deletedInAppUser = this._inAppUser; - this._inAppUser = null; - return deletedInAppUser; + Future clearInAppUser() async { + return await this._boxOpener().then((box) async { + await box.delete("user"); + InAppUserEntity? deletedInAppUser = this._inAppUser; + this._inAppUser = null; + return deletedInAppUser; + }); } } diff --git a/lib/src/services/client/page_client_service.dart b/lib/src/services/client/page_client_service.dart index c4a5e389..60c8c163 100644 --- a/lib/src/services/client/page_client_service.dart +++ b/lib/src/services/client/page_client_service.dart @@ -5,7 +5,7 @@ abstract class PageClientService { factory PageClientService.build(PageRepository pageRepository) => _PageClientHttpService(pageRepository); - Future getPage(final String route); + Future getPage(final String route); } class _PageClientHttpService implements PageClientService { @@ -14,7 +14,7 @@ class _PageClientHttpService implements PageClientService { _PageClientHttpService(this._pageRepository); @override - Future getPage(String route) { + Future getPage(String route) { return this._pageRepository.getPage(route); } } diff --git a/lib/src/services/client/versions/version.dart b/lib/src/services/client/versions/version.dart index eefe51cb..eb284e29 100644 --- a/lib/src/services/client/versions/version.dart +++ b/lib/src/services/client/versions/version.dart @@ -5,7 +5,7 @@ class AppVersion { AppVersion._(this.major, this.minor, this.patch, ); - factory AppVersion.fromString(String version) { + factory AppVersion.fromString(String? version) { if(version == null || version == "latest") return new AppVersion._(-1, -1, -1); var parsed = version.split("."); diff --git a/lib/src/services/editor/groups/group_service.dart b/lib/src/services/editor/groups/group_service.dart index 5a272c66..89195a25 100644 --- a/lib/src/services/editor/groups/group_service.dart +++ b/lib/src/services/editor/groups/group_service.dart @@ -10,15 +10,15 @@ abstract class EditorHelperGroupService { EditorHelperGroupHttpService(appContext.editorHelperGroupRepository); /// returns the list of groups on a route - Future> getPageGroups(String route); + Future> getPageGroups(String? route); - Future> getGroupHelpers(String groupId); + Future> getGroupHelpers(String? groupId); - Future getGroupDetails(String groupId); + Future getGroupDetails(String? groupId); Future updateGroup(HelperGroupUpdate updated); - Future deleteGroup(String groupId); + Future deleteGroup(String? groupId); } class EditorHelperGroupHttpService implements EditorHelperGroupService { @@ -26,15 +26,15 @@ class EditorHelperGroupHttpService implements EditorHelperGroupService { EditorHelperGroupHttpService(this._editorHelperGroupRepository); - Future> getPageGroups(String pageId) => + Future> getPageGroups(String? pageId) => _editorHelperGroupRepository.listHelperGroups(pageId); @override - Future> getGroupHelpers(String groupId) => + Future> getGroupHelpers(String? groupId) => _editorHelperGroupRepository.listGroupHelpers(groupId); @override - Future getGroupDetails(String groupId) => + Future getGroupDetails(String? groupId) => _editorHelperGroupRepository.getGroupDetails(groupId); @override @@ -48,7 +48,7 @@ class EditorHelperGroupHttpService implements EditorHelperGroupService { } @override - Future deleteGroup(String groupId) { + Future deleteGroup(String? groupId) { return this._editorHelperGroupRepository.deleteGroup(groupId); } } diff --git a/lib/src/services/editor/helper/helper_editor_model_adapter.dart b/lib/src/services/editor/helper/helper_editor_model_adapter.dart index 34c7f398..15400f3b 100644 --- a/lib/src/services/editor/helper/helper_editor_model_adapter.dart +++ b/lib/src/services/editor/helper/helper_editor_model_adapter.dart @@ -9,12 +9,12 @@ class HelperEditorAdapter { static HelperEntity parseSimpleHelper(CreateSimpleHelper args) => _parseConfig(args.config, HelperType.SIMPLE_HELPER) ..helperTexts = [_parseHelperText(SimpleHelperKeys.CONTENT_KEY, args.titleText)] - ..helperBoxes = args.boxConfig?.color != null ? [_parseHelperBox(SimpleHelperKeys.BACKGROUND_KEY, args.boxConfig)] : []; + ..helperBoxes = args.boxConfig.color != null ? [_parseHelperBox(SimpleHelperKeys.BACKGROUND_KEY, args.boxConfig)] : []; static HelperEntity parseFullscreenHelper(CreateFullScreenHelper args) => _parseConfig(args.config, HelperType.HELPER_FULL_SCREEN) - ..helperImages = args.mediaHeader?.url != null && args.mediaHeader.url.isNotEmpty ? - [_parseHelperImage(FullscreenHelperKeys.IMAGE_KEY, args.mediaHeader)]:[] + ..helperImages = args.mediaHeader?.url != null && args.mediaHeader!.url!.isNotEmpty ? + [_parseHelperImage(FullscreenHelperKeys.IMAGE_KEY, args.mediaHeader!)]:[] ..helperTexts = [ _parseHelperText(FullscreenHelperKeys.TITLE_KEY, args.title), _parseHelperText(FullscreenHelperKeys.DESCRIPTION_KEY, args.description), @@ -34,7 +34,7 @@ class HelperEditorAdapter { ), ] ..helperBoxes = [_parseHelperBox(UpdatescreenHelperKeys.BACKGROUND_KEY, args.bodyBox)] - ..helperImages = args.headerMedia?.url != null && args.headerMedia.url.isNotEmpty ? + ..helperImages = args.headerMedia.url != null && args.headerMedia.url!.isNotEmpty ? [_parseHelperImage(UpdatescreenHelperKeys.IMAGE_KEY, args.headerMedia)]:[]; @@ -46,12 +46,12 @@ class HelperEditorAdapter { _parseHelperText(AnchoredscreenHelperKeys.POSITIV_KEY, args.positivButton), _parseHelperText(AnchoredscreenHelperKeys.NEGATIV_KEY, args.negativButton), ] - ..helperBoxes = [_parseHelperBox(args.bodyBox.key, args.bodyBox)]; + ..helperBoxes = [_parseHelperBox(args.bodyBox!.key, args.bodyBox)]; //------------------------------------------------------------- //------------------------------------------------------------- - static HelperBoxEntity _parseHelperBox(String key, HelperBoxConfig boxConfig) { + static HelperBoxEntity _parseHelperBox(String? key, HelperBoxConfig? boxConfig) { return HelperBoxEntity( id: boxConfig?.id, key: key, @@ -59,7 +59,7 @@ class HelperEditorAdapter { ); } - static HelperTextEntity _parseHelperText(String key, HelperTextConfig textConfig) { + static HelperTextEntity _parseHelperText(String key, HelperTextConfig? textConfig) { return HelperTextEntity( id: textConfig?.id, fontColor: textConfig?.fontColor, diff --git a/lib/src/services/editor/helper/helper_editor_models.dart b/lib/src/services/editor/helper/helper_editor_models.dart index 4e9328f7..ac2fe547 100644 --- a/lib/src/services/editor/helper/helper_editor_models.dart +++ b/lib/src/services/editor/helper/helper_editor_models.dart @@ -9,30 +9,30 @@ import 'package:pal/src/ui/editor/pages/helper_editor/helper_editor_viewmodel.da /// Base helper config ///------------------------------- class CreateHelperConfig { - String id; - String route; - String name; - HelperTriggerType triggerType; - HelperType helperType; //remove - int priority; + String? id; + String? route; + String? name; + HelperTriggerType? triggerType; + HelperType? helperType; //remove + int? priority; CreateHelperConfig({ this.id, - @required this.route, - @required this.name, - @required this.triggerType, - @required this.helperType, + required this.route, + required this.name, + required this.triggerType, + required this.helperType, this.priority, }); - factory CreateHelperConfig.from(String route, HelperViewModel viewModel) => + factory CreateHelperConfig.from(String? route, HelperViewModel viewModel) => CreateHelperConfig( - id: viewModel?.id, + id: viewModel.id, route: route, name: viewModel.name, - triggerType: viewModel?.helperGroup?.triggerType, - helperType: viewModel?.helperType, - priority: viewModel?.priority, + triggerType: viewModel.helperGroup?.triggerType, + helperType: viewModel.helperType, + priority: viewModel.priority, // minVersion: viewModel?.helperGroup?.minVersionCode, // maxVersion: viewModel?.helperGroup?.maxVersionCode, ); @@ -51,11 +51,11 @@ class CreateHelperConfig { /// Helper group related to helper ///------------------------------- class HelperGroupConfig { - String id; - String name; - String minVersion; - String maxVersion; - String triggerType; + String? id; + String? name; + String? minVersion; + String? maxVersion; + String? triggerType; HelperGroupConfig({this.id, this.name, this.minVersion, this.maxVersion, this.triggerType}); @@ -66,11 +66,11 @@ class HelperGroupConfig { } class HelperGroupUpdate { - String id; - String name; - HelperTriggerType type; - int minVersionId; - int maxVersionId; + String? id; + String? name; + HelperTriggerType? type; + int? minVersionId; + int? maxVersionId; HelperGroupUpdate( {this.id, this.name, this.type, this.minVersionId, this.maxVersionId}); @@ -86,11 +86,24 @@ class CreateSimpleHelper { HelperGroupConfig helperGroup; CreateSimpleHelper({ - @required this.config, - @required this.titleText, - @required this.boxConfig, - @required this.helperGroup, + required this.config, + required this.titleText, + required this.boxConfig, + required this.helperGroup, }); + + @visibleForTesting + factory CreateSimpleHelper.empty() => CreateSimpleHelper( + config: CreateHelperConfig( + name: "", + route: "", + helperType: HelperType.ANCHORED_OVERLAYED_HELPER, + triggerType: HelperTriggerType.ON_NEW_UPDATE + ), + titleText: HelperTextConfig.empty(), + boxConfig: HelperBoxConfig(), + helperGroup: HelperGroupConfig(), + ); } ///------------------------------- @@ -98,20 +111,34 @@ class CreateSimpleHelper { ///------------------------------- class CreateFullScreenHelper { CreateHelperConfig config; - HelperTextConfig title, description, positivButton, negativButton; - HelperMediaConfig mediaHeader; + HelperTextConfig? title, description, positivButton, negativButton; + HelperMediaConfig? mediaHeader; HelperBoxConfig bodyBox; HelperGroupConfig helperGroup; CreateFullScreenHelper( - {@required this.config, - @required this.title, - @required this.description, + {required this.config, + required this.title, + required this.description, this.positivButton, this.negativButton, - @required this.bodyBox, + required this.bodyBox, this.mediaHeader, - @required this.helperGroup}); + required this.helperGroup}); + + @visibleForTesting + factory CreateFullScreenHelper.empty() => CreateFullScreenHelper( + config: CreateHelperConfig( + name: "", + route: "", + helperType: HelperType.ANCHORED_OVERLAYED_HELPER, + triggerType: HelperTriggerType.ON_NEW_UPDATE + ), + title: HelperTextConfig.empty(), + description: HelperTextConfig.empty(), + helperGroup: HelperGroupConfig(), + bodyBox: HelperBoxConfig() + ); } ///------------------------------- @@ -119,21 +146,35 @@ class CreateFullScreenHelper { ///------------------------------- class CreateUpdateHelper { CreateHelperConfig config; - HelperTextConfig title, positivButton, negativButton; + HelperTextConfig? title, positivButton, negativButton; List lines; - HelperBoxConfig bodyBox; + HelperBoxConfig? bodyBox; HelperMediaConfig headerMedia; - HelperGroupConfig helperGroup; + HelperGroupConfig? helperGroup; CreateUpdateHelper( - {@required this.config, - @required this.title, - @required this.lines, - @required this.headerMedia, + {required this.config, + required this.title, + required this.lines, + required this.headerMedia, this.positivButton, this.negativButton, this.bodyBox, this.helperGroup}); + + @visibleForTesting + factory CreateUpdateHelper.empty() => CreateUpdateHelper( + config: CreateHelperConfig( + name: "", + route: "", + helperType: HelperType.ANCHORED_OVERLAYED_HELPER, + triggerType: HelperTriggerType.ON_NEW_UPDATE + ), + title: HelperTextConfig.empty(), + headerMedia: HelperMediaConfig(), + lines: [], + helperGroup: HelperGroupConfig(), + ); } ///------------------------------- @@ -141,18 +182,32 @@ class CreateUpdateHelper { ///------------------------------- class CreateAnchoredHelper { CreateHelperConfig config; - HelperTextConfig title, description, positivButton, negativButton; - HelperBoxConfig bodyBox; + HelperTextConfig? title, description, positivButton, negativButton; + HelperBoxConfig? bodyBox; HelperGroupConfig helperGroup; CreateAnchoredHelper( - {@required this.config, + {required this.config, this.title, this.description, this.positivButton, this.negativButton, this.bodyBox, - @required this.helperGroup}); + required this.helperGroup}); + + @visibleForTesting + factory CreateAnchoredHelper.empty() => CreateAnchoredHelper( + config: CreateHelperConfig( + name: "", + route: "", + helperType: HelperType.ANCHORED_OVERLAYED_HELPER, + triggerType: HelperTriggerType.ON_NEW_UPDATE + ), + title: HelperTextConfig.empty(), + description: HelperTextConfig.empty(), + helperGroup: HelperGroupConfig(), + bodyBox: HelperBoxConfig() + ); toJson() => { "config": jsonEncode(config), @@ -169,20 +224,29 @@ class CreateAnchoredHelper { /// use this in helpers with multiple text ///------------------------------- class HelperTextConfig { - int id; - String text; - String fontColor; - String fontWeight; - String fontFamily; - int fontSize; + int? id; + String? text; + String? fontColor; + String? fontWeight; + String? fontFamily; + int? fontSize; HelperTextConfig( {this.id, - @required this.text, - @required this.fontColor, - @required this.fontWeight, - @required this.fontFamily, - @required this.fontSize}); + required this.text, + required this.fontColor, + required this.fontWeight, + required this.fontFamily, + required this.fontSize}); + + @visibleForTesting + factory HelperTextConfig.empty() => HelperTextConfig( + text: "", + fontColor: "", + fontFamily: "", + fontSize: 1, + fontWeight: "" + ); toJson() => { "id": id, @@ -194,8 +258,8 @@ class HelperTextConfig { } class HelperMediaConfig { - int id; - String url; + int? id; + String? url; HelperMediaConfig({ this.id, @@ -204,9 +268,9 @@ class HelperMediaConfig { } class HelperBoxConfig { - int id; - String key; - String color; + int? id; + String? key; + String? color; HelperBoxConfig({ this.id, diff --git a/lib/src/services/editor/helper/helper_editor_service.dart b/lib/src/services/editor/helper/helper_editor_service.dart index 03f178da..e278108a 100644 --- a/lib/src/services/editor/helper/helper_editor_service.dart +++ b/lib/src/services/editor/helper/helper_editor_service.dart @@ -30,24 +30,24 @@ abstract class EditorHelperService { Future> getPage( final String route, final int page, final int pageSize); - Future getHelper(String helperId); + Future getHelper(String? helperId); /// saves a simple helper to our api /// providing [args.config.id] will makes an update - Future saveSimpleHelper(final CreateSimpleHelper args); + Future saveSimpleHelper(final CreateSimpleHelper args); /// saves a fullscreen helper to our api /// providing [args.config.id] will makes an update - Future saveFullScreenHelper( + Future saveFullScreenHelper( final CreateFullScreenHelper createArgs); /// saves an update helper to our api /// providing [args.config.id] will makes an update - Future saveUpdateHelper(final CreateUpdateHelper createArgs); + Future saveUpdateHelper(final CreateUpdateHelper createArgs); /// saves an anchored helper to our api /// providing [args.config.id] will makes an update - Future saveAnchoredWidget( + Future saveAnchoredWidget( final CreateAnchoredHelper createArgs); /// Change helperPriority @@ -71,10 +71,10 @@ class _EditorHelperHttpService implements EditorHelperService { this._versionRepository, this._editorHelperGroupRepository); @override - Future saveSimpleHelper( + Future saveSimpleHelper( final CreateSimpleHelper createArgs) async { var pageId = await _getOrCreatePageId(createArgs.config.route); - String groupId =createArgs.config.id != null ? null : createArgs.helperGroup?.id ?? + String? groupId =createArgs.config.id != null ? null : createArgs.helperGroup.id ?? await _createGroupId(pageId, createArgs.helperGroup); return createArgs.config.id != null ? _editorHelperRepository.updateHelper( @@ -84,53 +84,53 @@ class _EditorHelperHttpService implements EditorHelperService { } @override - Future getHelper(String helperId) { + Future getHelper(String? helperId) { return this._editorHelperRepository.getHelper(helperId); } @override - Future saveFullScreenHelper( + Future saveFullScreenHelper( CreateFullScreenHelper createArgs) async { if (createArgs.title == null || createArgs.description == null || - createArgs.title.text.isEmpty) throw "TITLE_AND_DESCRIPTION_REQUIRED"; + createArgs.title!.text!.isEmpty) throw "TITLE_AND_DESCRIPTION_REQUIRED"; // create page group version var pageId = await _getOrCreatePageId(createArgs.config.route); - String groupId = createArgs.config.id != null ? null : createArgs.helperGroup.id ?? + String? groupId = createArgs.config.id != null ? null : createArgs.helperGroup.id ?? await _createGroupId(pageId, createArgs.helperGroup); // create entity var helperEntity = HelperEditorAdapter.parseFullscreenHelper(createArgs); - helperEntity.helperTexts.removeWhere( - (element) => element.value == null || element.value.isEmpty); + helperEntity.helperTexts!.removeWhere( + (element) => element.value == null || element.value!.isEmpty); return createArgs.config.id != null ? _editorHelperRepository.updateHelper(pageId, helperEntity) : _editorHelperRepository.createHelper(pageId, groupId, helperEntity); } @override - Future saveUpdateHelper(CreateUpdateHelper createArgs) async { + Future saveUpdateHelper(CreateUpdateHelper createArgs) async { var pageId = await _getOrCreatePageId(createArgs.config.route); // create page group version - String groupId =createArgs.config.id != null ? null : createArgs.helperGroup.id ?? - await _createGroupId(pageId, createArgs.helperGroup); + String? groupId =createArgs.config.id != null ? null : createArgs.helperGroup!.id ?? + await _createGroupId(pageId, createArgs.helperGroup!); // create entity var helperEntity = HelperEditorAdapter.parseUpdateHelper(createArgs); - helperEntity.helperTexts.removeWhere( - (element) => element.value == null || element.value.isEmpty); + helperEntity.helperTexts!.removeWhere( + (element) => element.value == null || element.value!.isEmpty); return createArgs.config.id != null ? _editorHelperRepository.updateHelper(pageId, helperEntity) : _editorHelperRepository.createHelper(pageId, groupId, helperEntity); } @override - Future saveAnchoredWidget( + Future saveAnchoredWidget( CreateAnchoredHelper createArgs) async { - if (createArgs.bodyBox.key.isEmpty) { + if (createArgs.bodyBox!.key!.isEmpty) { throw "ANCHOR_KEY_MISSING"; } var pageId = await _getOrCreatePageId(createArgs.config.route); // create page group version - String groupId =createArgs.config.id != null ? null : createArgs.helperGroup.id ?? + String? groupId =createArgs.config.id != null ? null : createArgs.helperGroup.id ?? await _createGroupId(pageId, createArgs.helperGroup); // create entity var helperEntity = HelperEditorAdapter.parseAnchoredHelper(createArgs); @@ -156,7 +156,7 @@ class _EditorHelperHttpService implements EditorHelperService { // PRIVATES // ------------------------------------------------------------ - Future _getOrCreatePageId(String routeName) async { + Future _getOrCreatePageId(String? routeName) async { if (routeName == null || routeName.isEmpty) { final errorMessage = """EMPTY_ROUTE_PROVIDED, maybe you forgot to add an unique name to your route like this: @@ -171,43 +171,42 @@ class _EditorHelperHttpService implements EditorHelperService { """; throw PageCreationException(message: errorMessage); } - PageEntity resPage = await this._pageRepository.getPage(routeName); - if (resPage == null || resPage.id == null || resPage.id.isEmpty) { + PageEntity? resPage = await this._pageRepository.getPage(routeName); + if (resPage == null || resPage.id == null || resPage.id!.isEmpty) { resPage = await this._pageRepository.createPage( PageEntity(route: routeName), ); } - if (resPage?.id != null && resPage.id.length > 0) { - return resPage?.id; + if (resPage.id != null && resPage.id!.length > 0) { + return resPage.id; } else { throw PageCreationException(); } } - Future _getOrCreateVersionId(String versionCode) async { + Future _getOrCreateVersionId(String? versionCode) async { if (versionCode == null || versionCode.isEmpty) { return 0; } - VersionEntity resVersion = - await this._versionRepository.getVersion(name: versionCode); + VersionEntity? resVersion = await this._versionRepository.getVersion(name: versionCode); if (resVersion == null || resVersion.id == null) { - resVersion = await this._versionRepository.createVersion( - VersionEntity(name: versionCode), - ); - } - if (resVersion != null) { - return resVersion.id; - } else { - throw PageCreationException(); + try { + resVersion = await this._versionRepository.createVersion( + VersionEntity(name: versionCode), + ); + } catch(_) { + throw PageCreationException(); + } } + return resVersion.id; } Future _createGroupId( - String pageId, HelperGroupConfig helperGroupConfig) async { - if (helperGroupConfig.name.isEmpty) throw "EMPTY_GROUP_NAME_NOT_ALLOWED"; + String? pageId, HelperGroupConfig helperGroupConfig) async { + if (helperGroupConfig.name!.isEmpty) throw "EMPTY_GROUP_NAME_NOT_ALLOWED"; var minVersionId = await _getOrCreateVersionId(helperGroupConfig.minVersion); - int maxVersionId; + int? maxVersionId; if (helperGroupConfig.minVersion == helperGroupConfig.maxVersion) { maxVersionId = minVersionId; } else if (helperGroupConfig.maxVersion != null) { @@ -216,12 +215,12 @@ class _EditorHelperHttpService implements EditorHelperService { return _editorHelperGroupRepository .create(pageId, helperGroupConfig.name, minVersionId, maxVersionId, helperGroupConfig.triggerType) - .then((value) => value.id); + .then((value) => value.id!); } } class PageCreationException implements Exception { - final String message; + final String? message; PageCreationException({this.message}); @@ -232,7 +231,7 @@ class PageCreationException implements Exception { } class VersionCreationException implements Exception { - final String message; + final String? message; VersionCreationException({this.message}); diff --git a/lib/src/services/editor/page/page_editor_service.dart b/lib/src/services/editor/page/page_editor_service.dart index 3416046d..a742612e 100644 --- a/lib/src/services/editor/page/page_editor_service.dart +++ b/lib/src/services/editor/page/page_editor_service.dart @@ -8,17 +8,17 @@ import 'package:pal/src/database/repository/page_repository.dart'; abstract class PageEditorService { factory PageEditorService.build( - GlobalKey repaintBoundaryKey, PageRepository pageRepository) => + GlobalKey? repaintBoundaryKey, PageRepository pageRepository) => _PageEditorHttpService(repaintBoundaryKey, pageRepository); Future capturePagePreview(); - Future getPage(String route); + Future getPage(String route); Future createPage(PageEntity createPage); - Future getOrCreatePageId(String routeName); + Future getOrCreatePageId(String? routeName); } class _PageEditorHttpService implements PageEditorService { - final GlobalKey _repaintBoundaryKey; + final GlobalKey? _repaintBoundaryKey; final PageRepository _pageRepository; _PageEditorHttpService(this._repaintBoundaryKey, this._pageRepository); @@ -27,22 +27,22 @@ class _PageEditorHttpService implements PageEditorService { Future capturePagePreview({double pixelRatio = 3.0}) async { try { RenderRepaintBoundary boundary = - _repaintBoundaryKey.currentContext.findRenderObject(); + _repaintBoundaryKey!.currentContext!.findRenderObject() as RenderRepaintBoundary; ui.Image image = await boundary.toImage(pixelRatio: pixelRatio); ByteData byteData = - await image.toByteData(format: ui.ImageByteFormat.png); + await (image.toByteData(format: ui.ImageByteFormat.png) as Future); Uint8List data = byteData.buffer.asUint8List(); List dataList = data.toList(); - print(dataList); // TODO: Send with repository using multipart image - } catch (e) { - print('error while catching screenshot'); + } catch (e,s) { + debugPrint('error while catching screenshot'); print(e); + print(s); } } @override - Future getPage(String route) { + Future getPage(String route) { return this._pageRepository.getPage(route); } @@ -52,26 +52,18 @@ class _PageEditorHttpService implements PageEditorService { } @override - Future getOrCreatePageId(String routeName) async { + Future getOrCreatePageId(String? routeName) async { if (routeName == null || routeName.length <= 0) { throw 'invalid route name'; } - - String pageId; - PageEntity resPage = await this.getPage(routeName); - if (resPage?.id != null && resPage.id.length > 0) { - pageId = resPage.id; - } else { - PageEntity resPage = await this.createPage( + PageEntity? resPage = await this.getPage(routeName); + if(resPage == null || resPage.id!.length == 0) { + resPage = await this.createPage( PageEntity(route: routeName), ); - if (resPage?.id != null && resPage.id.length > 0) { - pageId = resPage?.id; - } else { + if(resPage.id == null) throw 'page id is null'; - } - } - - return pageId; + } + return resPage.id; } } diff --git a/lib/src/services/editor/project/app_icon_grabber_delegate.dart b/lib/src/services/editor/project/app_icon_grabber_delegate.dart index 9ed8f593..67e43e20 100644 --- a/lib/src/services/editor/project/app_icon_grabber_delegate.dart +++ b/lib/src/services/editor/project/app_icon_grabber_delegate.dart @@ -1,9 +1,11 @@ import 'dart:typed_data'; -import 'package:application_icon/application_icon.dart'; +// import 'package:application_icon/application_icon.dart'; class AppIconGrabberDelegate { Future getClientAppIcon() async { - return AppIconInfo.getAppIcon(); + // FIXME: Remove this to enable application icon on multiple platforms + return Uint8List(0); + // return AppIconInfo.getAppIcon(); } } diff --git a/lib/src/services/editor/project/project_editor_service.dart b/lib/src/services/editor/project/project_editor_service.dart index 502bc7a5..675f13db 100644 --- a/lib/src/services/editor/project/project_editor_service.dart +++ b/lib/src/services/editor/project/project_editor_service.dart @@ -21,13 +21,13 @@ abstract class ProjectEditorService { Future sendAppIcon(Uint8List icon, String imageType) => throw "not implemented yet"; - Future updateAppIcon(String appIconId, Uint8List icon, String imageType) => throw "not implemented yet"; + Future updateAppIcon(String? appIconId, Uint8List icon, String imageType) => throw "not implemented yet"; Future getAppIcon() => throw "not implemented yet"; - Future> getPageGroups(String routeName) => throw "not implemented yet"; + Future> getPageGroups(String? routeName) => throw "not implemented yet"; - Future> getGroupHelpers(String groupId) => throw "not implemented yet"; + Future> getGroupHelpers(String? groupId) => throw "not implemented yet"; } class ProjectEditorHttpService implements ProjectEditorService { @@ -46,7 +46,7 @@ class ProjectEditorHttpService implements ProjectEditorService { Future sendAppIcon(Uint8List icon, String imageType) => this.projectRepository.createAppIcon( icon, imageType); - Future updateAppIcon(String appIconId, Uint8List icon, String imageType) + Future updateAppIcon(String? appIconId, Uint8List icon, String imageType) => this.projectRepository.updateAppIcon(appIconId, icon, imageType); @override @@ -54,11 +54,11 @@ class ProjectEditorHttpService implements ProjectEditorService { => this.projectRepository.getAppIcon(); @override - Future> getPageGroups(String pageId) + Future> getPageGroups(String? pageId) => editorHelperGroupRepository.listHelperGroups(pageId); @override - Future> getGroupHelpers(String groupId) + Future> getGroupHelpers(String? groupId) => editorHelperRepository.getGroupHelpers(groupId); } diff --git a/lib/src/services/editor/project_gallery/project_gallery_editor_service.dart b/lib/src/services/editor/project_gallery/project_gallery_editor_service.dart index 5b0b36fa..71d5f2bc 100644 --- a/lib/src/services/editor/project_gallery/project_gallery_editor_service.dart +++ b/lib/src/services/editor/project_gallery/project_gallery_editor_service.dart @@ -1,11 +1,10 @@ -import 'package:flutter/cupertino.dart'; import 'package:pal/src/database/entity/graphic_entity.dart'; import 'package:pal/src/database/entity/pageable.dart'; import 'package:pal/src/database/repository/project_gallery_repository.dart'; abstract class ProjectGalleryEditorService { factory ProjectGalleryEditorService.build({ - @required ProjectGalleryRepository projectGalleryRepository, + required ProjectGalleryRepository projectGalleryRepository, }) => ProjectGalleryEditorHttpService(projectGalleryRepository); @@ -19,6 +18,6 @@ class ProjectGalleryEditorHttpService implements ProjectGalleryEditorService { @override Future> getAllMedias(final int page, final int pageSize) { - return this.projectGalleryRepository.getAllMedias(page, pageSize); + return this.projectGalleryRepository.getAllMedias(page, pageSize + 1); } } diff --git a/lib/src/services/editor/versions/version_editor_service.dart b/lib/src/services/editor/versions/version_editor_service.dart index e9c37b73..35dd7aa2 100644 --- a/lib/src/services/editor/versions/version_editor_service.dart +++ b/lib/src/services/editor/versions/version_editor_service.dart @@ -1,24 +1,23 @@ -import 'package:flutter/cupertino.dart'; import 'package:pal/src/database/entity/version_entity.dart'; import 'package:pal/src/database/repository/version_repository.dart'; import 'package:pal/src/services/package_version.dart'; abstract class VersionEditorService { factory VersionEditorService.build( - {@required VersionRepository versionRepository, - @required PackageVersionReader packageVersionReader}) => + {required VersionRepository versionRepository, + required PackageVersionReader packageVersionReader}) => VersionEditorHttpService(versionRepository, packageVersionReader); - Future getCurrentVersion() => throw "not implemented yet"; + Future getCurrentVersion() => throw "not implemented yet"; Future> getAll() => throw "not implemented yet"; - Future getVersion(String name) => throw "not implemented yet"; + Future getVersion(String name) => throw "not implemented yet"; Future createVersion(VersionEntity version) => throw "not implemented yet"; - Future getOrCreateVersionId(String versionName) => + Future getOrCreateVersionId(String versionName) => throw "not implemented yet"; } @@ -29,22 +28,22 @@ class VersionEditorHttpService implements VersionEditorService { VersionEditorHttpService(this.versionRepository, this.packageVersionReader); @override - Future getCurrentVersion() async { + Future getCurrentVersion() async { var currentVersion = packageVersionReader.version; return versionRepository .getVersions(name: currentVersion) - .then((res) => res.numberOfElements > 0 ? res.entities.first : null); + .then((res) => res.numberOfElements! > 0 ? res.entities!.first : null); } @override Future> getAll() { return versionRepository .getVersions(pageSize: 1000) - .then((res) => res.numberOfElements > 0 ? res.entities : []); + .then((res) => res.numberOfElements! > 0 ? res.entities! : []); } @override - Future getVersion(String name) { + Future getVersion(String name) { return versionRepository.getVersion(name: name); } @@ -55,23 +54,19 @@ class VersionEditorHttpService implements VersionEditorService { @override Future getOrCreateVersionId(String versionName) async { - if (versionName == null || versionName.length <= 0) { + if (versionName.length == 0) { throw 'invalid version name'; } - int versionMinId; - VersionEntity resVersion = await this.getVersion(versionName); - if (resVersion?.id != null) { - versionMinId = resVersion.id; - } else { - VersionEntity resVersion = await this.createVersion( - VersionEntity(name: versionName), - ); - if (resVersion?.id != null) { - versionMinId = resVersion?.id; - } else { - throw 'page id is null'; + try { + VersionEntity? resVersion = await this.getVersion(versionName); + if(resVersion == null) { + resVersion = await this.createVersion( + VersionEntity(name: versionName), + ); } + return resVersion.id!; + } catch(_) { + throw 'page id is null'; } - return versionMinId; } } diff --git a/lib/src/services/finder/finder_service.dart b/lib/src/services/finder/finder_service.dart index fa12275d..4e2dda3a 100644 --- a/lib/src/services/finder/finder_service.dart +++ b/lib/src/services/finder/finder_service.dart @@ -8,32 +8,32 @@ import '../../pal_navigator_observer.dart'; class FinderService { - PalNavigatorObserver observer; + PalNavigatorObserver? observer; - FinderService({@required this.observer}); + FinderService({required this.observer}); - Future searchChildElement(String key) async { + Future searchChildElement(String? key) async { var completer = new Completer(); - var currentRoute = await observer.route.first; - if(WidgetsBinding.instance.hasScheduledFrame) { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - ElementModel res = ElementFinder(currentRoute.subtreeContext).searchChildElement(key); + var currentRoute = await observer!.route.first; + if(WidgetsBinding.instance!.hasScheduledFrame) { + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { + ElementModel res = ElementFinder(currentRoute.subtreeContext).searchChildElement(key)!; print("res => ${res.key}"); completer.complete(res); }); } else { - ElementModel res = ElementFinder(currentRoute.subtreeContext).searchChildElement(key); + ElementModel res = ElementFinder(currentRoute.subtreeContext).searchChildElement(key)!; print("res => ${res.key}"); completer.complete(res); } return completer.future; } - Future> scan({Key omitChildsOf, bool debugMode = false}) async { + Future> scan({Key? omitChildsOf, bool debugMode = false}) async { var completer = new Completer>(); - var currentRoute = await observer.route.first; - if(WidgetsBinding.instance.hasScheduledFrame) { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + var currentRoute = await observer!.route.first; + if(WidgetsBinding.instance!.hasScheduledFrame) { + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { completer.complete(ElementFinder(currentRoute.subtreeContext).scan(debugMode: debugMode)); }); } else { @@ -43,7 +43,7 @@ class FinderService { } Future getLargestAvailableSpace(ElementModel element) async { - var currentRoute = await observer.route.first; + var currentRoute = await observer!.route.first; return ElementFinder(currentRoute.subtreeContext).getLargestAvailableSpace(element); } diff --git a/lib/src/services/http_client/adapters/error_adapter.dart b/lib/src/services/http_client/adapters/error_adapter.dart index 2aef1dd3..9048f03f 100644 --- a/lib/src/services/http_client/adapters/error_adapter.dart +++ b/lib/src/services/http_client/adapters/error_adapter.dart @@ -3,8 +3,8 @@ import 'package:pal/src/database/adapter/generic_adapter.dart'; class ErrorAdapter extends GenericEntityAdapter { @override - parseMap(Map map) { - if (map == null && !map.containsValue('message')) { + parseMap(Map? map) { + if (map == null && !map!.containsValue('message')) { return null; } diff --git a/lib/src/services/http_client/base_client.dart b/lib/src/services/http_client/base_client.dart index bda5c098..648653e7 100644 --- a/lib/src/services/http_client/base_client.dart +++ b/lib/src/services/http_client/base_client.dart @@ -23,12 +23,15 @@ class HttpClient extends http.BaseClient implements BaseHttpClient { HttpClient.internal(url, token); @visibleForTesting - HttpClient.internal(final String url, final String token, {http.Client httpClient}) - : assert(url != null && url != ""), - assert(token != null && token != ""), - this._baseUrl = url, + HttpClient.internal(final String url, final String token, {http.Client? httpClient, bool testMode = false}) + : this._baseUrl = url, this._client = httpClient ?? new http.Client(), - this._token = token; + this._token = token { + if(!testMode) { + assert(url.isNotEmpty); + assert(token.isNotEmpty); + } + } @override Future send(final http.BaseRequest request) async { @@ -40,11 +43,11 @@ class HttpClient extends http.BaseClient implements BaseHttpClient { if (response.statusCode >= 200 && response.statusCode < 300) { return response; } else if (response.statusCode >= 400 && response.statusCode < 500) { - String errorCode; + String? errorCode; try { errorCode = ErrorAdapter().parse(response.body); } catch(_) {} - throw UnreachableHttpError('Http ${response.statusCode} error, network or bad gateway : ${response?.request?.url}', + throw UnreachableHttpError('Http ${response.statusCode} error, network or bad gateway : ${response.request?.url}', code: errorCode); } else if (response.statusCode >= 500 && response.statusCode < 600) { debugPrint("... ==> 500 error ${response.body}"); @@ -57,9 +60,9 @@ class HttpClient extends http.BaseClient implements BaseHttpClient { @override Future post(final url, - {Map headers, + {Map? headers, final body, - final Encoding encoding}) async { + final Encoding? encoding}) async { headers = _initHeader(headers); return this._checkResponse( await super.post( @@ -74,9 +77,9 @@ class HttpClient extends http.BaseClient implements BaseHttpClient { @override Future delete( final Uri url, - { final Map headers, + { final Map? headers, final body, - final Encoding encoding + final Encoding? encoding } ) async { return this._checkResponse( @@ -85,9 +88,9 @@ class HttpClient extends http.BaseClient implements BaseHttpClient { @override Future put(final url, - {Map headers, + {Map? headers, final body, - final Encoding encoding}) async { + final Encoding? encoding}) async { headers = _initHeader(headers); var res = await super.put(Uri.parse('${this._baseUrl}/$url'), headers: headers, @@ -98,15 +101,15 @@ class HttpClient extends http.BaseClient implements BaseHttpClient { @override Future patch(final url, - {Map headers, + {Map? headers, final body, - final Encoding encoding}) async { + final Encoding? encoding}) async { headers = _initHeader(headers); return this._checkResponse(await super.patch(Uri.parse('${this._baseUrl}/$url'), headers: headers, body: body, encoding: encoding)); } - Map _initHeader(Map headers) { + Map _initHeader(Map? headers) { if (headers == null) { headers = new Map(); } @@ -116,18 +119,18 @@ class HttpClient extends http.BaseClient implements BaseHttpClient { } @override - Future get(final url, {final Map headers}) async { + Future get(final url, {final Map? headers}) async { return this._checkResponse( - await super.get(Uri.parse('${this._baseUrl}/$url'), headers: headers)); + await super.get(Uri.parse('${this._baseUrl}/$url'), headers: headers as Map?)); } Future multipartImage(url, - {Map fields, - Map headers, - List fileData, - String imageType, - String filename, - String fileFieldName, + {Map? fields, + Map? headers, + required List fileData, + String? imageType, + String? filename, + required String fileFieldName, String httpMethod = "POST"}) async { var request = new http.MultipartRequest( httpMethod, Uri.parse('${this._baseUrl}/$url')); @@ -163,7 +166,7 @@ class InternalHttpError implements Exception { class UnreachableHttpError implements Exception { String message; - String code; + String? code; UnreachableHttpError(this.message, {this.code}); diff --git a/lib/src/services/local_storage/local_storage_manager.dart b/lib/src/services/local_storage/local_storage_manager.dart deleted file mode 100644 index 5a4a808b..00000000 --- a/lib/src/services/local_storage/local_storage_manager.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'dart:io'; - -import 'package:path_provider/path_provider.dart'; - -abstract class StorageManager { - Future store(String value); - - Future read(); - - Future deleteFile(); -} - -/// use this implementation for a mock test -class MockStorageManager implements StorageManager { - String _value = ''; - - @override - Future read() => Future.value(this._value); - - @override - Future store(String value) { - return Future(() { - this._value = value; - }); - } - - @override - Future deleteFile() { - throw Future.value(); - } -} - -/// store a file on local app storage folder -class LocalStorageManager implements StorageManager { - final String _filename; - - LocalStorageManager(this._filename); - - @override - Future store(String value) async { - await deleteFile() - .then((res) => getLocalFile()) - .then((file) => file.writeAsString(value, flush: true)); - } - - @override - Future read() { - return getLocalFile().then((file) => file.readAsStringSync()); - } - - Future getLocalFile() async { - return getApplicationDocumentsDirectory().then((path) { - String finalPath = path.path + '/' + this._filename; - return File(finalPath).exists().then((bool) { - if (bool) { - return File(finalPath); - } else { - return File(finalPath).create().then((file) { - return file; - }); - } - }); - }); - } - - Future deleteFile() async { - try { - File file = await getLocalFile(); - var exists = await file.exists(); - if (exists) { - await file.delete(); - } - } catch (e) { - print("error while delete file : $e "); - } - } -} diff --git a/lib/src/services/locale_service/locale_service.dart b/lib/src/services/locale_service/locale_service.dart index 0026a1f1..478d1844 100644 --- a/lib/src/services/locale_service/locale_service.dart +++ b/lib/src/services/locale_service/locale_service.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; class LocaleService { - final GlobalKey hostedKey; - final Locale defaultLocale; + final GlobalKey? hostedKey; + final Locale? defaultLocale; LocaleService({this.hostedKey, this.defaultLocale}); Locale get locale => - defaultLocale ?? Localizations.localeOf(hostedKey.currentContext); + defaultLocale ?? Localizations.localeOf(hostedKey!.currentContext!); String get languageCode => locale.languageCode; } diff --git a/lib/src/services/package_version.dart b/lib/src/services/package_version.dart index eed2701c..d7e31888 100644 --- a/lib/src/services/package_version.dart +++ b/lib/src/services/package_version.dart @@ -1,9 +1,8 @@ -import 'package:package_info/package_info.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'package:pal/src/services/client/versions/version.dart'; class PackageVersionReader { - - PackageInfo info; + late PackageInfo info; PackageVersionReader() { init(); diff --git a/lib/src/services/pal/pal_state_service.dart b/lib/src/services/pal/pal_state_service.dart index e183ffb8..3c683225 100644 --- a/lib/src/services/pal/pal_state_service.dart +++ b/lib/src/services/pal/pal_state_service.dart @@ -9,9 +9,9 @@ abstract class PalEditModeStateService { /// returns whether or not we show the [BubbleOverlayButton] above the user app ValueNotifier get showEditorBubble => throw "not implemented yet"; - showBubble(BuildContext context, bool show) => throw "not implemented yet"; + showBubble(BuildContext? context, bool show) => throw "not implemented yet"; - showHelpersList(BuildContext context) => throw "not implemented yet"; + showHelpersList(BuildContext? context) => throw "not implemented yet"; } class _PalEditModeStateService implements PalEditModeStateService { @@ -22,12 +22,12 @@ class _PalEditModeStateService implements PalEditModeStateService { ValueNotifier get showEditorBubble => _showEditorBubbleNotifier; @override - showBubble(BuildContext context, bool show) { + showBubble(BuildContext? context, bool show) { ShowBubbleNotification(show).dispatch(context); } @override - showHelpersList(BuildContext context) { + showHelpersList(BuildContext? context) { ShowHelpersListNotification().dispatch(context); } diff --git a/lib/src/theme.dart b/lib/src/theme.dart index efaabdbf..57b068dc 100644 --- a/lib/src/theme.dart +++ b/lib/src/theme.dart @@ -32,21 +32,21 @@ class _PalThemeLightColors { } class _PalThemeColors { - final Color dark; + final Color? dark; - final Color black; + final Color? black; - final Color green; + final Color? green; - final Color color1, color2, color3, color4, color5; + final Color? color1, color2, color3, color4, color5; - final Color accent; + final Color? accent; - final Color light; + final Color? light; - final Gradient bottomNavEditorGradient; + final Gradient? bottomNavEditorGradient; - final Gradient settingsSilverGradient; + final Gradient? settingsSilverGradient; const _PalThemeColors._({ this.dark, @@ -82,17 +82,17 @@ class _PalThemeColors { /// use this to let all app get our custom theme from context /// we have more colors than pure material class PalTheme extends InheritedWidget { - final PalThemeData theme; + final PalThemeData? theme; PalTheme({ this.theme, - Key key, - @required Widget child, + Key? key, + required Widget child, }) : assert(child != null), super(key: key, child: child); - static PalThemeData of(BuildContext context) => - context.dependOnInheritedWidgetOfExactType().theme; + static PalThemeData? of(BuildContext context) => + context.dependOnInheritedWidgetOfExactType()!.theme; @override bool updateShouldNotify(PalTheme old) { @@ -101,7 +101,7 @@ class PalTheme extends InheritedWidget { } class PalThemeData { - _PalThemeColors colors; + late _PalThemeColors colors; PalThemeData._(_PalThemeColors colors) { this.colors = colors; @@ -135,10 +135,10 @@ class PalThemeData { inputDecorationTheme: InputDecorationTheme( labelStyle: TextStyle(color: colors.color1), helperStyle: TextStyle(color: colors.color1), - hintStyle: TextStyle(color: colors.dark.withAlpha(60)), + hintStyle: TextStyle(color: colors.dark!.withAlpha(60)), enabledBorder: OutlineInputBorder( borderSide: BorderSide( - color: colors.color1, + color: colors.color1!, ), ), ), @@ -155,17 +155,17 @@ class PalThemeData { ); } - Gradient get bottomNavEditorGradient => colors.bottomNavEditorGradient; + Gradient? get bottomNavEditorGradient => colors.bottomNavEditorGradient; - Gradient get settingsSilverGradient => colors.settingsSilverGradient; + Gradient? get settingsSilverGradient => colors.settingsSilverGradient; - Color get highlightColor => colors.color4; + Color? get highlightColor => colors.color4; - Color get toolbarBackgroundColor => colors.color5; + Color? get toolbarBackgroundColor => colors.color5; - Color get floatingBubbleBackgroundColor => colors.color1; + Color? get floatingBubbleBackgroundColor => colors.color1; - Color get simpleHelperBackgroundColor => colors.black; + Color? get simpleHelperBackgroundColor => colors.black; Color get simpleHelperFontColor => Color(0xFFFAFEFF); } diff --git a/lib/src/ui/client/helper_factory.dart b/lib/src/ui/client/helper_factory.dart index 72ac8010..45490d33 100644 --- a/lib/src/ui/client/helper_factory.dart +++ b/lib/src/ui/client/helper_factory.dart @@ -12,9 +12,9 @@ import 'helpers/simple_helper/widget/simple_helper_layout.dart'; import 'helpers/user_anchored_helper/anchored_helper_widget.dart'; class HelperFactory { - static Widget build(final HelperEntity helper, - {final Function(bool positiveFeedBack) onTrigger, - final Function onError}) { + static Widget? build(final HelperEntity helper, + {final Function(bool positiveFeedBack)? onTrigger, + final Function? onError}) { switch (helper.type) { case HelperType.HELPER_FULL_SCREEN: return _createHelperFullScreen(helper, onTrigger); @@ -24,41 +24,42 @@ class HelperFactory { return _createUpdateHelper(helper, onTrigger); case HelperType.ANCHORED_OVERLAYED_HELPER: return _createAnchoredHelper(helper, onTrigger, onError); + case null: + return null; } - return null; } static Widget _createHelperFullScreen( final HelperEntity helper, - final Function onTrigger, + final Function? onTrigger, ) { return UserFullScreenHelperPage( titleLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.TITLE_KEY, - helper.helperTexts, - ), + helper.helperTexts!, + )!, descriptionLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.DESCRIPTION_KEY, - helper.helperTexts, - ), + helper.helperTexts!, + )!, headerImageViewModel: HelperSharedFactory.parseImageUrl( FullscreenHelperKeys.IMAGE_KEY, helper.helperImages, ), helperBoxViewModel: HelperSharedFactory.parseBoxBackground( FullscreenHelperKeys.BACKGROUND_KEY, - helper.helperBoxes, - ), + helper.helperBoxes!, + )!, positivLabel: HelperSharedFactory.parseButtonLabel( FullscreenHelperKeys.POSITIV_KEY, - helper.helperTexts, + helper.helperTexts!, ), negativLabel: HelperSharedFactory.parseButtonLabel( FullscreenHelperKeys.NEGATIV_KEY, - helper.helperTexts, + helper.helperTexts!, ), - onPositivButtonTap: () => onTrigger(true), - onNegativButtonTap: () => onTrigger(false), + onPositivButtonTap: () => onTrigger!(true), + onNegativButtonTap: () => onTrigger!(false), ); } @@ -118,7 +119,7 @@ class HelperFactory { static Widget _createSimpleHelper( final HelperEntity helper, - final Function onTrigger, + final Function? onTrigger, ) { GlobalKey _simpleHelperLayoutKey = GlobalKey(); return SimpleHelperLayout( @@ -126,41 +127,41 @@ class HelperFactory { toaster: SimpleHelperPage( descriptionLabel: HelperSharedFactory.parseTextLabel( SimpleHelperKeys.CONTENT_KEY, - helper.helperTexts, - ), + helper.helperTexts!, + )!, // helperBoxViewModel: HelperSharedFactory.parseBoxBackground( // SimpleHelperKeys.BACKGROUND_KEY, // helper.helperBoxes, // ), ), onDismissed: (res) async { - await _simpleHelperLayoutKey.currentState.reverseAnimations(); - onTrigger(res == DismissDirection.startToEnd); + await _simpleHelperLayoutKey.currentState!.reverseAnimations(); + onTrigger!(res == DismissDirection.startToEnd); }, ); } static Widget _createUpdateHelper( - final HelperEntity helper, final Function onTrigger) { + final HelperEntity helper, final Function? onTrigger) { return UserUpdateHelperPage( onPositivButtonTap: () { - onTrigger(true); + onTrigger!(true); }, helperBoxViewModel: HelperSharedFactory.parseBoxBackground( UpdatescreenHelperKeys.BACKGROUND_KEY, - helper.helperBoxes, - ), + helper.helperBoxes!, + )!, thanksButtonLabel: HelperSharedFactory.parseButtonLabel( UpdatescreenHelperKeys.POSITIV_KEY, - helper.helperTexts, + helper.helperTexts!, ), titleLabel: HelperSharedFactory.parseTextLabel( UpdatescreenHelperKeys.TITLE_KEY, - helper.helperTexts, - ), + helper.helperTexts!, + )!, changelogLabels: HelperSharedFactory.parseTextsLabel( UpdatescreenHelperKeys.LINES_KEY, - helper.helperTexts, + helper.helperTexts!, ), helperImageViewModel: HelperSharedFactory.parseImageUrl( UpdatescreenHelperKeys.IMAGE_KEY, @@ -170,32 +171,32 @@ class HelperFactory { } static Widget _createAnchoredHelper(final HelperEntity helper, - final Function onTrigger, final Function onError) { + final Function? onTrigger, final Function? onError) { return AnchoredHelper.fromEntity( titleLabel: HelperSharedFactory.parseTextLabel( AnchoredscreenHelperKeys.TITLE_KEY, - helper.helperTexts, + helper.helperTexts!, ), descriptionLabel: HelperSharedFactory.parseTextLabel( AnchoredscreenHelperKeys.DESCRIPTION_KEY, - helper.helperTexts, + helper.helperTexts!, ), helperBoxViewModel: HelperBoxViewModel( backgroundColor: - HexColor.fromHex(helper.helperBoxes.first.backgroundColor), - id: helper.helperBoxes.first.id, + HexColor.fromHex(helper.helperBoxes!.first.backgroundColor!), + id: helper.helperBoxes!.first.id, ), - anchorKey: helper.helperBoxes.first.key, + anchorKey: helper.helperBoxes!.first.key, positivButtonLabel: HelperSharedFactory.parseButtonLabel( AnchoredscreenHelperKeys.POSITIV_KEY, - helper.helperTexts, + helper.helperTexts!, ), negativButtonLabel: HelperSharedFactory.parseButtonLabel( AnchoredscreenHelperKeys.NEGATIV_KEY, - helper.helperTexts, + helper.helperTexts!, ), - onPositivButtonTap: () => onTrigger(true), - onNegativButtonTap: () => onTrigger(false), + onPositivButtonTap: () => onTrigger!(true), + onNegativButtonTap: () => onTrigger!(false), onError: onError, ); } diff --git a/lib/src/ui/client/helper_orchestrator.dart b/lib/src/ui/client/helper_orchestrator.dart index 13f5ec50..36ca1641 100644 --- a/lib/src/ui/client/helper_orchestrator.dart +++ b/lib/src/ui/client/helper_orchestrator.dart @@ -18,7 +18,7 @@ typedef OnTriggeredHelper = Future Function(bool userPositivFeedback); /// There is a variety of Helper types. class HelperOrchestrator { - static HelperOrchestrator _instance; + static HelperOrchestrator? _instance; final PalRouteObserver routeObserver; @@ -26,45 +26,45 @@ class HelperOrchestrator { final InAppUserClientService inAppUserClientService; - final GlobalKey navigatorKey; + final GlobalKey? navigatorKey; - final HelpersSynchronizer helpersSynchronizer; + final HelpersSynchronizer? helpersSynchronizer; - final PackageVersionReader packageVersionReader; + final PackageVersionReader? packageVersionReader; - OverlayEntry overlay; + OverlayEntry? overlay; - bool hasSync; + late bool hasSync; factory HelperOrchestrator.getInstance({ - GlobalKey navigatorKey, - PalRouteObserver routeObserver, - HelperClientService helperClientService, - InAppUserClientService inAppUserClientService, - HelpersSynchronizer helpersSynchronizer, - PackageVersionReader packageVersionReader, + GlobalKey? navigatorKey, + PalRouteObserver? routeObserver, + HelperClientService? helperClientService, + InAppUserClientService? inAppUserClientService, + HelpersSynchronizer? helpersSynchronizer, + PackageVersionReader? packageVersionReader, }) { if (_instance == null) { _instance = HelperOrchestrator._( - routeObserver, - helperClientService, - inAppUserClientService, + routeObserver!, + helperClientService!, + inAppUserClientService!, navigatorKey, helpersSynchronizer, packageVersionReader ); } - return _instance; + return _instance!; } @visibleForTesting factory HelperOrchestrator.create({ - GlobalKey navigatorKey, - PalRouteObserver routeObserver, - HelperClientService helperClientService, - InAppUserClientService inAppUserClientService, - HelpersSynchronizer helpersSynchronizer, - @required PackageVersionReader packageVersionReader, + GlobalKey? navigatorKey, + required PalRouteObserver routeObserver, + required HelperClientService helperClientService, + required InAppUserClientService inAppUserClientService, + HelpersSynchronizer? helpersSynchronizer, + required PackageVersionReader packageVersionReader, }) { _instance = HelperOrchestrator._( routeObserver, @@ -74,7 +74,7 @@ class HelperOrchestrator { helpersSynchronizer, packageVersionReader ); - return _instance; + return _instance!; } HelperOrchestrator._( @@ -97,25 +97,25 @@ class HelperOrchestrator { } @visibleForTesting - onChangePage(final String route) async { + onChangePage(final String? route) async { if (overlay != null) { popHelper(); } try { final InAppUserEntity inAppUser = await this.inAppUserClientService.getOrCreate(); if(!hasSync) { - var lang = Localizations.localeOf(navigatorKey.currentContext).languageCode; - await this.helpersSynchronizer.sync(inAppUser.id, languageCode: lang); + var lang = Localizations.localeOf(navigatorKey!.currentContext!).languageCode; + await this.helpersSynchronizer!.sync(inAppUser.id, languageCode: lang); this.hasSync = true; } final helperGroupToShow = await helperClientService.getPageNextHelper( route, inAppUser.id, - packageVersionReader.appVersion + packageVersionReader!.appVersion ); - if (helperGroupToShow != null && helperGroupToShow.helpers.isNotEmpty) { + if (helperGroupToShow != null && helperGroupToShow.helpers!.isNotEmpty) { showHelper( - helperGroupToShow.page.id, + helperGroupToShow.page!.id, inAppUser.id, helperGroupToShow, 0); @@ -128,7 +128,7 @@ class HelperOrchestrator { bool popHelper() { if (overlay != null) { - overlay.remove(); + overlay!.remove(); overlay = null; return true; } @@ -137,8 +137,8 @@ class HelperOrchestrator { @visibleForTesting showHelper( - final String pageId, - final String userId, + final String? pageId, + final String? userId, final HelperGroupEntity helperGroupEntity, final int helperIndex) { var onTriggeredHelper = _buildTriggeredHelperAction( @@ -151,37 +151,37 @@ class HelperOrchestrator { builder: (context) => PalTheme( theme: PalThemeData.light(), child: HelperFactory.build( - helperGroupEntity.helpers[helperIndex], + helperGroupEntity.helpers![helperIndex], onTrigger: onTriggeredHelper, onError: this.popHelper - ), + )!, )); - var overlay = navigatorKey.currentState.overlay; + var overlay = navigatorKey!.currentState!.overlay!; // If there is already an helper, remove it and show the next one (useful when we change page fastly) if (this.overlay != null) { - this.overlay.remove(); + this.overlay!.remove(); } overlay.insert(entry); this.overlay = entry; } OnTriggeredHelper _buildTriggeredHelperAction( - String pageId, - String userId, + String? pageId, + String? userId, HelperGroupEntity helperGroupEntity, int helperIndex, ) { return (positivAnswer) async { - final appversion = packageVersionReader.version; + final appversion = packageVersionReader!.version; await helperClientService.onHelperTrigger( pageId, helperGroupEntity, - helperGroupEntity.helpers[helperIndex], + helperGroupEntity.helpers![helperIndex], userId, positivAnswer, appversion); this.popHelper(); - if(positivAnswer && helperIndex < helperGroupEntity.helpers.length - 1 ) { + if(positivAnswer && helperIndex < helperGroupEntity.helpers!.length - 1 ) { showHelper(pageId, userId, helperGroupEntity, helperIndex + 1); } }; diff --git a/lib/src/ui/client/helpers/simple_helper/simple_helper.dart b/lib/src/ui/client/helpers/simple_helper/simple_helper.dart index 164c87f7..c2ac6785 100644 --- a/lib/src/ui/client/helpers/simple_helper/simple_helper.dart +++ b/lib/src/ui/client/helpers/simple_helper/simple_helper.dart @@ -13,13 +13,13 @@ abstract class SimpleHelperView {} class SimpleHelperPage extends StatelessWidget implements SimpleHelperView { final HelperTextViewModel descriptionLabel; - final HelperBoxViewModel helperBoxViewModel; + final HelperBoxViewModel? helperBoxViewModel; SimpleHelperPage({ - Key key, - @required this.descriptionLabel, + Key? key, + required this.descriptionLabel, this.helperBoxViewModel, - }) : assert(descriptionLabel != null); + }); final _mvvmPageBuilder = MVVMPageBuilder(); @@ -33,14 +33,14 @@ class SimpleHelperPage extends StatelessWidget implements SimpleHelperView { builder: (mvvmContext, presenter, model) { final Animation offsetAnimation = Tween(begin: 0.0, end: 20.0) .chain(CurveTween(curve: Curves.elasticIn)) - .animate(mvvmContext.animationsControllers[2]); + .animate(mvvmContext.animationsControllers![2]); return AnimatedTranslateWidget( position: Tween( begin: Offset(0.0, 1.0), end: Offset(0.0, 0.0), ), - animationController: mvvmContext.animationsControllers[0], + animationController: mvvmContext.animationsControllers![0], widget: SafeArea( child: Column( children: [ @@ -52,7 +52,7 @@ class SimpleHelperPage extends StatelessWidget implements SimpleHelperView { child: Container( width: MediaQuery.of(context).size.width, decoration: BoxDecoration( - color: PalTheme.of(context).colors.black, //this.helperBoxViewModel?.backgroundColor, + color: PalTheme.of(context)!.colors.black, //this.helperBoxViewModel?.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(8.0)), boxShadow: [ @@ -122,20 +122,20 @@ class SimpleHelperPage extends StatelessWidget implements SimpleHelperView { }, animListener: (context, presenter, model) { if (model.boxTransitionAnimation) { - context.animationsControllers[0].forward().then( + context.animationsControllers![0].forward().then( (value) => presenter.onBoxAnimationEnd(), ); } if (model.thumbAnimation) { - context.animationsControllers[1].repeat(reverse: true).then( + context.animationsControllers![1].repeat(reverse: true).then( (value) => presenter.onThumbAnimationEnd(), ); } if (model.shakeAnimation) { - context.animationsControllers[2].forward().then( + context.animationsControllers![2].forward().then( (value) { presenter.onShakeAnimationEnd(); - context.animationsControllers[2].reverse(); + context.animationsControllers![2].reverse(); }, ); } @@ -184,7 +184,7 @@ class SimpleHelperPage extends StatelessWidget implements SimpleHelperView { Padding( padding: const EdgeInsets.only(top: 4.0), child: Text( - descriptionLabel?.text ?? '', + descriptionLabel.text ?? '', key: ValueKey('SimpleHelperContentText'), textAlign: TextAlign.center, style: TextStyle( @@ -193,7 +193,7 @@ class SimpleHelperPage extends StatelessWidget implements SimpleHelperView { fontWeight: descriptionLabel.fontWeight ?? FontWeight.normal, ).merge( GoogleFonts.getFont( - descriptionLabel?.fontFamily ?? 'Montserrat'), + descriptionLabel.fontFamily ?? 'Montserrat'), ), maxLines: 10, ), diff --git a/lib/src/ui/client/helpers/simple_helper/simple_helper_viewmodel.dart b/lib/src/ui/client/helpers/simple_helper/simple_helper_viewmodel.dart index 8f35be5f..f97ba2e3 100644 --- a/lib/src/ui/client/helpers/simple_helper/simple_helper_viewmodel.dart +++ b/lib/src/ui/client/helpers/simple_helper/simple_helper_viewmodel.dart @@ -3,8 +3,8 @@ import 'dart:async'; import 'package:mvvm_builder/mvvm_builder.dart'; class SimpleHelperModel extends MVVMModel { - bool thumbAnimation; - bool boxTransitionAnimation; - bool shakeAnimation; - Timer shakeAnimationTimer; + late bool thumbAnimation; + late bool boxTransitionAnimation; + late bool shakeAnimation; + Timer? shakeAnimationTimer; } \ No newline at end of file diff --git a/lib/src/ui/client/helpers/simple_helper/widget/simple_helper_layout.dart b/lib/src/ui/client/helpers/simple_helper/widget/simple_helper_layout.dart index 7b83b29c..c6844b97 100644 --- a/lib/src/ui/client/helpers/simple_helper/widget/simple_helper_layout.dart +++ b/lib/src/ui/client/helpers/simple_helper/widget/simple_helper_layout.dart @@ -4,10 +4,10 @@ import 'package:flutter/services.dart'; import 'package:pal/src/ui/client/helpers/simple_helper/simple_helper.dart'; class SimpleHelperLayout extends StatefulWidget { - final SimpleHelperPage toaster; - final DismissDirectionCallback onDismissed; + final SimpleHelperPage? toaster; + final DismissDirectionCallback? onDismissed; - SimpleHelperLayout({this.toaster, this.onDismissed, Key key}) + SimpleHelperLayout({this.toaster, this.onDismissed, Key? key}) : super(key: key); @override @@ -118,7 +118,7 @@ class SimpleHelperLayoutState extends State shadowColor: Colors.transparent, child: Dismissible( key: ValueKey("toaster"), - child: widget.toaster, + child: widget.toaster!, onDismissed: (DismissDirection direction) { if (widget.onDismissed != null) { switch (direction) { @@ -131,7 +131,7 @@ class SimpleHelperLayoutState extends State default: } - widget.onDismissed(direction); + widget.onDismissed!(direction); } }, ), diff --git a/lib/src/ui/client/helpers/user_anchored_helper/anchored_helper_model.dart b/lib/src/ui/client/helpers/user_anchored_helper/anchored_helper_model.dart index 001cbb98..3de38acd 100644 --- a/lib/src/ui/client/helpers/user_anchored_helper/anchored_helper_model.dart +++ b/lib/src/ui/client/helpers/user_anchored_helper/anchored_helper_model.dart @@ -6,13 +6,13 @@ import 'package:pal/src/ui/shared/helper_shared_viewmodels.dart'; class AnchoredHelperModel { - final HelperTextViewModel title; - final HelperTextViewModel description; - final HelperTextViewModel positivBtn; - final HelperTextViewModel negativBtn; + final HelperTextViewModel? title; + final HelperTextViewModel? description; + final HelperTextViewModel? positivBtn; + final HelperTextViewModel? negativBtn; - final Color bgColor; - final String anchorKey; + final Color? bgColor; + final String? anchorKey; AnchoredHelperModel._({ this.title, this.description, @@ -22,12 +22,12 @@ class AnchoredHelperModel { factory AnchoredHelperModel.fromEntity(HelperEntity entity) => AnchoredHelperModel._( - title: HelperSharedFactory.parseTextLabel(AnchoredscreenHelperKeys.TITLE_KEY, entity.helperTexts), - description: HelperSharedFactory.parseTextLabel(AnchoredscreenHelperKeys.DESCRIPTION_KEY, entity.helperTexts), - positivBtn: HelperSharedFactory.parseTextLabel(AnchoredscreenHelperKeys.POSITIV_KEY, entity.helperTexts), - negativBtn: HelperSharedFactory.parseTextLabel(AnchoredscreenHelperKeys.NEGATIV_KEY, entity.helperTexts), - bgColor: HexColor.fromHex(entity.helperBoxes.first.backgroundColor), - anchorKey: entity.helperBoxes.first.key + title: HelperSharedFactory.parseTextLabel(AnchoredscreenHelperKeys.TITLE_KEY, entity.helperTexts!), + description: HelperSharedFactory.parseTextLabel(AnchoredscreenHelperKeys.DESCRIPTION_KEY, entity.helperTexts!), + positivBtn: HelperSharedFactory.parseTextLabel(AnchoredscreenHelperKeys.POSITIV_KEY, entity.helperTexts!), + negativBtn: HelperSharedFactory.parseTextLabel(AnchoredscreenHelperKeys.NEGATIV_KEY, entity.helperTexts!), + bgColor: HexColor.fromHex(entity.helperBoxes!.first.backgroundColor!), + anchorKey: entity.helperBoxes!.first.key ); diff --git a/lib/src/ui/client/helpers/user_anchored_helper/anchored_helper_widget.dart b/lib/src/ui/client/helpers/user_anchored_helper/anchored_helper_widget.dart index b05befd2..93410140 100644 --- a/lib/src/ui/client/helpers/user_anchored_helper/anchored_helper_widget.dart +++ b/lib/src/ui/client/helpers/user_anchored_helper/anchored_helper_widget.dart @@ -10,32 +10,32 @@ import 'package:pal/src/ui/shared/helper_shared_viewmodels.dart'; class AnchoredHelper extends StatefulWidget { - final String anchorKey; - final bool isTestingMode; + final String? anchorKey; + final bool? isTestingMode; - final FinderService finderService; + final FinderService? finderService; - final Function onPositivButtonTap, onNegativButtonTap, onError; + final Function? onPositivButtonTap, onNegativButtonTap, onError; // ATTRIBUTES MODELS - final HelperTextViewModel titleLabel; - final HelperTextViewModel descriptionLabel; - final HelperButtonViewModel positivButtonLabel; - final HelperButtonViewModel negativButtonLabel; + final HelperTextViewModel? titleLabel; + final HelperTextViewModel? descriptionLabel; + final HelperButtonViewModel? positivButtonLabel; + final HelperButtonViewModel? negativButtonLabel; final HelperBoxViewModel helperBoxViewModel; factory AnchoredHelper.fromEntity({ - FinderService finderService, - String anchorKey, - @required HelperTextViewModel titleLabel, - @required HelperTextViewModel descriptionLabel, - @required HelperButtonViewModel positivButtonLabel, - @required HelperButtonViewModel negativButtonLabel, - @required HelperBoxViewModel helperBoxViewModel, - Function onPositivButtonTap, - Function onNegativButtonTap, - Function onError, - bool isTestingMode = false, + FinderService? finderService, + String? anchorKey, + required HelperTextViewModel? titleLabel, + required HelperTextViewModel? descriptionLabel, + required HelperButtonViewModel? positivButtonLabel, + required HelperButtonViewModel? negativButtonLabel, + required HelperBoxViewModel helperBoxViewModel, + Function? onPositivButtonTap, + Function? onNegativButtonTap, + Function? onError, + bool? isTestingMode = false, }) => AnchoredHelper( finderService, @@ -70,26 +70,25 @@ class AnchoredHelper extends StatefulWidget { class _AnchoredHelperState extends State with TickerProviderStateMixin { - Offset currentPos; + Offset? currentPos; - Size anchorSize; + Size? anchorSize; - Rect writeArea; + Rect? writeArea; - FinderService finderService; + late FinderService finderService; - AnimationController anchorAnimationController, fadeAnimController; + late AnimationController anchorAnimationController, fadeAnimController; - Animation backgroundAnimation; - Animation titleOpacityAnimation, titleSizeAnimation; - Animation descriptionOpacityAnimation, descriptionSizeAnimation; - Animation btnOpacityAnimation, btnSizeAnimation; + late Animation backgroundAnimation; + Animation? titleOpacityAnimation, titleSizeAnimation; + Animation? descriptionOpacityAnimation, descriptionSizeAnimation; + Animation? btnOpacityAnimation, btnSizeAnimation; @override void initState() { super.initState(); - anchorAnimationController = - AnimationController(vsync: this, duration: Duration(seconds: 1)) + anchorAnimationController = AnimationController(vsync: this, duration: Duration(seconds: 1)) ..repeat(reverse: true); fadeAnimController = AnimationController( vsync: this, duration: Duration(milliseconds: 2000)); @@ -121,13 +120,13 @@ class _AnchoredHelperState extends State parent: fadeAnimController, curve: Interval(.8, 1, curve: Curves.easeInOutBack), ); - WidgetsBinding.instance.addPostFrameCallback((_) => init()); + WidgetsBinding.instance!.addPostFrameCallback((_) => init()); } @override void didChangeDependencies() { finderService = - widget.finderService ?? UserInjector.of(context).finderService; + widget.finderService ?? UserInjector.of(context)!.finderService; super.didChangeDependencies(); } @@ -151,10 +150,10 @@ class _AnchoredHelperState extends State } else { var element = await finderService.searchChildElement(widget.anchorKey); if (element == null || element.bounds == null) { - widget.onError(); + widget.onError!(); return; } - anchorSize = element.bounds.size; + anchorSize = element.bounds!.size; currentPos = element.offset; writeArea = await finderService.getLargestAvailableSpace(element); } @@ -192,7 +191,7 @@ class _AnchoredHelperState extends State child: _buildAnimItem( opacityAnim: titleOpacityAnimation, sizeAnim: titleSizeAnimation, - child: _buildText(widget.titleLabel, + child: _buildText(widget.titleLabel!, ValueKey('pal_AnchoredHelperTitleLabel'))), ), Padding( @@ -201,7 +200,7 @@ class _AnchoredHelperState extends State opacityAnim: descriptionOpacityAnimation, sizeAnim: descriptionSizeAnimation, child: _buildText( - widget.descriptionLabel, + widget.descriptionLabel!, ValueKey( 'pal_AnchoredHelperDescriptionLabel'))), ), @@ -214,7 +213,7 @@ class _AnchoredHelperState extends State opacityAnim: btnOpacityAnimation, sizeAnim: btnSizeAnimation, child: _buildEditableBordered( - widget.negativButtonLabel, + widget.negativButtonLabel!, ValueKey('pal_AnchoredHelperNegativFeedbackLabel'), ValueKey("negativeFeedback"), widget.onNegativButtonTap @@ -225,7 +224,7 @@ class _AnchoredHelperState extends State opacityAnim: btnOpacityAnimation, sizeAnim: btnSizeAnimation, child: _buildEditableBordered( - widget.positivButtonLabel, + widget.positivButtonLabel!, ValueKey('pal_AnchoredHelperPositivFeedbackLabel'), ValueKey("positiveFeedback"), widget.onPositivButtonTap @@ -254,7 +253,7 @@ class _AnchoredHelperState extends State : Container(); Widget _buildText(HelperTextViewModel text, Key key) => Text( - text.text, + text.text!, key: key, textAlign: TextAlign.center, style: TextStyle( @@ -262,16 +261,16 @@ class _AnchoredHelperState extends State fontWeight: text.fontWeight, color: text.fontColor, ).merge( - GoogleFonts.getFont(text?.fontFamily ?? 'Montserrat'), + GoogleFonts.getFont(text.fontFamily ?? 'Montserrat'), ), ); - Widget _buildEditableBordered(HelperButtonViewModel model, Key textKey, Key buttonKey, Function onTap) { + Widget _buildEditableBordered(HelperButtonViewModel model, Key textKey, Key buttonKey, Function? onTap) { final textStyle = TextStyle( fontSize: model.fontSize, fontWeight: model.fontWeight, - color: model?.fontColor ?? Colors.white, - ).merge(GoogleFonts.getFont(model?.fontFamily ?? 'Montserrat')); + color: model.fontColor ?? Colors.white, + ).merge(GoogleFonts.getFont(model.fontFamily ?? 'Montserrat')); final ButtonStyle outlineButtonStyle = OutlinedButton.styleFrom( primary: model.fontColor ?? Colors.white, padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16), @@ -283,7 +282,7 @@ class _AnchoredHelperState extends State ).copyWith( side: MaterialStateProperty.resolveWith( (Set states) => BorderSide( - color: model !=null && model.fontColor != null ? model.fontColor : Colors.white, + color: model !=null && model.fontColor != null ? model.fontColor! : Colors.white, width: 1, ), ), @@ -293,11 +292,11 @@ class _AnchoredHelperState extends State onPressed: () async { HapticFeedback.selectionClick(); await fadeAnimController.reverse(); - onTap(); + onTap!(); }, style: outlineButtonStyle, child: Text( - model.text, + model.text!, key: textKey, style: textStyle, textAlign: TextAlign.center, @@ -306,9 +305,9 @@ class _AnchoredHelperState extends State } Widget _buildAnimItem( - {Animation sizeAnim, - Animation opacityAnim, - Widget child}) => + {Animation? sizeAnim, + Animation? opacityAnim, + Widget? child}) => AnimatedBuilder( animation: fadeAnimController, builder: (context, child) => Transform.translate( @@ -326,21 +325,21 @@ class _AnchoredHelperState extends State } class AnimatedAnchoredFullscreenCircle extends AnimatedWidget { - final Offset currentPos; + final Offset? currentPos; final double padding; - final Size anchorSize; - final Color bgColor; + final Size? anchorSize; + final Color? bgColor; final Animation _stroke1Animation, _stroke2Animation; AnimatedAnchoredFullscreenCircle( - {@required this.currentPos, - @required this.padding, - @required this.bgColor, - @required this.anchorSize, - @required Listenable listenable}) + {required this.currentPos, + required this.padding, + required this.bgColor, + required this.anchorSize, + required Listenable listenable}) : _stroke1Animation = - new CurvedAnimation(parent: listenable, curve: Curves.ease), + new CurvedAnimation(parent: listenable as Animation, curve: Curves.ease), _stroke2Animation = CurvedAnimation( parent: listenable, curve: Interval(0, .8, curve: Curves.ease), @@ -363,15 +362,15 @@ class AnimatedAnchoredFullscreenCircle extends AnimatedWidget { } class AnchoredFullscreenPainter extends CustomPainter { - final Offset currentPos; + final Offset? currentPos; final double padding; - final Size anchorSize; + final Size? anchorSize; final double area = 24.0 * 24.0; - final Color bgColor; + final Color? bgColor; double circle1Width, circle2Width; @@ -390,7 +389,7 @@ class AnchoredFullscreenPainter extends CustomPainter { ..blendMode = BlendMode.clear ..isAntiAlias = true; Paint bgPainter = Paint() - ..color = bgColor + ..color = bgColor! ..style = PaintingStyle.fill ..isAntiAlias = true; Paint circle1Painter = Paint() @@ -407,9 +406,9 @@ class AnchoredFullscreenPainter extends CustomPainter { canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), bgPainter); // canvas.drawCircle(currentPos, radius, clearPainter); // canvas.drawRect(currentPos & anchorSize, clearPainter); - var radius = sqrt(pow(anchorSize.width, 2) + pow(anchorSize.height, 2)) / 2; + var radius = sqrt(pow(anchorSize!.width, 2) + pow(anchorSize!.height, 2)) / 2; var center = - currentPos.translate(anchorSize.width / 2, anchorSize.height / 2); + currentPos!.translate(anchorSize!.width / 2, anchorSize!.height / 2); canvas.drawCircle(center, radius + padding, circle1Painter); canvas.drawCircle(center, radius + padding, circle2Painter); canvas.drawCircle(center, radius + padding, clearPainter); @@ -427,7 +426,7 @@ class AnchoredFullscreenPainter extends CustomPainter { @override bool hitTest(Offset position) { if (currentPos == null) return false; - var distance = (position - currentPos).distanceSquared; + var distance = (position - currentPos!).distanceSquared; if (distance <= area) { return true; } diff --git a/lib/src/ui/client/helpers/user_fullscreen_helper/user_fullscreen_helper.dart b/lib/src/ui/client/helpers/user_fullscreen_helper/user_fullscreen_helper.dart index d0c1af7f..a0a458e8 100644 --- a/lib/src/ui/client/helpers/user_fullscreen_helper/user_fullscreen_helper.dart +++ b/lib/src/ui/client/helpers/user_fullscreen_helper/user_fullscreen_helper.dart @@ -24,40 +24,38 @@ abstract class UserFullScreenHelperView { class UserFullScreenHelperPage extends StatelessWidget implements UserFullScreenHelperView { - final HelperBoxViewModel helperBoxViewModel; final HelperTextViewModel titleLabel; final HelperTextViewModel descriptionLabel; - final HelperButtonViewModel positivLabel; - final HelperButtonViewModel negativLabel; - final HelperImageViewModel headerImageViewModel; + final HelperButtonViewModel? positivLabel; + final HelperButtonViewModel? negativLabel; + final HelperImageViewModel? headerImageViewModel; final Function onPositivButtonTap; final Function onNegativButtonTap; UserFullScreenHelperPage({ - Key key, - @required this.helperBoxViewModel, - @required this.titleLabel, - @required this.descriptionLabel, - @required this.onPositivButtonTap, - @required this.onNegativButtonTap, + Key? key, + required this.helperBoxViewModel, + required this.titleLabel, + required this.descriptionLabel, + required this.onPositivButtonTap, + required this.onNegativButtonTap, this.headerImageViewModel, this.positivLabel, this.negativLabel, - }) : assert(helperBoxViewModel != null), - assert(titleLabel != null), - assert(descriptionLabel != null), - assert(onPositivButtonTap != null), - assert(onNegativButtonTap != null); + }); final _mvvmPageBuilder = MVVMPageBuilder(); final GlobalKey _scaffoldKey = GlobalKey(); + @visibleForTesting + get presenter => _mvvmPageBuilder.presenter; + @override Widget build(BuildContext context) { return _mvvmPageBuilder.build( - key: ValueKey('pal_UserFullScreenHelperPage_Builder'), + key: UniqueKey(), context: context, multipleAnimControllerBuilder: (tickerProvider) { return [ @@ -85,26 +83,26 @@ class UserFullScreenHelperPage extends StatelessWidget ]; }, animListener: (context, presenter, model) { - if (model.mediaAnimation) { + if (model.mediaAnimation!) { this.playAnimation( context, - model.isReversedAnimations, + model.isReversedAnimations!, 0, presenter.onMediaAnimationEnd, ); } - if (model.titleAnimation) { + if (model.titleAnimation!) { this.playAnimation( context, - model.isReversedAnimations, + model.isReversedAnimations!, 1, presenter.onTitleAnimationEnd, ); } - if (model.feedbackAnimation) { + if (model.feedbackAnimation!) { this.playAnimation( context, - model.isReversedAnimations, + model.isReversedAnimations!, 2, presenter.onFeedbackAnimationEnd, ); @@ -124,9 +122,9 @@ class UserFullScreenHelperPage extends StatelessWidget return AnimatedOpacity( duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn, - opacity: model?.helperOpacity, + opacity: model.helperOpacity!, child: Scaffold( - backgroundColor: helperBoxViewModel?.backgroundColor, + backgroundColor: helperBoxViewModel.backgroundColor, key: _scaffoldKey, body: SafeArea( child: Container( @@ -138,7 +136,7 @@ class UserFullScreenHelperPage extends StatelessWidget mainAxisAlignment: MainAxisAlignment.center, children: [ if (headerImageViewModel?.url != null && - headerImageViewModel.url.length > 0) + headerImageViewModel!.url!.length > 0) Flexible( key: ValueKey('pal_UserFullScreenHelperPage_Media'), flex: 3, @@ -175,7 +173,7 @@ class UserFullScreenHelperPage extends StatelessWidget widget: ClipRRect( borderRadius: BorderRadius.circular(15.0), child: CachedNetworkImage( - imageUrl: headerImageViewModel?.url, + imageUrl: headerImageViewModel?.url ?? '', fit: BoxFit.cover, placeholder: (context, url) => Center(child: CircularProgressIndicator()), @@ -184,38 +182,38 @@ class UserFullScreenHelperPage extends StatelessWidget }, ), ), - animationController: context.animationsControllers[0], + animationController: context.animationsControllers![0], ); } Widget _buildTitle(MvvmContext context) { return AnimatedTranslateWidget( - animationController: context.animationsControllers[1], + animationController: context.animationsControllers![1], widget: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( - titleLabel?.text ?? 'Title', + titleLabel.text ?? 'Title', key: ValueKey('pal_UserFullScreenHelperPage_Title'), textAlign: TextAlign.center, style: TextStyle( - color: titleLabel?.fontColor ?? Colors.white, - fontSize: titleLabel?.fontSize ?? 60.0, - fontWeight: titleLabel?.fontWeight, + color: titleLabel.fontColor ?? Colors.white, + fontSize: titleLabel.fontSize ?? 60.0, + fontWeight: titleLabel.fontWeight, ).merge( - GoogleFonts.getFont(titleLabel?.fontFamily ?? 'Montserrat')), + GoogleFonts.getFont(titleLabel.fontFamily ?? 'Montserrat')), ), Text( - descriptionLabel?.text ?? '', + descriptionLabel.text ?? '', key: ValueKey('pal_UserFullScreenHelperPage_Description'), textAlign: TextAlign.center, style: TextStyle( - color: descriptionLabel?.fontColor ?? Colors.white, - fontSize: descriptionLabel?.fontSize ?? 60.0, - fontWeight: descriptionLabel?.fontWeight, + color: descriptionLabel.fontColor ?? Colors.white, + fontSize: descriptionLabel.fontSize ?? 60.0, + fontWeight: descriptionLabel.fontWeight, ).merge(GoogleFonts.getFont( - descriptionLabel?.fontFamily ?? 'Montserrat')), + descriptionLabel.fontFamily ?? 'Montserrat')), ) ], ), @@ -227,7 +225,7 @@ class UserFullScreenHelperPage extends StatelessWidget MvvmContext context, UserFullScreenHelperPresenter presenter) { return AnimatedTranslateWidget( position: Tween(begin: Offset(0.0, -1.0), end: Offset(0.0, 0.0)), - animationController: context.animationsControllers[2], + animationController: context.animationsControllers![2], widget: Column( children: [ SizedBox( @@ -239,7 +237,7 @@ class UserFullScreenHelperPage extends StatelessWidget HapticFeedback.selectionClick(); presenter.onPositivButtonCallback(); }, - color: PalTheme.of(context.buildContext).colors.green, + color: PalTheme.of(context.buildContext)!.colors.green, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -272,7 +270,7 @@ class UserFullScreenHelperPage extends StatelessWidget HapticFeedback.selectionClick(); presenter.onNegativButtonCallback(); }, - color: PalTheme.of(context.buildContext).colors.accent, + color: PalTheme.of(context.buildContext)!.colors.accent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -316,11 +314,11 @@ class UserFullScreenHelperPage extends StatelessWidget Function callback, ) { if (isReversed) { - context.animationsControllers[index] + context.animationsControllers![index] .reverse() .then((value) => callback()); } else { - context.animationsControllers[index] + context.animationsControllers![index] .forward() .then((value) => callback()); } diff --git a/lib/src/ui/client/helpers/user_fullscreen_helper/user_fullscreen_helper_viewmodel.dart b/lib/src/ui/client/helpers/user_fullscreen_helper/user_fullscreen_helper_viewmodel.dart index 72471c4a..2c6f1dab 100644 --- a/lib/src/ui/client/helpers/user_fullscreen_helper/user_fullscreen_helper_viewmodel.dart +++ b/lib/src/ui/client/helpers/user_fullscreen_helper/user_fullscreen_helper_viewmodel.dart @@ -1,11 +1,11 @@ import 'package:mvvm_builder/mvvm_builder.dart'; class UserFullScreenHelperModel extends MVVMModel { - double helperOpacity; - bool mediaAnimation; - bool titleAnimation; - bool feedbackAnimation; - bool isReversedAnimations; + double? helperOpacity; + bool? mediaAnimation; + bool? titleAnimation; + bool? feedbackAnimation; + bool? isReversedAnimations; UserFullScreenHelperModel({ this.helperOpacity, diff --git a/lib/src/ui/client/helpers/user_update_helper/user_update_helper.dart b/lib/src/ui/client/helpers/user_update_helper/user_update_helper.dart index e5940100..77d7f2a8 100644 --- a/lib/src/ui/client/helpers/user_update_helper/user_update_helper.dart +++ b/lib/src/ui/client/helpers/user_update_helper/user_update_helper.dart @@ -29,23 +29,21 @@ class UserUpdateHelperPage extends StatelessWidget final HelperBoxViewModel helperBoxViewModel; final HelperTextViewModel titleLabel; final List changelogLabels; - final HelperButtonViewModel thanksButtonLabel; - final PackageVersionReader packageVersionReader; - final HelperImageViewModel helperImageViewModel; + final HelperButtonViewModel? thanksButtonLabel; + final PackageVersionReader? packageVersionReader; + final HelperImageViewModel? helperImageViewModel; final Function onPositivButtonTap; UserUpdateHelperPage({ - Key key, - @required this.helperBoxViewModel, - @required this.titleLabel, - @required this.changelogLabels, - @required this.onPositivButtonTap, + Key? key, + required this.helperBoxViewModel, + required this.titleLabel, + required this.changelogLabels, + required this.onPositivButtonTap, this.helperImageViewModel, this.thanksButtonLabel, this.packageVersionReader, - }) : assert(helperBoxViewModel != null), - assert(titleLabel != null), - assert(changelogLabels != null); + }); final _mvvmPageBuilder = MVVMPageBuilder(); @@ -88,34 +86,34 @@ class UserUpdateHelperPage extends StatelessWidget ]; }, animListener: (context, presenter, model) { - if (model.changelogCascadeAnimation) { + if (model.changelogCascadeAnimation!) { this.playAnimation( context, - model.isReversedAnimations, + model.isReversedAnimations!, 0, presenter.onCascadeAnimationEnd, ); } - if (model.progressBarAnimation) { + if (model.progressBarAnimation!) { this.playAnimation( context, - model.isReversedAnimations, + model.isReversedAnimations!, 1, presenter.onProgressBarAnimationEnd, ); } - if (model.imageAnimation) { + if (model.imageAnimation!) { this.playAnimation( context, - model.isReversedAnimations, + model.isReversedAnimations!, 2, presenter.onImageAnimationEnd, ); } - if (model.titleAnimation) { + if (model.titleAnimation!) { this.playAnimation( context, - model.isReversedAnimations, + model.isReversedAnimations!, 3, presenter.onTitleAnimationEnd, ); @@ -123,7 +121,7 @@ class UserUpdateHelperPage extends StatelessWidget }, presenterBuilder: (context) => UserUpdateHelperPresenter( this, - packageVersionReader ?? UserInjector.of(context).packageVersionReader, + packageVersionReader ?? UserInjector.of(context)!.packageVersionReader, ), builder: (context, presenter, model) { return this._buildPage(context, presenter, model); @@ -139,17 +137,17 @@ class UserUpdateHelperPage extends StatelessWidget return AnimatedOpacity( duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn, - opacity: model.helperOpacity, + opacity: model.helperOpacity!, child: Scaffold( key: ValueKey('pal_UserUpdateHelperWidget_Scaffold'), - backgroundColor: helperBoxViewModel?.backgroundColor, + backgroundColor: helperBoxViewModel.backgroundColor, body: SafeArea( child: Container( width: double.infinity, child: Container( child: Column( children: [ - if (helperImageViewModel?.url != null && helperImageViewModel.url.length > 0) + if (helperImageViewModel?.url != null && helperImageViewModel!.url!.length > 0) Flexible( key: ValueKey('pal_UserUpdateHelperWidget_Icon'), flex: 4, @@ -187,7 +185,7 @@ class UserUpdateHelperPage extends StatelessWidget borderRadius: BorderRadius.circular(15.0), child: CachedNetworkImage( key: ValueKey('pal_UserUpdateHelperWidget_Image'), - imageUrl: helperImageViewModel?.url, + imageUrl: helperImageViewModel?.url ?? '', fit: BoxFit.contain, placeholder: (context, url) => Center(child: CircularProgressIndicator()), @@ -198,7 +196,7 @@ class UserUpdateHelperPage extends StatelessWidget }, ), ), - animationController: context.animationsControllers[2], + animationController: context.animationsControllers![2], ), ), ); @@ -212,23 +210,23 @@ class UserUpdateHelperPage extends StatelessWidget width: double.infinity, child: AnimatedTranslateWidget( position: Tween(begin: Offset(-1.0, 0.0), end: Offset(0, 0)), - animationController: context.animationsControllers[3], + animationController: context.animationsControllers![3], widget: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( - titleLabel?.text ?? 'New application update', + titleLabel.text ?? 'New application update', key: ValueKey('pal_UserUpdateHelperWidget_AppSummary_Title'), textAlign: TextAlign.center, style: TextStyle( - fontSize: titleLabel?.fontSize ?? 27.0, - fontWeight: titleLabel?.fontWeight ?? FontWeight.normal, - color: titleLabel?.fontColor ?? - PalTheme.of(context.buildContext).colors.light, + fontSize: titleLabel.fontSize ?? 27.0, + fontWeight: titleLabel.fontWeight ?? FontWeight.normal, + color: titleLabel.fontColor ?? + PalTheme.of(context.buildContext)!.colors.light, ).merge( - GoogleFonts.getFont(titleLabel?.fontFamily ?? 'Montserrat'), + GoogleFonts.getFont(titleLabel.fontFamily ?? 'Montserrat'), ), ), ), @@ -266,8 +264,8 @@ class UserUpdateHelperPage extends StatelessWidget ), child: RaisedButton( key: ValueKey('pal_UserUpdateHelperWidget_ThanksButton_Raised'), - color: PalTheme.of(context.buildContext).colors.dark, - onPressed: model.showThanksButton + color: PalTheme.of(context.buildContext)!.colors.dark, + onPressed: model.showThanksButton! ? () { HapticFeedback.selectionClick(); presenter.onThanksButtonCallback(); @@ -283,7 +281,7 @@ class UserUpdateHelperPage extends StatelessWidget child: child, scale: animation, ), - child: model.showThanksButton + child: model.showThanksButton! ? Padding( padding: const EdgeInsets.symmetric(vertical: 12.0), child: Text( @@ -302,7 +300,7 @@ class UserUpdateHelperPage extends StatelessWidget ), ) : AnimatedProgressBar( - animationController: context.animationsControllers[1], + animationController: context.animationsControllers![1], ), ), ), @@ -343,7 +341,7 @@ class UserUpdateHelperPage extends StatelessWidget ReleaseNoteCell( index: index++, customLabel: label, - animationController: context.animationsControllers[0], + animationController: context.animationsControllers![0], positionCurve: Interval( animationStart, animationEnd, @@ -368,20 +366,16 @@ class UserUpdateHelperPage extends StatelessWidget Function callback, ) { if (isReversed) { - context.animationsControllers[index] + context.animationsControllers![index] .reverse() .then((value) => callback()); } else { - context.animationsControllers[index] + context.animationsControllers![index] .forward() .then((value) => callback()); } } @override - void onThanksButtonCallback() { - if (this.onPositivButtonTap != null) { - this.onPositivButtonTap(); - } - } + void onThanksButtonCallback() => onPositivButtonTap(); } diff --git a/lib/src/ui/client/helpers/user_update_helper/user_update_helper_viewmodel.dart b/lib/src/ui/client/helpers/user_update_helper/user_update_helper_viewmodel.dart index 038a7ad8..366b9d8f 100644 --- a/lib/src/ui/client/helpers/user_update_helper/user_update_helper_viewmodel.dart +++ b/lib/src/ui/client/helpers/user_update_helper/user_update_helper_viewmodel.dart @@ -1,14 +1,14 @@ import 'package:mvvm_builder/mvvm_builder.dart'; class UserUpdateHelperModel extends MVVMModel { - double helperOpacity; - String appVersion; - bool changelogCascadeAnimation; - bool progressBarAnimation; - bool titleAnimation; - bool imageAnimation; - bool showThanksButton; - bool isReversedAnimations; + double? helperOpacity; + String? appVersion; + bool? changelogCascadeAnimation; + bool? progressBarAnimation; + bool? titleAnimation; + bool? imageAnimation; + bool? showThanksButton; + bool? isReversedAnimations; UserUpdateHelperModel({ this.helperOpacity, diff --git a/lib/src/ui/client/helpers/user_update_helper/widgets/animated_progress_bar.dart b/lib/src/ui/client/helpers/user_update_helper/widgets/animated_progress_bar.dart index 7b0f1c09..42c2d1ca 100644 --- a/lib/src/ui/client/helpers/user_update_helper/widgets/animated_progress_bar.dart +++ b/lib/src/ui/client/helpers/user_update_helper/widgets/animated_progress_bar.dart @@ -2,13 +2,13 @@ import 'package:flutter/material.dart'; class AnimatedProgressBar extends AnimatedWidget { final AnimationController animationController; - final Animation valueColor; + final Animation? valueColor; final Color backgroundColor; final Animation progressValueAnim; AnimatedProgressBar({ - Key key, - @required this.animationController, + Key? key, + required this.animationController, this.valueColor, this.backgroundColor = Colors.grey, }) : this.progressValueAnim = Tween(begin: 0, end: 1).animate(animationController), diff --git a/lib/src/ui/client/helpers/user_update_helper/widgets/release_note_cell.dart b/lib/src/ui/client/helpers/user_update_helper/widgets/release_note_cell.dart index 615a7ca5..0a2b5062 100644 --- a/lib/src/ui/client/helpers/user_update_helper/widgets/release_note_cell.dart +++ b/lib/src/ui/client/helpers/user_update_helper/widgets/release_note_cell.dart @@ -8,14 +8,14 @@ class ReleaseNoteCell extends StatelessWidget { final int index; final HelperTextViewModel customLabel; final AnimationController animationController; - final Curve positionCurve; - final Curve opacityCurve; + final Curve? positionCurve; + final Curve? opacityCurve; const ReleaseNoteCell({ - Key key, - @required this.index, - @required this.customLabel, - @required this.animationController, + Key? key, + required this.index, + required this.customLabel, + required this.animationController, this.positionCurve, this.opacityCurve, }) : super(key: key); diff --git a/lib/src/ui/client/helpers_synchronizer.dart b/lib/src/ui/client/helpers_synchronizer.dart index 918b62e8..81b93001 100644 --- a/lib/src/ui/client/helpers_synchronizer.dart +++ b/lib/src/ui/client/helpers_synchronizer.dart @@ -14,14 +14,14 @@ class HelpersSynchronizer { final PackageVersionReader packageVersionReader; HelpersSynchronizer({ - @required this.pageUserVisitRemoteRepository, - @required this.pageUserVisitLocalRepository, - @required this.schemaRemoteRepository, - @required this.schemaLocalRepository, - @required this.packageVersionReader, + required this.pageUserVisitRemoteRepository, + required this.pageUserVisitLocalRepository, + required this.schemaRemoteRepository, + required this.schemaLocalRepository, + required this.packageVersionReader, }); - Future sync(String inAppUserId, {String languageCode}) async { + Future sync(String? inAppUserId, {String? languageCode}) async { debugPrint("...sync database start"); String currentVersion = packageVersionReader.version; var currentSchema = await schemaLocalRepository.get(appVersion: currentVersion); @@ -38,8 +38,8 @@ class HelpersSynchronizer { await pageUserVisitLocalRepository.saveAll(visits); } if(lastSchemaVersion != null) { - debugPrint(" remote schema version ${lastSchemaVersion?.schemaVersion}"); - debugPrint("${lastSchemaVersion?.groups?.length ?? 0} groups saved"); + debugPrint(" remote schema version ${lastSchemaVersion.schemaVersion}"); + debugPrint("${lastSchemaVersion.groups?.length ?? 0} groups saved"); await schemaLocalRepository.save(lastSchemaVersion); } debugPrint("...sync database end"); diff --git a/lib/src/ui/client/widgets/animated/animated_scale.dart b/lib/src/ui/client/widgets/animated/animated_scale.dart index a797ebeb..9d741566 100644 --- a/lib/src/ui/client/widgets/animated/animated_scale.dart +++ b/lib/src/ui/client/widgets/animated/animated_scale.dart @@ -2,14 +2,14 @@ import 'package:flutter/material.dart'; class AnimatedScaleWidget extends AnimatedWidget { final AnimationController animationController; - final Tween scale; + final Tween? scale; final Curve curve; final Widget widget; AnimatedScaleWidget({ - Key key, - @required this.animationController, - @required this.widget, + Key? key, + required this.animationController, + required this.widget, this.curve = Curves.ease, this.scale, }) : super(key: key, listenable: animationController); @@ -17,7 +17,7 @@ class AnimatedScaleWidget extends AnimatedWidget { @override Widget build(BuildContext context) { return ScaleTransition( - scale: ((scale?.begin != null && scale?.end != null) ? scale : Tween(begin: 0.0, end: 1.0)).animate( + scale: ((scale?.begin != null && scale?.end != null) ? scale : Tween(begin: 0.0, end: 1.0))!.animate( CurvedAnimation( parent: animationController, curve: Curves.ease, diff --git a/lib/src/ui/client/widgets/animated/animated_translate.dart b/lib/src/ui/client/widgets/animated/animated_translate.dart index e12fda37..997b2ccf 100644 --- a/lib/src/ui/client/widgets/animated/animated_translate.dart +++ b/lib/src/ui/client/widgets/animated/animated_translate.dart @@ -2,16 +2,16 @@ import 'package:flutter/material.dart'; class AnimatedTranslateWidget extends AnimatedWidget { final AnimationController animationController; - final Tween opacity; - final Tween position; + final Tween? opacity; + final Tween? position; final Widget widget; - final Curve positionCurve; - final Curve opacityCurve; + final Curve? positionCurve; + final Curve? opacityCurve; AnimatedTranslateWidget({ - Key key, - @required this.animationController, - @required this.widget, + Key? key, + required this.animationController, + required this.widget, this.opacity, this.position, this.positionCurve = Curves.ease, @@ -23,21 +23,21 @@ class AnimatedTranslateWidget extends AnimatedWidget { return FadeTransition( opacity: ((opacity?.begin != null && opacity?.end != null) ? opacity - : Tween(begin: 0, end: 1)) + : Tween(begin: 0, end: 1))! .animate( CurvedAnimation( parent: animationController, - curve: opacityCurve, + curve: opacityCurve!, ), ), child: SlideTransition( position: ((position?.begin != null && position?.end != null) ? position - : Tween(begin: Offset(-1, 0), end: Offset(0, 0))) + : Tween(begin: Offset(-1, 0), end: Offset(0, 0)))! .animate( CurvedAnimation( parent: animationController, - curve: positionCurve, + curve: positionCurve!, ), ), child: widget, diff --git a/lib/src/ui/editor/pages/app_settings/app_settings.dart b/lib/src/ui/editor/pages/app_settings/app_settings.dart index 8395a792..776169ab 100644 --- a/lib/src/ui/editor/pages/app_settings/app_settings.dart +++ b/lib/src/ui/editor/pages/app_settings/app_settings.dart @@ -26,9 +26,9 @@ abstract class AppSettingsView { class AppSettingsPage extends StatelessWidget with SnackbarMixin implements AppSettingsView { - final AppIconGrabberDelegate appIconGrabberDelegate; - final PackageVersionReader packageVersionReader; - final ProjectEditorService projectEditorService; + final AppIconGrabberDelegate? appIconGrabberDelegate; + final PackageVersionReader? packageVersionReader; + final ProjectEditorService? projectEditorService; final bool testMode; final GlobalKey _scaffoldKey = GlobalKey(); @@ -36,7 +36,7 @@ class AppSettingsPage extends StatelessWidget final double _logoSize = 120.0; AppSettingsPage({ - Key key, + Key? key, this.appIconGrabberDelegate, this.packageVersionReader, this.projectEditorService, @@ -54,11 +54,11 @@ class AppSettingsPage extends StatelessWidget presenterBuilder: (context) => AppSettingsPresenter( this, packageVersionReader: packageVersionReader ?? - EditorInjector.of(context).packageVersionReader, + EditorInjector.of(context)!.packageVersionReader, projectEditorService: projectEditorService ?? - EditorInjector.of(context).projectEditorService, + EditorInjector.of(context)!.projectEditorService, appIconGrabberDelegate: appIconGrabberDelegate ?? - EditorInjector.of(context).appIconGrabberDelegate, + EditorInjector.of(context)!.appIconGrabberDelegate, ), singleAnimControllerBuilder: (tickerProvider) { return AnimationController( @@ -69,8 +69,8 @@ class AppSettingsPage extends StatelessWidget ); }, animListener: (context, presenter, model) { - if (model.appIconAnimation) { - context.animationController + if (model.appIconAnimation!) { + context.animationController! .forward() .then((value) => presenter.onAppIconAnimationEnd()); } @@ -100,12 +100,12 @@ class AppSettingsPage extends StatelessWidget alignment: Alignment.topCenter, child: Padding( padding: EdgeInsets.only( - top: (model.headerSize.height / 2) + - ((model.headerSize.height - _logoSize) / 2), + top: (model.headerSize!.height / 2) + + ((model.headerSize!.height - _logoSize) / 2), ), child: AnimatedAppIcon( radius: _logoSize / 2, - animationController: context.animationController, + animationController: context.animationController!, onTap: presenter.refreshAppIcon, isSendingAppIcon: model.isSendingAppIcon, testMode: testMode, @@ -121,7 +121,7 @@ class AppSettingsPage extends StatelessWidget return Container( key: _headerKey, decoration: BoxDecoration( - gradient: PalTheme.of(context).settingsSilverGradient, + gradient: PalTheme.of(context)!.settingsSilverGradient, ), ); } @@ -142,7 +142,7 @@ class AppSettingsPage extends StatelessWidget ), Expanded( flex: 25, - child: model.isLoadingAppInfo + child: model.isLoadingAppInfo! ? Center( child: CircularProgressIndicator(), ) @@ -210,16 +210,16 @@ class AppSettingsPage extends StatelessWidget child: Text( 'Beta account member', style: TextStyle( - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1, ), ), ), borderSide: BorderSide( - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1!, ), shape: RoundedRectangleBorder( side: BorderSide( - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1!, width: 3, style: BorderStyle.solid, ), @@ -240,7 +240,7 @@ class AppSettingsPage extends StatelessWidget @override getHeaderSize() { - RenderBox _headerRenderBox = _headerKey.currentContext.findRenderObject(); + RenderBox _headerRenderBox = _headerKey.currentContext!.findRenderObject() as RenderBox; return _headerRenderBox.size; } diff --git a/lib/src/ui/editor/pages/app_settings/app_settings_presenter.dart b/lib/src/ui/editor/pages/app_settings/app_settings_presenter.dart index 232d47be..5cb02119 100644 --- a/lib/src/ui/editor/pages/app_settings/app_settings_presenter.dart +++ b/lib/src/ui/editor/pages/app_settings/app_settings_presenter.dart @@ -16,9 +16,9 @@ class AppSettingsPresenter AppSettingsPresenter( AppSettingsView viewInterface, { - @required this.packageVersionReader, - @required this.projectEditorService, - @required this.appIconGrabberDelegate, + required this.packageVersionReader, + required this.projectEditorService, + required this.appIconGrabberDelegate, }) : super(AppSettingsModel(), viewInterface); @override @@ -31,7 +31,7 @@ class AppSettingsPresenter this.readAppInfo(); startAnimation(); - WidgetsBinding.instance.addPostFrameCallback(afterLayout); + WidgetsBinding.instance!.addPostFrameCallback(afterLayout); } afterLayout(Duration duration) { @@ -90,7 +90,7 @@ class AppSettingsPresenter }); } - void _updateAppIcon(Uint8List appIcon, String appIconId) { + void _updateAppIcon(Uint8List appIcon, String? appIconId) { this .projectEditorService .updateAppIcon(appIconId, appIcon, "png") diff --git a/lib/src/ui/editor/pages/app_settings/app_settings_viewmodel.dart b/lib/src/ui/editor/pages/app_settings/app_settings_viewmodel.dart index 58f0c27d..09b34d0d 100644 --- a/lib/src/ui/editor/pages/app_settings/app_settings_viewmodel.dart +++ b/lib/src/ui/editor/pages/app_settings/app_settings_viewmodel.dart @@ -2,14 +2,14 @@ import 'package:flutter/widgets.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; class AppSettingsModel extends MVVMModel { - Size headerSize; - String appVersion; - String appName; - bool appIconAnimation; - bool isSendingAppIcon; - bool isLoadingAppInfo; - String appIconUrl; - String appIconId; + Size? headerSize; + String? appVersion; + String? appName; + bool? appIconAnimation; + bool? isSendingAppIcon; + bool? isLoadingAppInfo; + String? appIconUrl; + String? appIconId; AppSettingsModel({ this.headerSize, diff --git a/lib/src/ui/editor/pages/app_settings/widgets/animated_app_icon.dart b/lib/src/ui/editor/pages/app_settings/widgets/animated_app_icon.dart index c4052dff..b1731848 100644 --- a/lib/src/ui/editor/pages/app_settings/widgets/animated_app_icon.dart +++ b/lib/src/ui/editor/pages/app_settings/widgets/animated_app_icon.dart @@ -1,19 +1,19 @@ -import 'package:application_icon/application_icon.dart'; +// import 'package:application_icon/application_icon.dart'; import 'package:flutter/material.dart'; import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/shared/widgets/circle_button.dart'; class AnimatedAppIcon extends AnimatedWidget { final double radius; - final Function onTap; - final bool isSendingAppIcon; + final Function? onTap; + final bool? isSendingAppIcon; final AnimationController animationController; final bool testMode; AnimatedAppIcon({ - Key key, - @required this.radius, - @required this.animationController, + Key? key, + required this.radius, + required this.animationController, this.onTap, this.isSendingAppIcon = false, this.testMode = false, @@ -44,7 +44,7 @@ class AnimatedAppIcon extends AnimatedWidget { ), child: Stack( children: [ - ClipOval(child: !testMode ? AppIconImage() : Container()), + // ClipOval(child: !testMode ? AppIconImage() : Container()), Align( alignment: Alignment.bottomRight, child: CircleIconButton( @@ -53,10 +53,10 @@ class AnimatedAppIcon extends AnimatedWidget { isLoading: isSendingAppIcon, icon: Icon( Icons.refresh, - color: PalTheme.of(context).colors.light, + color: PalTheme.of(context)!.colors.light, ), - backgroundColor: PalTheme.of(context).colors.dark, - onTapCallback: !isSendingAppIcon + backgroundColor: PalTheme.of(context)!.colors.dark, + onTapCallback: !isSendingAppIcon! ? onTap : null, ), diff --git a/lib/src/ui/editor/pages/create_helper/create_helper.dart b/lib/src/ui/editor/pages/create_helper/create_helper.dart index 46fa2f53..f88192de 100644 --- a/lib/src/ui/editor/pages/create_helper/create_helper.dart +++ b/lib/src/ui/editor/pages/create_helper/create_helper.dart @@ -19,8 +19,8 @@ import '../../../../pal_navigator_observer.dart'; import 'steps/select_group_position/helper_position_setup.dart'; class CreateHelperPageArguments { - final GlobalKey hostedAppNavigatorKey; - final String pageId; + final GlobalKey? hostedAppNavigatorKey; + final String? pageId; CreateHelperPageArguments( this.hostedAppNavigatorKey, @@ -30,7 +30,7 @@ class CreateHelperPageArguments { abstract class CreateHelperView { - void launchHelperEditor(final String pageRoute, final CreateHelperModel model); + void launchHelperEditor(final String? pageRoute, final CreateHelperModel model); void changeStep(int index); @@ -43,18 +43,18 @@ abstract class CreateHelperView { class CreateHelperPage extends StatelessWidget implements CreateHelperView { - final GlobalKey hostedAppNavigatorKey; - final PalRouteObserver routeObserver; - final String pageId; - final PackageVersionReader packageVersionReader; - final ProjectEditorService projectEditorService; + final GlobalKey? hostedAppNavigatorKey; + final PalRouteObserver? routeObserver; + final String? pageId; + final PackageVersionReader? packageVersionReader; + final ProjectEditorService? projectEditorService; final GlobalKey _scaffoldKey = GlobalKey(); final GlobalKey _nestedNavigationKey = GlobalKey(); CreateHelperPage({ - Key key, + Key? key, this.hostedAppNavigatorKey, this.packageVersionReader, this.pageId, @@ -72,9 +72,9 @@ class CreateHelperPage extends StatelessWidget implements CreateHelperView { presenterBuilder: (context) => CreateHelperPresenter( this, this.pageId, - routeObserver: routeObserver ?? EditorInjector.of(context).routeObserver, - packageVersionReader: packageVersionReader ?? EditorInjector.of(context).packageVersionReader, - projectEditorService: projectEditorService ?? EditorInjector.of(context).projectEditorService + routeObserver: routeObserver ?? EditorInjector.of(context)!.routeObserver, + packageVersionReader: packageVersionReader ?? EditorInjector.of(context)!.packageVersionReader, + projectEditorService: projectEditorService ?? EditorInjector.of(context)!.projectEditorService ), builder: (context, presenter, model) => Scaffold( @@ -83,12 +83,12 @@ class CreateHelperPage extends StatelessWidget implements CreateHelperView { elevation: 0, backgroundColor: Colors.transparent, iconTheme: IconThemeData( - color: PalTheme.of(context.buildContext).colors.dark, + color: PalTheme.of(context.buildContext)!.colors.dark, ), title: Text( 'Create new helper', style: TextStyle( - color: PalTheme.of(context.buildContext).colors.dark, + color: PalTheme.of(context.buildContext)!.colors.dark, ), ), ), @@ -124,7 +124,7 @@ class CreateHelperPage extends StatelessWidget implements CreateHelperView { routes: { 'create/new_helper_group': (context) => CreateHelperGroup( triggerTypes: model.triggerTypes, - defaultTriggerType: model.triggerTypes.first, + defaultTriggerType: model.triggerTypes!.first, helperNameValidator: presenter.checkHelperGroupName, onTriggerValueSelected: presenter.selectHelperGroupTrigger, onChangedNameText: presenter.onChangedHelperGroupName, @@ -181,8 +181,9 @@ class CreateHelperPage extends StatelessWidget implements CreateHelperView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - (model?.step?.value != null) - ? model.stepsTitle[model?.step?.value] + // model.step?.value.toString() ?? '', + (model.step?.value != null) + ? model.stepsTitle![model.step!.value] : '', style: TextStyle( fontWeight: FontWeight.bold, @@ -204,17 +205,17 @@ class CreateHelperPage extends StatelessWidget implements CreateHelperView { final CreateHelperPresenter presenter, ) { return ValueListenableBuilder( - valueListenable: model.isFormValid, + valueListenable: model.isFormValid!, builder: (context, value, child) => RaisedButton( key: ValueKey('palCreateHelperNextButton'), - disabledColor: PalTheme.of(context).colors.color4, + disabledColor: PalTheme.of(context)!.colors.color4, child: Text( 'Next', style: TextStyle( color: Colors.white, ), ), - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1, onPressed: (value) ? presenter.incrementStep : null, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), @@ -224,10 +225,10 @@ class CreateHelperPage extends StatelessWidget implements CreateHelperView { } @override - void launchHelperEditor(final String pageRoute, final CreateHelperModel model) { + void launchHelperEditor(final String? pageRoute, final CreateHelperModel model) { new EditorRouter(hostedAppNavigatorKey).createHelper(pageRoute, model); // Go back - Navigator.of(_scaffoldKey.currentContext).pop(true); + Navigator.of(_scaffoldKey.currentContext!).pop(true); } @override @@ -238,19 +239,19 @@ class CreateHelperPage extends StatelessWidget implements CreateHelperView { "type", "theme", ]; - Navigator.of(_nestedNavigationKey.currentContext).pushNamed('create/${routeNames[index]}'); + Navigator.of(_nestedNavigationKey.currentContext!).pushNamed('create/${routeNames[index]}'); } void showNewHelperGroupForm() - => Navigator.of(_nestedNavigationKey.currentContext).pushNamed('create/new_helper_group'); + => Navigator.of(_nestedNavigationKey.currentContext!).pushNamed('create/new_helper_group'); @override void popStep() - => Navigator.of(_nestedNavigationKey.currentContext).pop(); + => Navigator.of(_nestedNavigationKey.currentContext!).pop(); @override void showGroupHelpersPositions(Future> loadGroupHelpers, OnValidate onValidate) { - Navigator.of( _scaffoldKey.currentContext).push(new MaterialPageRoute( + Navigator.of( _scaffoldKey.currentContext!).push(new MaterialPageRoute( settings: RouteSettings(name: "helper_group_position"), builder: (context) => HelperPositionPage( helpersLoader: loadGroupHelpers, diff --git a/lib/src/ui/editor/pages/create_helper/create_helper_presenter.dart b/lib/src/ui/editor/pages/create_helper/create_helper_presenter.dart index 76094507..15273c40 100644 --- a/lib/src/ui/editor/pages/create_helper/create_helper_presenter.dart +++ b/lib/src/ui/editor/pages/create_helper/create_helper_presenter.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; @@ -10,21 +11,22 @@ import 'package:pal/src/ui/editor/pages/create_helper/steps/create_helper_infos/ import 'package:pal/src/ui/editor/pages/create_helper/steps/create_helper_theme/create_helper_theme_step_model.dart'; import 'package:pal/src/ui/editor/pages/create_helper/steps/create_helper_type/create_helper_type_step_model.dart'; -class CreateHelperPresenter extends Presenter { - +class CreateHelperPresenter + extends Presenter { final PackageVersionReader packageVersionReader; - final PalRouteObserver routeObserver; + final PalRouteObserver? routeObserver; final ProjectEditorService projectEditorService; - final String pageId; + final String? pageId; CreateHelperPresenter( - CreateHelperView viewInterface, this.pageId, { - @required this.projectEditorService, - @required this.routeObserver, - @required this.packageVersionReader, + CreateHelperView viewInterface, + this.pageId, { + required this.projectEditorService, + required this.routeObserver, + required this.packageVersionReader, }) : super(CreateHelperModel(), viewInterface); @override @@ -49,19 +51,16 @@ class CreateHelperPresenter extends Presenter> loadHelperGroup() async { - return projectEditorService.getPageGroups(this.pageId) - .catchError((error) { - print("error $error"); - return null; - }) - .then((groupsEntity) { - List res = []; - groupsEntity.forEach((element) => res.add( - HelperGroupViewModel(groupId: element.id, title: element.name)) - ); - viewModel.helperGroups = res; - return viewModel.helperGroups; - }); + return projectEditorService.getPageGroups(this.pageId).catchError((error) { + print("error $error"); + return null; + }).then((groupsEntity) { + List res = []; + groupsEntity.forEach((element) => res + .add(HelperGroupViewModel(groupId: element.id, title: element.name))); + viewModel.helperGroups = res; + return viewModel.helperGroups; + }); } void onTapHelperGroupSelection(HelperGroupViewModel select) { @@ -70,7 +69,8 @@ class CreateHelperPresenter extends Presenter= 45) { return 'Maximum 45 character allowed'; @@ -88,15 +88,15 @@ class CreateHelperPresenter extends Presenter viewModel.helperGroupCreationState = state; + void groupCreationFormChanged(bool state) => + viewModel.helperGroupCreationState = state; void setMinAppVersion(String value) { viewModel.minVersion = value; @@ -140,36 +140,33 @@ class CreateHelperPresenter extends Presenter> loadGroupHelpers() async { - // MOCK - // var res = [ - // GroupHelperViewModel(id: "3802832", title: "my helper 1"), - // GroupHelperViewModel(id: "3802833", title: "my helper 2"), - // GroupHelperViewModel(id: "3802834", title: "my helper 3"), - // GroupHelperViewModel(id: "3802835", title: "my helper 4"), - // GroupHelperViewModel(id: "3802836", title: "my helper 5"), - // ]; - // return res; - - if(viewModel.selectedHelperGroup == null || viewModel.selectedHelperGroup.groupId == null) { + if (viewModel.selectedHelperGroup == null || + viewModel.selectedHelperGroup!.groupId == null) { return []; } // put our new helper in the list and highlight it try { - var helpers = await projectEditorService.getGroupHelpers(viewModel.selectedHelperGroup.groupId); - return helpers.map((e) => GroupHelperViewModel(id: e.id, title: e.name)) - .toList() - ..add(GroupHelperViewModel(id: "NEW_HELPER", title: viewModel?.helperNameController?.text ?? "My new helper")); - } catch(e) { + var helpers = await projectEditorService + .getGroupHelpers(viewModel.selectedHelperGroup!.groupId); + return helpers + .map((e) => GroupHelperViewModel(id: e.id, title: e.name)) + .toList() + ..add(GroupHelperViewModel( + id: "NEW_HELPER", + title: + viewModel.helperNameController?.text ?? "My new helper")); + } catch (e) { return Future.error("error while parsing helpers"); } } - void onGroupReorder(int selectedRank) { + void onGroupReorder(int? selectedRank) { viewModel.selectedRank = selectedRank; } void onTapChangePosition() { - viewInterface.showGroupHelpersPositions(loadGroupHelpers(), this.onGroupReorder); + viewInterface.showGroupHelpersPositions( + loadGroupHelpers(), this.onGroupReorder); } //////////////////////////////////////////////////////////////// @@ -184,7 +181,7 @@ class CreateHelperPresenter extends Presenter= this.viewModel.stepsTitle.length - 1) { - var currentPageRoute = await this.routeObserver.routeSettings.first; + if (this.viewModel.step!.value >= this.viewModel.stepsTitle!.length - 1) { + var currentPageRoute = await this.routeObserver!.routeSettings.first; this.viewInterface.launchHelperEditor(currentPageRoute.name, viewModel); return; } - viewModel.step.value++; - viewInterface.changeStep(viewModel.step.value); + viewModel.step!.value++; + viewInterface.changeStep(viewModel.step!.value); checkValidStep(); refreshView(); } decrementStep() { - if (this.viewModel.step.value <= 0) { + if (this.viewModel.step!.value <= 0) { return; } - this.viewModel.step.value--; + this.viewModel.step!.value--; this.checkValidStep(); this.refreshView(); } void checkValidStep() { - switch (this.viewModel.step.value) { + switch (this.viewModel.step!.value) { case 0: - this.viewModel.isFormValid.value = this.viewModel.selectedHelperGroup != null - && this.viewModel.selectedHelperGroup.title.isNotEmpty - && (this.viewModel.selectedHelperGroup.groupId != null - || (checkValidVersion(viewModel.minVersion) == null - && checkMaxValidVersion(viewModel.maxVersion) == null) - ); + this.viewModel.isFormValid!.value = + this.viewModel.selectedHelperGroup != null && + this.viewModel.selectedHelperGroup!.title!.isNotEmpty && + (this.viewModel.selectedHelperGroup!.groupId != null || + (checkValidVersion(viewModel.minVersion) == null && + checkMaxValidVersion(viewModel.maxVersion) == null)); break; case 1: - this.viewModel.isFormValid.value = viewModel.infosForm != null - && this.viewModel.infosForm.currentState != null - ? this.viewModel.infosForm.currentState.validate() + this.viewModel.isFormValid!.value = viewModel.infosForm != null && + this.viewModel.infosForm!.currentState != null + ? this.viewModel.infosForm!.currentState!.validate() : false; break; case 2: - this.viewModel.isFormValid.value = this.viewModel.selectedHelperType != null; + this.viewModel.isFormValid!.value = + this.viewModel.selectedHelperType != null; break; case 3: - this.viewModel.isFormValid.value = this.viewModel.selectedHelperTheme != null; + this.viewModel.isFormValid!.value = + this.viewModel.selectedHelperTheme != null; break; default: } } - } diff --git a/lib/src/ui/editor/pages/create_helper/create_helper_viewmodel.dart b/lib/src/ui/editor/pages/create_helper/create_helper_viewmodel.dart index 7847c934..1849095b 100644 --- a/lib/src/ui/editor/pages/create_helper/create_helper_viewmodel.dart +++ b/lib/src/ui/editor/pages/create_helper/create_helper_viewmodel.dart @@ -7,29 +7,29 @@ import 'package:pal/src/ui/editor/pages/create_helper/steps/create_helper_infos/ import 'package:pal/src/ui/editor/pages/helper_editor/helper_editor_viewmodel.dart'; class CreateHelperModel extends MVVMModel { - ValueNotifier isFormValid = ValueNotifier(false); - List stepsTitle; - ValueNotifier step; + ValueNotifier? isFormValid = ValueNotifier(false); + List? stepsTitle; + ValueNotifier? step; // Step 0 - List helperGroups; - HelperGroupViewModel selectedHelperGroup; - List triggerTypes; - HelperTriggerTypeDisplay selectedTriggerType; - String appVersion, minVersion, maxVersion; - bool helperGroupCreationState; + late List helperGroups; + HelperGroupViewModel? selectedHelperGroup; + List? triggerTypes; + HelperTriggerTypeDisplay? selectedTriggerType; + String? appVersion, minVersion, maxVersion; + bool? helperGroupCreationState; // Step 1 - GlobalKey infosForm; - bool isAppVersionLoading; - TextEditingController helperNameController; - int selectedRank; + GlobalKey? infosForm; + bool? isAppVersionLoading; + TextEditingController? helperNameController; + int? selectedRank; // Step 2 - HelperType selectedHelperType; + HelperType? selectedHelperType; // Step 3 - HelperTheme selectedHelperTheme; + HelperTheme? selectedHelperTheme; CreateHelperModel({ this.selectedTriggerType, @@ -48,12 +48,12 @@ class CreateHelperModel extends MVVMModel { HelperViewModel asHelperViewModel() => HelperViewModel( helperType: selectedHelperType, helperTheme: selectedHelperTheme, - name: helperNameController?.value?.text, + name: helperNameController?.value.text, priority: selectedRank, helperGroup: HelperGroupModel( id: selectedHelperGroup?.groupId, name: selectedHelperGroup?.title, - triggerType: selectedTriggerType.key, + triggerType: selectedTriggerType!.key, minVersionCode: minVersion, maxVersionCode: maxVersion, ), @@ -71,10 +71,10 @@ class CreateHelperModel extends MVVMModel { class HelperGroupViewModel extends ChangeNotifier implements ValueListenable { bool _selected; - String groupId; - String title; + String? groupId; + String? title; - HelperGroupViewModel({@required this.groupId, @required this.title}) + HelperGroupViewModel({required this.groupId, required this.title}) : this._selected = false; set selected(bool selected) { @@ -97,12 +97,12 @@ class HelperGroupViewModel extends ChangeNotifier class HelperSelectionViewModel { String id, title; - HelperSelectionViewModel({@required this.id, @required this.title}); + HelperSelectionViewModel({required this.id, required this.title}); } class GroupHelperViewModel { - String id; - String title; + String? id; + String? title; GroupHelperViewModel({this.id, this.title}); } diff --git a/lib/src/ui/editor/pages/create_helper/steps/create_helper_group/create_helper_group.dart b/lib/src/ui/editor/pages/create_helper/steps/create_helper_group/create_helper_group.dart index ddd421a4..fa92248f 100644 --- a/lib/src/ui/editor/pages/create_helper/steps/create_helper_group/create_helper_group.dart +++ b/lib/src/ui/editor/pages/create_helper/steps/create_helper_group/create_helper_group.dart @@ -3,113 +3,113 @@ import 'package:pal/src/ui/editor/pages/create_helper/steps/create_helper_infos/ import 'package:pal/src/ui/editor/widgets/bordered_text_field.dart'; import 'package:pal/src/ui/editor/widgets/labeled_form.dart'; -typedef HelperNameValidator = String Function(String value); -typedef TriggerTypeValidator = String Function(HelperTriggerTypeDisplay value); - -typedef VersionValidator = String Function(String value); +typedef TriggerTypeValidator = String Function(HelperTriggerTypeDisplay? value); typedef OnVersionChanged = void Function(String value); typedef OnFormChanged = void Function(bool state); -typedef OnTriggerValueSelected = void Function(HelperTriggerTypeDisplay triggerType); +typedef OnTriggerValueSelected = void Function(HelperTriggerTypeDisplay? triggerType); typedef OnChangedText = void Function(String value); class CreateHelperGroup extends StatelessWidget { - final HelperNameValidator helperNameValidator; - final TriggerTypeValidator triggerTypeValidator; + final TextFieldValidator helperNameValidator; + final TriggerTypeValidator? triggerTypeValidator; final OnTriggerValueSelected onTriggerValueSelected; final HelperTriggerTypeDisplay defaultTriggerType; - final List triggerTypes; + final List? triggerTypes; final OnChangedText onChangedNameText; final OnFormChanged onFormChanged; - final VersionValidator minVersionValidator, maxVersionValidator; - final String minVersionInitialValue, maxVersionInitialValue; + final TextFieldValidator minVersionValidator, maxVersionValidator; + final String? minVersionInitialValue, maxVersionInitialValue; final OnVersionChanged minVersionChanged, maxVersionChanged; final GlobalKey _formKey = GlobalKey(); CreateHelperGroup({ - @required this.helperNameValidator, - @required this.onFormChanged, - @required this.triggerTypeValidator, - @required this.onTriggerValueSelected, - @required this.defaultTriggerType, - @required this.triggerTypes, - @required this.onChangedNameText, - @required this.minVersionValidator, - @required this.maxVersionValidator, - @required this.minVersionInitialValue, - @required this.maxVersionInitialValue, - @required this.minVersionChanged, - @required this.maxVersionChanged + required this.helperNameValidator, + required this.onFormChanged, + required this.triggerTypeValidator, + required this.onTriggerValueSelected, + required this.defaultTriggerType, + required this.triggerTypes, + required this.onChangedNameText, + required this.minVersionValidator, + required this.maxVersionValidator, + required this.minVersionInitialValue, + required this.maxVersionInitialValue, + required this.minVersionChanged, + required this.maxVersionChanged }); @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(16.0), - child: Form( - key: _formKey, - onChanged: () => onFormChanged(_formKey.currentState.validate()), - child: ListView( - children: [ - LabeledForm( - label: 'New helper group name', - widget: BorderedTextField( - key: ValueKey('pal_CreateHelperGroup_TextField_Name'), - hintText: 'My new group name', - validator: helperNameValidator, - textCapitalization: TextCapitalization.sentences, - onValueChanged: onChangedNameText, + return Container( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Form( + key: _formKey, + onChanged: () => onFormChanged(_formKey.currentState!.validate()), + child: ListView( + children: [ + LabeledForm( + label: 'New helper group name', + widget: BorderedTextField( + key: ValueKey('pal_CreateHelperGroup_TextField_Name'), + hintText: 'My new group name', + validator: helperNameValidator, + textCapitalization: TextCapitalization.sentences, + onValueChanged: onChangedNameText, + ), ), - ), - SizedBox(height: 16), - LabeledForm( - label: 'Trigger type', - widget: DropdownButtonFormField( - key: ValueKey('pal_CreateHelperGroup_Dropdown_Type'), - validator: triggerTypeValidator, - value: defaultTriggerType, - items: triggerTypes.map( - (element) => DropdownMenuItem( - value: element, - child: Text(element.description), - ) - ).toList(), - onChanged: onTriggerValueSelected, - // items: _buildDropdownArray(), + SizedBox(height: 16), + LabeledForm( + label: 'Trigger type', + widget: DropdownButtonFormField( + key: ValueKey('pal_CreateHelperGroup_Dropdown_Type'), + validator: triggerTypeValidator, + value: defaultTriggerType, + items: triggerTypes!.map( + (element) => DropdownMenuItem( + value: element, + child: Text(element.description!), + ) + ).toList(), + onChanged: onTriggerValueSelected, + // items: _buildDropdownArray(), + ), ), - ), - SizedBox(height: 16), - LabeledForm( - label: 'Minimum app version', - widget: BorderedTextField( - key: ValueKey('pal_CreateHelper_TextField_MinimumVersion'), - textInputType: TextInputType.numberWithOptions(decimal: true), - initialValue: minVersionInitialValue, - onValueChanged: minVersionChanged, - validator: minVersionValidator, - isLoading: false, + SizedBox(height: 16), + LabeledForm( + label: 'Minimum app version', + widget: BorderedTextField( + key: ValueKey('pal_CreateHelper_TextField_MinimumVersion'), + textInputType: TextInputType.numberWithOptions(decimal: true), + initialValue: minVersionInitialValue, + onValueChanged: minVersionChanged, + validator: minVersionValidator, + isLoading: false, + ), ), - ), - SizedBox(height: 16), - LabeledForm( - label: 'Maximum app version', - widget: BorderedTextField( - key: ValueKey('pal_CreateHelper_TextField_MaximumVersion'), - textInputType: TextInputType.numberWithOptions(decimal: true), - initialValue: maxVersionInitialValue, - hintText: "Max version number or empty for latest version", - onValueChanged: maxVersionChanged, - validator: maxVersionValidator, - isLoading: false, + SizedBox(height: 16), + LabeledForm( + label: 'Maximum app version', + widget: BorderedTextField( + key: ValueKey('pal_CreateHelper_TextField_MaximumVersion'), + textInputType: TextInputType.numberWithOptions(decimal: true, signed: true), + initialValue: maxVersionInitialValue, + hintText: "Max version number or empty for latest version", + onValueChanged: maxVersionChanged, + validator: maxVersionValidator, + isLoading: false, + ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/src/ui/editor/pages/create_helper/steps/create_helper_infos/create_helper_infos_step.dart b/lib/src/ui/editor/pages/create_helper/steps/create_helper_infos/create_helper_infos_step.dart index d8d1b274..1f6aaac7 100644 --- a/lib/src/ui/editor/pages/create_helper/steps/create_helper_infos/create_helper_infos_step.dart +++ b/lib/src/ui/editor/pages/create_helper/steps/create_helper_infos/create_helper_infos_step.dart @@ -14,14 +14,14 @@ class CreateHelperInfosStep extends StatelessWidget { final CreateHelperPresenter presenter; - final Function() onFormChanged; + final Function()? onFormChanged; - final Function onTapChangePosition; + final Function? onTapChangePosition; const CreateHelperInfosStep({ - Key key, - @required this.model, - @required this.presenter, + Key? key, + required this.model, + required this.presenter, this.onFormChanged, this.onTapChangePosition }) : super(key: key); @@ -44,8 +44,8 @@ class CreateHelperInfosStep extends StatelessWidget { } void _checkFormValid() { - if (!model.isAppVersionLoading) { - model.isFormValid?.value = model.infosForm.currentState.validate(); + if (!model.isAppVersionLoading!) { + model.isFormValid?.value = model.infosForm!.currentState!.validate(); presenter.refreshView(); } } @@ -54,7 +54,7 @@ class CreateHelperInfosStep extends StatelessWidget { return Form( key: model.infosForm, onChanged: _checkFormValid, - autovalidateMode: AutovalidateMode.disabled, + autovalidateMode: AutovalidateMode.onUserInteraction, child: Wrap( runSpacing: 17.0, children: [ @@ -80,8 +80,8 @@ class CreateHelperInfosStep extends StatelessWidget { ); } // Check fields - String _checkHelperName(String value) { - if (value.isEmpty) { + String? _checkHelperName(String? value) { + if (value == null || value.isEmpty) { return 'Please enter a name'; } else if (value.length >= 45) { return 'Maximum 45 character allowed'; @@ -94,15 +94,15 @@ class CreateHelperInfosStep extends StatelessWidget { width: double.infinity, child: OutlineButton( key: ValueKey('palHelperPositionNextButton'), - borderSide: BorderSide(color: PalTheme.of(context).colors.dark), + borderSide: BorderSide(color: PalTheme.of(context)!.colors.dark!), child: Text( 'Change position in group', style: TextStyle( - color: PalTheme.of(context).colors.dark, + color: PalTheme.of(context)!.colors.dark, ), ), - color: PalTheme.of(context).colors.dark, - onPressed: onTapChangePosition, + color: PalTheme.of(context)!.colors.dark, + onPressed: onTapChangePosition as void Function()?, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0,), ), diff --git a/lib/src/ui/editor/pages/create_helper/steps/create_helper_infos/create_helper_infos_step_model.dart b/lib/src/ui/editor/pages/create_helper/steps/create_helper_infos/create_helper_infos_step_model.dart index 4f86174e..6f394c92 100644 --- a/lib/src/ui/editor/pages/create_helper/steps/create_helper_infos/create_helper_infos_step_model.dart +++ b/lib/src/ui/editor/pages/create_helper/steps/create_helper_infos/create_helper_infos_step_model.dart @@ -1,8 +1,8 @@ import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; class HelperTriggerTypeDisplay { - final HelperTriggerType key; - final String description; + final HelperTriggerType? key; + final String? description; HelperTriggerTypeDisplay({ this.key, diff --git a/lib/src/ui/editor/pages/create_helper/steps/create_helper_theme/create_helper_theme_step.dart b/lib/src/ui/editor/pages/create_helper/steps/create_helper_theme/create_helper_theme_step.dart index 894e4cae..66a2e3aa 100644 --- a/lib/src/ui/editor/pages/create_helper/steps/create_helper_theme/create_helper_theme_step.dart +++ b/lib/src/ui/editor/pages/create_helper/steps/create_helper_theme/create_helper_theme_step.dart @@ -10,9 +10,9 @@ class CreateHelperThemeStep extends StatelessWidget { final CreateHelperPresenter presenter; const CreateHelperThemeStep({ - Key key, - @required this.model, - @required this.presenter, + Key? key, + required this.model, + required this.presenter, }) : super(key: key); @override @@ -21,7 +21,7 @@ class CreateHelperThemeStep extends StatelessWidget { body: PreviewCardSwiperWidget( note: 'Note : you can customize colors / fonts… after this', onCardSelected: _checkFormValid, - cards: CreateHelperThemeStepModel.cards[model.selectedHelperType], + cards: CreateHelperThemeStepModel.cards[model.selectedHelperType!], ), ); } @@ -29,7 +29,7 @@ class CreateHelperThemeStep extends StatelessWidget { void _checkFormValid(int index) { bool isFormValid = false; for (PreviewThemeCard card - in CreateHelperThemeStepModel.cards[model.selectedHelperType]) { + in CreateHelperThemeStepModel.cards[model.selectedHelperType!]!) { if (card.isSelected) { isFormValid = true; model.selectedHelperTheme = card.helperTheme; diff --git a/lib/src/ui/editor/pages/create_helper/steps/create_helper_type/create_helper_type_step.dart b/lib/src/ui/editor/pages/create_helper/steps/create_helper_type/create_helper_type_step.dart index 36b3978b..aeb237bf 100644 --- a/lib/src/ui/editor/pages/create_helper/steps/create_helper_type/create_helper_type_step.dart +++ b/lib/src/ui/editor/pages/create_helper/steps/create_helper_type/create_helper_type_step.dart @@ -10,9 +10,9 @@ class CreateHelperTypeStep extends StatelessWidget { final CreateHelperPresenter presenter; const CreateHelperTypeStep({ - Key key, - @required this.model, - @required this.presenter, + Key? key, + required this.model, + required this.presenter, }) : super(key: key); @override diff --git a/lib/src/ui/editor/pages/create_helper/steps/select_group_position/helper_position_setup.dart b/lib/src/ui/editor/pages/create_helper/steps/select_group_position/helper_position_setup.dart index 7c5357c5..4a1c19d0 100644 --- a/lib/src/ui/editor/pages/create_helper/steps/select_group_position/helper_position_setup.dart +++ b/lib/src/ui/editor/pages/create_helper/steps/select_group_position/helper_position_setup.dart @@ -2,13 +2,13 @@ import 'package:flutter/material.dart'; import '../../../../../../theme.dart'; import '../../create_helper_viewmodel.dart'; -typedef OnValidate = void Function(int models); +typedef OnValidate = void Function(int? models); class HelperPositionPage extends StatefulWidget { - final Future> helpersLoader; - final OnValidate onValidate; + final Future>? helpersLoader; + final OnValidate? onValidate; - HelperPositionPage({this.helpersLoader, this.onValidate, Key key}) + HelperPositionPage({this.helpersLoader, this.onValidate, Key? key}) : super(key: key); @override @@ -16,8 +16,8 @@ class HelperPositionPage extends StatefulWidget { } class _HelperPositionPageState extends State { - List reorderableList; - int selectedRank; + List? reorderableList; + int? selectedRank; _HelperPositionPageState(); @@ -26,7 +26,7 @@ class _HelperPositionPageState extends State { return Scaffold( key: ValueKey("helper_position_page"), appBar: AppBar(title: Text("Position inside your group")), - body: FutureBuilder( + body: FutureBuilder>( future: widget.helpersLoader, builder: (context, snapshot) { if (snapshot.connectionState != ConnectionState.done || @@ -42,16 +42,26 @@ class _HelperPositionPageState extends State { top: 0, left: 0, right: 0, - bottom: 0, + bottom: 70, child: LayoutBuilder( builder: (context, constraints) => _buildReorderebleList(constraints)), ), Positioned( - bottom: 8.0, - left: 16.0, - right: 16.0, - child: _buildValidateButton(context)) + bottom: 8.0, + left: 16.0, + right: 16.0, + child: Column( + children: [ + Text( + 'You can change the position by long dragging item', + style: + TextStyle(fontSize: 10, fontWeight: FontWeight.w200), + ), + _buildValidateButton(context) + ], + ), + ) ], ); }, @@ -67,15 +77,15 @@ class _HelperPositionPageState extends State { : constraints.maxHeight, child: ReorderableListView( children: - reorderableList.map((element) => _buildItem(element)).toList(), + (reorderableList!.map((element) => _buildItem(element)).toList()), onReorder: (oldIndex, newIndex) { setState(() { if (oldIndex < newIndex) { newIndex -= 1; } - if (reorderableList[oldIndex].id == "NEW_HELPER") { - var element = reorderableList.removeAt(oldIndex); - reorderableList.insert(newIndex, element); + if (reorderableList![oldIndex].id == "NEW_HELPER") { + var element = reorderableList!.removeAt(oldIndex); + reorderableList!.insert(newIndex, element); this.selectedRank = newIndex; } }); @@ -86,34 +96,37 @@ class _HelperPositionPageState extends State { Widget _buildItem(GroupHelperViewModel element) { return Padding( - key: ValueKey(element?.id), + key: ValueKey(element.id), padding: const EdgeInsets.symmetric(vertical: 1.0), child: ListTile( - title: Text(element.title), + title: Text(element.title!.isEmpty ? "[No name]" : element.title!), tileColor: element.id != "NEW_HELPER" ? Colors.grey.withOpacity(.2) - : PalTheme.of(context).colors.color1.withOpacity(.2), + : PalTheme.of(context)!.colors.color1!.withOpacity(.2), ), ); } _buildValidateButton(BuildContext context) { - return RaisedButton( - key: ValueKey('palHelperPositionNextButton'), - disabledColor: PalTheme.of(context).colors.color4, - child: Text( - 'Validate position', - style: TextStyle( - color: Colors.white, + return SizedBox( + width: double.infinity, + child: RaisedButton( + key: ValueKey('palHelperPositionNextButton'), + disabledColor: PalTheme.of(context)!.colors.color4, + child: Text( + 'Validate position', + style: TextStyle( + color: Colors.white, + ), + ), + color: PalTheme.of(context)!.colors.color1, + onPressed: () { + widget.onValidate!(this.selectedRank); + Navigator.of(context).pop(); + }, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), ), - ), - color: PalTheme.of(context).colors.color1, - onPressed: () { - widget.onValidate(this.selectedRank); - Navigator.of(context).pop(); - }, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), ), ); } diff --git a/lib/src/ui/editor/pages/create_helper/steps/setup_group/select_helper_group.dart b/lib/src/ui/editor/pages/create_helper/steps/setup_group/select_helper_group.dart index 91c56093..270be37e 100644 --- a/lib/src/ui/editor/pages/create_helper/steps/setup_group/select_helper_group.dart +++ b/lib/src/ui/editor/pages/create_helper/steps/setup_group/select_helper_group.dart @@ -12,11 +12,11 @@ typedef OnTapHelperGroup = void Function(HelperGroupViewModel tapedElement); /// --------------------------------------------------------- class SelectHelperGroupPage extends StatelessWidget { - final HelperGroupLoader helperGroupLoader; + final HelperGroupLoader? helperGroupLoader; - final Function onTapAdd; + final Function? onTapAdd; - final OnTapHelperGroup onTapElement; + final OnTapHelperGroup? onTapElement; SelectHelperGroupPage({this.helperGroupLoader, this.onTapAdd, this.onTapElement}); @@ -28,9 +28,9 @@ class SelectHelperGroupPage extends StatelessWidget { _AddGroupButton(onTapAdd: onTapAdd), Expanded( child: FutureBuilder>( - future: helperGroupLoader(), + future: helperGroupLoader!(), builder: (ctx, snapshot) => snapshot.connectionState == ConnectionState.done - ? (!snapshot.hasData || snapshot.data.length == 0) ? _buildEmptyList() : _buildItems(snapshot.data) + ? (!snapshot.hasData || snapshot.data!.length == 0) ? _buildEmptyList() : _buildItems(snapshot.data!) : _buildLoading(), ), ), @@ -56,21 +56,21 @@ class HelperGroupItemLine extends StatelessWidget { final HelperGroupViewModel model; - final OnTapHelperGroup onTapElement; + final OnTapHelperGroup? onTapElement; HelperGroupItemLine(this.model, this.onTapElement); @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: model, - builder: (ctx, value, child) => ListTile( - onTap: () => onTapElement(value), + builder: (ctx, dynamic value, child) => ListTile( + onTap: () => onTapElement!(value), selected: value.selected, - selectedTileColor: PalTheme.of(context).colors.color4, + selectedTileColor: PalTheme.of(context)!.colors.color4, title: Text(value?.title ?? "", style: TextStyle( fontSize: 16, - color: PalTheme.of(context).colors.dark, + color: PalTheme.of(context)!.colors.dark, fontFamily: 'Montserrat', fontWeight: FontWeight.w500 ), @@ -86,27 +86,27 @@ class HelperGroupItemLine extends StatelessWidget { /// --------------------------------------------------------- class _AddGroupButton extends StatelessWidget { - final Function onTapAdd; + final Function? onTapAdd; - _AddGroupButton({@required this.onTapAdd}); + _AddGroupButton({required this.onTapAdd}); @override Widget build(BuildContext context) => InkWell( - onTap: this.onTapAdd, + onTap: this.onTapAdd as void Function()?, child: Container( - color: PalTheme.of(context).colors.color3, + color: PalTheme.of(context)!.colors.color3, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16), child: Row( children: [ - Icon(Icons.add, color: PalTheme.of(context).colors.light), + Icon(Icons.add, color: PalTheme.of(context)!.colors.light), SizedBox(width: 8), Text("Create new group", style: TextStyle( fontSize: 18, fontFamily: 'Montserrat', fontWeight: FontWeight.w500, - color: PalTheme.of(context).colors.light)) + color: PalTheme.of(context)!.colors.light)) ], ), ), diff --git a/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/dot_indicators.dart b/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/dot_indicators.dart index d696975f..793bff40 100644 --- a/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/dot_indicators.dart +++ b/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/dot_indicators.dart @@ -5,9 +5,9 @@ class DotIndicatorsWidget extends StatelessWidget { final int pagesCount; final int activePage; const DotIndicatorsWidget({ - Key key, - @required this.pagesCount, - @required this.activePage, + Key? key, + required this.pagesCount, + required this.activePage, }) : super(key: key); @override @@ -38,7 +38,7 @@ class DotIndicatorsWidget extends StatelessWidget { height: 20, decoration: BoxDecoration( shape: BoxShape.circle, - color: PalTheme.of(context).colors.dark, + color: PalTheme.of(context)!.colors.dark, ), ); } @@ -49,7 +49,7 @@ class DotIndicatorsWidget extends StatelessWidget { height: 10, decoration: BoxDecoration( shape: BoxShape.circle, - color: PalTheme.of(context).colors.dark.withAlpha(50), + color: PalTheme.of(context)!.colors.dark!.withAlpha(50), ), ); } diff --git a/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card.dart b/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card.dart index 58ea9cfd..b2a52b2e 100644 --- a/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card.dart +++ b/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card.dart @@ -19,12 +19,12 @@ class PreviewCard { class PreviewCardWidget extends StatefulWidget { final PreviewCard cardData; - final int index; - final Function(int) onTap; + final int? index; + final Function(int)? onTap; const PreviewCardWidget({ - Key key, - @required this.cardData, + Key? key, + required this.cardData, this.index, this.onTap, }) : super(key: key); @@ -40,13 +40,13 @@ class _PreviewCardWidgetState extends State Widget build(BuildContext context) { return BouncingWidget( key: ValueKey('pal_PreviewCard_${widget.index}'), - onTap: () => widget.onTap?.call(widget.index), + onTap: () => widget.onTap?.call(widget.index!), child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(25.0), side: (widget.cardData.isSelected) ? BorderSide( - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1!, width: 6.0, ) : BorderSide.none, @@ -63,7 +63,7 @@ class _PreviewCardWidgetState extends State vertical: 20.0, horizontal: 35.0, ), - child: Image.asset(widget.cardData.previewImage, package: 'pal'), + child: Center(child: Image.asset(widget.cardData.previewImage, package: 'pal')), ), ), Padding( @@ -116,7 +116,7 @@ class _PreviewCardWidgetState extends State topRight: const Radius.circular(25.0), bottomLeft: const Radius.circular(25.0), ), - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1, ), child: Center( child: Icon( diff --git a/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card_swiper.dart b/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card_swiper.dart index 96e8405f..d6336144 100644 --- a/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card_swiper.dart +++ b/lib/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card_swiper.dart @@ -6,13 +6,13 @@ import 'package:pal/src/ui/editor/pages/create_helper/widgets/preview_card_swipe import 'package:pal/src/ui/editor/pages/create_helper/widgets/preview_card_swiper/preview_card.dart'; class PreviewCardSwiperWidget extends StatefulWidget { - final List cards; - final String note; - final Function(int) onCardSelected; + final List? cards; + final String? note; + final Function(int)? onCardSelected; PreviewCardSwiperWidget({ - Key key, - @required this.cards, + Key? key, + required this.cards, this.note, this.onCardSelected, }) : super(key: key); @@ -24,7 +24,7 @@ class PreviewCardSwiperWidget extends StatefulWidget { class _PreviewCardSwiperWidgetState extends State with SingleTickerProviderStateMixin { - PageController _controller; + PageController? _controller; int _currentpage = 0; @override @@ -38,7 +38,7 @@ class _PreviewCardSwiperWidgetState extends State @override dispose() { - _controller.dispose(); + _controller!.dispose(); super.dispose(); } @@ -49,10 +49,10 @@ class _PreviewCardSwiperWidgetState extends State children: [ if (widget.note != null) Text( - widget.note, + widget.note!, style: TextStyle( fontWeight: FontWeight.w300, - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1, fontSize: 10, ), ), @@ -63,7 +63,7 @@ class _PreviewCardSwiperWidgetState extends State PageView.builder( key: ValueKey('pal_PreviewCardSwiperWidget_PageView'), controller: _controller, - itemCount: widget.cards.length, + itemCount: widget.cards!.length, onPageChanged: _onPageViewChange, itemBuilder: (BuildContext context, int index) { return _buildPreviewCard( @@ -78,7 +78,7 @@ class _PreviewCardSwiperWidgetState extends State right: 0, child: DotIndicatorsWidget( activePage: _currentpage, - pagesCount: widget.cards.length, + pagesCount: widget.cards!.length, ), ), ], @@ -100,7 +100,7 @@ class _PreviewCardSwiperWidgetState extends State BuildContext context, int index, ) { - PreviewCard cardData = widget.cards[index]; + PreviewCard cardData = widget.cards![index]; return Padding( padding: EdgeInsets.only( @@ -119,17 +119,16 @@ class _PreviewCardSwiperWidgetState extends State void _onCardTap(int index) { int i = 0; - for (PreviewCard cardData in widget.cards) { + for (PreviewCard cardData in widget.cards!) { if (index == i++) { cardData.isSelected = !cardData.isSelected; } else { cardData.isSelected = false; } } - this.setState(() {}); - + setState(() {}); if (widget.onCardSelected != null) { - widget.onCardSelected(index); + widget.onCardSelected!(index); } } } diff --git a/lib/src/ui/editor/pages/group_details/group_details.dart b/lib/src/ui/editor/pages/group_details/group_details.dart index 643ebaba..6c1bfda3 100644 --- a/lib/src/ui/editor/pages/group_details/group_details.dart +++ b/lib/src/ui/editor/pages/group_details/group_details.dart @@ -19,22 +19,24 @@ abstract class GroupDetailsView { void showSucess(String text); void showEditor( - String routeName, String helperId, String groupId, HelperType type); + String? routeName, String helperId, String? groupId, HelperType type); void pop(); void previewHelper(String id) {} + + Future showGroupDeleteModal(); } class GroupDetailsPage extends StatelessWidget with SnackbarMixin implements GroupDetailsView { - final String groupId; - final String routeName; - final PageStep page; + final String? groupId; + final String? routeName; + final PageStep? page; GroupDetailsPage( - {Key key, @required this.groupId, @required this.routeName, this.page}) + {Key? key, required this.groupId, required this.routeName, this.page}) : super(key: key); final _mvvmBuilder = @@ -53,9 +55,9 @@ class GroupDetailsPage extends StatelessWidget GroupDetailsPageModel( this.groupId, GlobalKey(), this.routeName, page), this, - helperService: EditorInjector.of(context).helperService, - groupService: EditorInjector.of(context).helperGroupService, - versionService: EditorInjector.of(context).versionEditorService), + helperService: EditorInjector.of(context)!.helperService, + groupService: EditorInjector.of(context)!.helperGroupService, + versionService: EditorInjector.of(context)!.versionEditorService), builder: (context, presenter, model) => _buildPage(context, presenter, model), ); @@ -72,9 +74,9 @@ class GroupDetailsPage extends StatelessWidget return true; }, child: Theme( - data: PalTheme.of(context.buildContext).buildTheme().copyWith( + data: PalTheme.of(context.buildContext)!.buildTheme().copyWith( dividerTheme: DividerThemeData(color: Colors.transparent), - accentColor: PalTheme.of(context.buildContext).colors.color1, + accentColor: PalTheme.of(context.buildContext)!.colors.color1, ), child: Scaffold( key: _scaffoldKey, @@ -86,10 +88,10 @@ class GroupDetailsPage extends StatelessWidget leading: GestureDetector( onTap: () { Navigator.pop(context.buildContext); - EditorInjector.of(context.buildContext) + EditorInjector.of(context.buildContext)! .palEditModeStateService - .showHelpersList(EditorInjector.of(context.buildContext) - .hostedAppNavigatorKey + .showHelpersList(EditorInjector.of(context.buildContext)! + .hostedAppNavigatorKey! .currentContext); }, child: Icon( @@ -151,7 +153,7 @@ class GroupDetailsPage extends StatelessWidget ], icon: Icon(Icons.more_horiz), offset: Offset(0, 24), - onSelected: (val) => presenter.deleteGroup(), + onSelected: (dynamic val) => presenter.onDeleteTap(), ) ], // *******MENU BUTTON @@ -196,34 +198,34 @@ class GroupDetailsPage extends StatelessWidget @override void showEditor( - String routeName, String helperId, String groupId, HelperType type) { + String? routeName, String helperId, String? groupId, HelperType type) { // POP CURRENT ROUTE, THE OVERLAY MUST BE ON TOP OF CLIENT ROUTE - Navigator.pop(_scaffoldKey.currentContext); - var navKey = EditorInjector.of(this._scaffoldKey.currentContext) + Navigator.pop(_scaffoldKey.currentContext!); + var navKey = EditorInjector.of(this._scaffoldKey.currentContext!)! .hostedAppNavigatorKey; EditorRouter router = EditorRouter(navKey); // SHOWING EDITOR HELPER WITH PAL CONTEXT IN ORDER TO RETURN TO THIS PAGE router.editHelper(routeName, helperId, type, groupId, - con: EditorInjector.of(this._scaffoldKey.currentContext) - .palNavigatorKey + con: EditorInjector.of(this._scaffoldKey.currentContext!)! + .palNavigatorKey! .currentContext); } @override void pop() { - Navigator.pop(_scaffoldKey.currentContext); - EditorInjector.of(_scaffoldKey.currentContext) + Navigator.pop(_scaffoldKey.currentContext!); + EditorInjector.of(_scaffoldKey.currentContext!)! .palEditModeStateService - .showHelpersList(EditorInjector.of(_scaffoldKey.currentContext) - .hostedAppNavigatorKey + .showHelpersList(EditorInjector.of(_scaffoldKey.currentContext!)! + .hostedAppNavigatorKey! .currentContext); } @override void previewHelper(String id) async { - Navigator.pop(_scaffoldKey.currentContext); + Navigator.pop(_scaffoldKey.currentContext!); var navKey = - EditorInjector.of(this._scaffoldKey.currentContext).palNavigatorKey; + EditorInjector.of(this._scaffoldKey.currentContext!)!.palNavigatorKey!; EditorPreviewArguments arguments = EditorPreviewArguments( (context) => Navigator.of(context).pushReplacementNamed( '/editor/group/details', @@ -235,9 +237,38 @@ class GroupDetailsPage extends StatelessWidget ), helperId: id); await Navigator.pushNamed( - navKey.currentContext, + navKey.currentContext!, '/editor/preview', arguments: arguments, ); } + + @override + Future showGroupDeleteModal() async { + return await showDialog( + context: _scaffoldKey.currentContext!, + builder: (BuildContext context) { + return AlertDialog( + title: Text('Confirmation'), + content: Text('Do you really want to remove this group?'), + actions: [ + TextButton( + key: ValueKey('DeleteGroupConfirmationCancelButton'), + child: Text('Cancel'), + onPressed: () { + Navigator.of(context).pop(false); + }, + ), + TextButton( + key: ValueKey('DeleteGroupConfirmationYesButton'), + child: Text('Delete', style: TextStyle(color: Colors.redAccent),), + onPressed: () { + Navigator.of(context).pop(true); + }, + ), + ], + ); + }, + ); + } } diff --git a/lib/src/ui/editor/pages/group_details/group_details_model.dart b/lib/src/ui/editor/pages/group_details/group_details_model.dart index f327a2b9..76ea00cf 100644 --- a/lib/src/ui/editor/pages/group_details/group_details_model.dart +++ b/lib/src/ui/editor/pages/group_details/group_details_model.dart @@ -13,35 +13,35 @@ class GroupDetailsPageModel extends MVVMModel { final startPage; // GROUP INFO / GROUP HELPERS - GroupModel groupModel; - ValueNotifier> helpers; + late GroupModel groupModel; + late ValueNotifier?> helpers; // GROUP INFO CONTROLLERS & FORM KEY - TextEditingController groupNameController; - HelperTriggerType groupTriggerValue; - TextEditingController groupMinVerController; - TextEditingController groupMaxVerController; + TextEditingController? groupNameController; + HelperTriggerType? groupTriggerValue; + TextEditingController? groupMinVerController; + TextEditingController? groupMaxVerController; final GlobalKey formKey; // STATE ATTRIBUTES - bool loading; - PageStep page; - ValueNotifier canSave; - PageController pageController; + bool? loading; + PageStep? page; + late ValueNotifier canSave; + PageController? pageController; - bool editorMode; - bool locked; + bool? editorMode; + bool? locked; GroupDetailsPageModel(this.groupId, this.formKey, this.routeName, this.startPage); } class GroupModel { - HelperTriggerType triggerType; - String name; - String minVer; - String maxVer; - String groupRoute; + HelperTriggerType? triggerType; + String? name; + String? minVer; + String? maxVer; + String? groupRoute; GroupModel({this.triggerType, this.name, this.minVer, this.maxVer}); @@ -54,11 +54,11 @@ class GroupModel { } class HelperModel { - String helperId; - String title; - HelperType type; - int priority; - DateTime creationDate; + String? helperId; + String? title; + HelperType? type; + int? priority; + DateTime? creationDate; HelperModel( {this.title, this.type, this.priority, this.creationDate, this.helperId}); diff --git a/lib/src/ui/editor/pages/group_details/group_details_presenter.dart b/lib/src/ui/editor/pages/group_details/group_details_presenter.dart index 4eed7904..1d855873 100644 --- a/lib/src/ui/editor/pages/group_details/group_details_presenter.dart +++ b/lib/src/ui/editor/pages/group_details/group_details_presenter.dart @@ -13,14 +13,14 @@ import 'group_details_model.dart'; class GroupDetailsPresenter extends Presenter { final EditorHelperGroupService groupService; - final EditorHelperService helperService; + final EditorHelperService? helperService; final VersionEditorService versionService; GroupDetailsPresenter( GroupDetailsPageModel viewModel, GroupDetailsView viewInterface, {this.helperService, - @required this.groupService, - @required this.versionService}) + required this.groupService, + required this.versionService}) : super(viewModel, viewInterface); @override @@ -36,7 +36,7 @@ class GroupDetailsPresenter this.viewModel.canSave = ValueNotifier(false); this.viewModel.page = this.viewModel.startPage ?? PageStep.DETAILS; this.viewModel.pageController = - PageController(initialPage: this.viewModel.page.index); + PageController(initialPage: this.viewModel.page!.index); // *CONTROLLERS this.viewModel.groupMaxVerController = TextEditingController(); @@ -49,11 +49,12 @@ class GroupDetailsPresenter this.viewModel.groupModel = GroupModel.from(group); // ASSIGNING INITIALS VALUES TO CONTROLLERS - this.viewModel.groupMaxVerController.text = - this.viewModel.groupModel.maxVer; - this.viewModel.groupMinVerController.text = - this.viewModel.groupModel.minVer; - this.viewModel.groupNameController.text = this.viewModel.groupModel.name; + this.viewModel.groupMaxVerController!.text = + this.viewModel.groupModel.maxVer ?? ''; + this.viewModel.groupMinVerController!.text = + this.viewModel.groupModel.minVer!; + this.viewModel.groupNameController!.text = + this.viewModel.groupModel.name!; this.viewModel.groupTriggerValue = this.viewModel.groupModel.triggerType; // ENDING LOADING @@ -70,18 +71,17 @@ class GroupDetailsPresenter // SERVER CALLS [SAVE,DELETE] void save() { - if (!this.viewModel.locked) { + if (!this.viewModel.locked!) { this.viewModel.locked = true; this.viewModel.loading = true; this.refreshView(); Future.wait([ this .versionService - .getOrCreateVersionId(this.viewModel.groupMinVerController.text), - this.viewModel.groupMaxVerController.text.isNotEmpty - ? this - .versionService - .getOrCreateVersionId(this.viewModel.groupMaxVerController.text) + .getOrCreateVersionId(this.viewModel.groupMinVerController!.text), + this.viewModel.groupMaxVerController!.text.isNotEmpty + ? this.versionService.getOrCreateVersionId( + this.viewModel.groupMaxVerController!.text) : Future.value(null), ]).catchError((err) { this.viewModel.loading = false; @@ -93,7 +93,7 @@ class GroupDetailsPresenter id: this.viewModel.groupId, maxVersionId: res[1], minVersionId: res[0], - name: this.viewModel.groupNameController.text, + name: this.viewModel.groupNameController!.text, type: this.viewModel.groupTriggerValue, ); this.groupService.updateGroup(updated).then((res) { @@ -111,8 +111,15 @@ class GroupDetailsPresenter } } + void onDeleteTap() async { + var result = await this.viewInterface.showGroupDeleteModal(); + if (result) { + this.deleteGroup(); + } + } + void deleteGroup() { - if (!this.viewModel.locked) { + if (!this.viewModel.locked!) { this.viewModel.loading = true; this.refreshView(); this.groupService.deleteGroup(this.viewModel.groupId).then((done) { @@ -126,7 +133,7 @@ class GroupDetailsPresenter } // CONTROLLERS SUBMIT CHECKS && VALIDATOR - onNewTrigger(HelperTriggerType newTrigger) { + onNewTrigger(HelperTriggerType? newTrigger) { this.viewModel.groupTriggerValue = newTrigger; this.viewModel.canSave.value = true; } @@ -143,8 +150,8 @@ class GroupDetailsPresenter if (val != this.viewModel.groupModel.maxVer) this.updateState(); } - String validateVersion(String val) { - if (val.contains(new RegExp( + String? validateVersion(String? val) { + if (val!.contains(new RegExp( r'^(?(?0|[1-9][0-9]*)\.(?0|[1-9][0-9]*)\.(?0|[1-9][0-9]*))$'))) { this.viewModel.locked = false; return null; @@ -153,8 +160,8 @@ class GroupDetailsPresenter return 'Invalid version format'; } - String validateName(String val) { - if (val.isNotEmpty) { + String? validateName(String? val) { + if (val != null && val.isNotEmpty) { this.viewModel.locked = false; return null; } @@ -164,26 +171,26 @@ class GroupDetailsPresenter // STATE CHANGES void goToHelpersList() { - if (!this.viewModel.loading) { + if (!this.viewModel.loading!) { this.viewModel.page = PageStep.HELPERS; - this.viewModel.pageController.animateToPage(1, + this.viewModel.pageController!.animateToPage(1, curve: Curves.easeOut, duration: Duration(milliseconds: 250)); this.refreshView(); } } void goToGroupDetails() { - if (!this.viewModel.loading) { + if (!this.viewModel.loading!) { this.viewModel.page = PageStep.DETAILS; - this.viewModel.pageController.animateToPage(0, + this.viewModel.pageController!.animateToPage(0, curve: Curves.easeOut, duration: Duration(milliseconds: 250)); this.refreshView(); } } void updateState() { - this.viewModel.canSave.value = !this.viewModel.locked && - this.viewModel.formKey.currentState.validate(); + this.viewModel.canSave.value = !this.viewModel.locked! && + this.viewModel.formKey.currentState!.validate(); } // HELPERS ACTIONS / PREVIEW / EDIT / DELETE @@ -195,11 +202,11 @@ class GroupDetailsPresenter Future deleteHelper(String id) { this.viewModel.loading = true; this.refreshView(); - return this.helperService.deleteHelper(id).then((done) { + return this.helperService!.deleteHelper(id).then((done) { this.viewModel.helpers.value = this .viewModel .helpers - .value + .value! .where((helper) => helper.helperId != id) .toList(); this.viewModel.loading = false; diff --git a/lib/src/ui/editor/pages/group_details/widgets/group_details_helpers.dart b/lib/src/ui/editor/pages/group_details/widgets/group_details_helpers.dart index dd2c6cb8..21aeb7cf 100644 --- a/lib/src/ui/editor/pages/group_details/widgets/group_details_helpers.dart +++ b/lib/src/ui/editor/pages/group_details/widgets/group_details_helpers.dart @@ -8,27 +8,27 @@ typedef Future OnDelete(String id); class GroupDetailsHelpersList extends StatelessWidget { // CORE ATTRIBUTES - final ValueNotifier> helpersList; + final ValueNotifier?>? helpersList; final OnPreview onPreview; final OnEdit onEdit; final OnDelete onDelete; - final bool loading; + final bool? loading; - final ValueNotifier expandedTile = ValueNotifier(null); + final ValueNotifier expandedTile = ValueNotifier(null); GroupDetailsHelpersList({ - Key key, + Key? key, this.helpersList, - @required this.onPreview, - @required this.onEdit, - @required this.onDelete, - @required this.loading, + required this.onPreview, + required this.onEdit, + required this.onDelete, + required this.loading, }) : super(key: key); @override Widget build(BuildContext context) { - return ValueListenableBuilder>( - valueListenable: this.helpersList, + return ValueListenableBuilder?>( + valueListenable: this.helpersList!, builder: (context, value, child) { if (value == null) { return Container( @@ -38,12 +38,12 @@ class GroupDetailsHelpersList extends StatelessWidget { )), ); } else { - return value == null || value.length == 0 + return value.length == 0 ? Center( child: Text('No helpers found.'), ) : Opacity( - opacity: this.loading ? .5 : 1, + opacity: this.loading! ? .5 : 1, child: ListView.separated( itemBuilder: (context, index) { return GroupDetailsHelperTile( @@ -80,16 +80,16 @@ class GroupDetailsHelperTile extends StatefulWidget { final HelperModel model; - final int index; + final int? index; - final ValueNotifier expandedTile; + final ValueNotifier? expandedTile; const GroupDetailsHelperTile( - {Key key, - this.onPreview, - this.onEdit, - this.onDelete, - this.model, + {Key? key, + required this.onPreview, + required this.onEdit, + required this.onDelete, + required this.model, this.index, this.expandedTile}) : super(key: key); @@ -100,7 +100,7 @@ class GroupDetailsHelperTile extends StatefulWidget { class _GroupDetailsHelperTileState extends State with SingleTickerProviderStateMixin { - AnimationController controller; + late AnimationController controller; @override void initState() { @@ -109,8 +109,8 @@ class _GroupDetailsHelperTileState extends State this.controller = AnimationController( vsync: this, value: 0, lowerBound: animationLowerBound, upperBound: 0); - widget.expandedTile.addListener(() { - if (widget.expandedTile.value != widget.index) + widget.expandedTile!.addListener(() { + if (widget.expandedTile!.value != widget.index) this.controller.animateTo(0, curve: Curves.easeOut, duration: Duration(milliseconds: 250)); }); @@ -123,27 +123,27 @@ class _GroupDetailsHelperTileState extends State Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - _ActionWidget( + ActionWidget( key: ValueKey('PreviewHelperButton${widget.model.helperId}'), color: Color(0xFF3EB4D9), icon: Icons.play_arrow, text: 'Preview', - onTap: () => widget.onPreview(widget.model.helperId), + onTap: () => widget.onPreview(widget.model.helperId!), ), - _ActionWidget( + ActionWidget( key: ValueKey('EditHelperButton${widget.model.helperId}'), color: Color(0xFF90E0EF), icon: Icons.edit, text: 'Edit', onTap: () => - widget.onEdit(widget.model.helperId, widget.model.type), + widget.onEdit(widget.model.helperId!, widget.model.type!), ), - _ActionWidget( + ActionWidget( key: ValueKey('DeleteHelperButton${widget.model.helperId}'), color: Color(0xFFEB5160), icon: Icons.delete, text: 'Delete', - onTap: () => widget.onDelete(widget.model.helperId)), + onTap: () => widget.onDelete(widget.model.helperId!)), ], ), GestureDetector( @@ -151,7 +151,7 @@ class _GroupDetailsHelperTileState extends State this.controller.value = this.controller.value + details.delta.dx; }, onHorizontalDragEnd: (details) { - if (details.primaryVelocity > 0 || + if (details.primaryVelocity! > 0 || this.controller.value > animationLowerBound / 2) { this.controller.animateTo(0, curve: Curves.easeOutBack, @@ -160,7 +160,7 @@ class _GroupDetailsHelperTileState extends State this.controller.animateTo(this.controller.lowerBound, curve: Curves.easeOutBack, duration: Duration(milliseconds: 250)); - widget.expandedTile.value = widget.index; + widget.expandedTile!.value = widget.index; } }, child: SizedBox( @@ -191,7 +191,7 @@ class _GroupDetailsHelperTileState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.model.title, + widget.model.title!, overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14), @@ -200,7 +200,7 @@ class _GroupDetailsHelperTileState extends State height: 4, ), Text( - getHelperTypeDescription(widget.model.type), + getHelperTypeDescription(widget.model.type)!, overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.w200, fontSize: 10), @@ -209,7 +209,7 @@ class _GroupDetailsHelperTileState extends State height: 16, ), Text( - 'Created on ${widget.model.creationDate.day} / ${widget.model.creationDate.month} / ${widget.model.creationDate.year}', + 'Created on ${widget.model.creationDate!.day} / ${widget.model.creationDate!.month} / ${widget.model.creationDate!.year}', overflow: TextOverflow.ellipsis, style: TextStyle( fontWeight: FontWeight.w100, fontSize: 6), @@ -229,13 +229,13 @@ class _GroupDetailsHelperTileState extends State } } -class _ActionWidget extends StatelessWidget { - final IconData icon; - final String text; - final Color color; - final Function onTap; +class ActionWidget extends StatelessWidget { + final IconData? icon; + final String? text; + final Color? color; + final Function? onTap; - const _ActionWidget({Key key, this.icon, this.text, this.color, this.onTap}) + const ActionWidget({Key? key, this.icon, this.text, this.color, this.onTap}) : super(key: key); @override @@ -247,7 +247,7 @@ class _ActionWidget extends StatelessWidget { child: Material( color: Colors.transparent, child: InkWell( - onTap: this.onTap, + onTap: this.onTap as void Function()?, splashColor: Colors.black, child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -260,7 +260,7 @@ class _ActionWidget extends StatelessWidget { height: 14, ), Text( - this.text, + this.text!, style: TextStyle(fontSize: 10), ), ], diff --git a/lib/src/ui/editor/pages/group_details/widgets/group_details_infos.dart b/lib/src/ui/editor/pages/group_details/widgets/group_details_infos.dart index f9245bcb..23211ed2 100644 --- a/lib/src/ui/editor/pages/group_details/widgets/group_details_infos.dart +++ b/lib/src/ui/editor/pages/group_details/widgets/group_details_infos.dart @@ -16,7 +16,7 @@ class GroupDetailsInfo extends StatelessWidget { const GroupDetailsInfo( this.presenter, this.model, { - Key key, + Key? key, }) : super(key: key); @override @@ -31,7 +31,7 @@ class GroupDetailsInfo extends StatelessWidget { children: [ Expanded( child: Opacity( - opacity: model.loading ? .2 : 1, + opacity: model.loading! ? .2 : 1, child: SingleChildScrollView( padding: EdgeInsets.all(24), child: Column( @@ -73,7 +73,7 @@ class GroupDetailsInfo extends StatelessWidget { key: ValueKey('MaxVersionField'), label: 'Maximum version', validator: (val) { - if (val.isEmpty) return null; + if (val == null || val.isEmpty) return null; return presenter.validateVersion(val); }, hint: 'Default set to latest', @@ -86,16 +86,16 @@ class GroupDetailsInfo extends StatelessWidget { ), ), ), - if (!model.loading) + if (!model.loading!) Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: ValueListenableBuilder( valueListenable: model.canSave, - builder: (context, value, child) => ElevatedButton( + builder: (context, dynamic value, child) => ElevatedButton( key: ValueKey('saveButton'), style: ButtonStyle( backgroundColor: MaterialStateColor.resolveWith( - (states) => PalTheme.of(context).colors.color1), + (states) => PalTheme.of(context)!.colors.color1!), shape: MaterialStateProperty.resolveWith((states) => RoundedRectangleBorder( borderRadius: BorderRadius.circular(8))), @@ -111,7 +111,7 @@ class GroupDetailsInfo extends StatelessWidget { Divider( height: 8, ), - if (model.loading) + if (model.loading!) LinearProgressIndicator( value: null, minHeight: 5, @@ -123,14 +123,14 @@ class GroupDetailsInfo extends StatelessWidget { } class DetailsTextField extends StatelessWidget { - final String label, hint; + final String? label, hint; final TextInputType keyboardType; - final TextEditingController controller; - final String Function(String) validator; - final Function(String) onFieldSubmitted; + final TextEditingController? controller; + final String? Function(String?)? validator; + final Function(String)? onFieldSubmitted; const DetailsTextField( - {Key key, + {Key? key, this.label, this.controller, this.hint, @@ -157,15 +157,15 @@ class DetailsTextField extends StatelessWidget { } class DetailsSelectField extends StatelessWidget { - final String label; - final HelperTriggerType initialValue; - final Function(HelperTriggerType newTrigger) newTriggerCallBack; + final String? label; + final HelperTriggerType? initialValue; + final Function(HelperTriggerType? newTrigger) newTriggerCallBack; const DetailsSelectField( - {Key key, + {Key? key, this.label, - @required this.newTriggerCallBack, - @required this.initialValue}) + required this.newTriggerCallBack, + required this.initialValue}) : super(key: key); @override @@ -177,7 +177,7 @@ class DetailsSelectField extends StatelessWidget { items: HelperTriggerType.values .map((element) => DropdownMenuItem( value: element, - child: Text(getHelperTriggerTypeDescription(element)), + child: Text(getHelperTriggerTypeDescription(element)!), )) .toList(), onChanged: (val) { diff --git a/lib/src/ui/editor/pages/group_details/widgets/group_details_tabs.dart b/lib/src/ui/editor/pages/group_details/widgets/group_details_tabs.dart index 94d63067..a0767886 100644 --- a/lib/src/ui/editor/pages/group_details/widgets/group_details_tabs.dart +++ b/lib/src/ui/editor/pages/group_details/widgets/group_details_tabs.dart @@ -3,25 +3,25 @@ import 'package:flutter/material.dart'; import 'dart:ui' as ui; class GroupDetailsTabWidget extends StatelessWidget { - final String label; + final String? label; final bool active; - final Function onTap; + final Function? onTap; const GroupDetailsTabWidget( - {Key key, this.label, this.active = false, this.onTap}) + {Key? key, this.label, this.active = false, this.onTap}) : super(key: key); @override Widget build(BuildContext context) { return InkWell( - onTap: this.onTap, + onTap: this.onTap as void Function()?, child: CustomPaint( painter: TabCustomBorder(this.active), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ - Text(this.label), + Text(this.label!), ], ), ), diff --git a/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview.dart b/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview.dart index 3def238c..628e290e 100644 --- a/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview.dart +++ b/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview.dart @@ -17,8 +17,8 @@ import 'editor_preview_presenter.dart'; import 'editor_preview_viewmodel.dart'; class EditorPreviewArguments { - final String helperId; - final Widget preBuiltHelper; + final String? helperId; + final Widget? preBuiltHelper; final Function(BuildContext) onDismiss; EditorPreviewArguments( @@ -29,25 +29,21 @@ class EditorPreviewArguments { } abstract class EditorPreviewView { - Widget buildFullscreen( - HelperEntity helperEntity, Function(BuildContext) onDismiss); + Widget buildFullscreen(HelperEntity helperEntity, Function(BuildContext?) onDismiss); - Widget buildSimple( - HelperEntity helperEntity, Function(BuildContext) onDismiss); + Widget buildSimple(HelperEntity helperEntity, Function(BuildContext?) onDismiss); - Widget buildAnchored( - HelperEntity helperEntity, Function(BuildContext) onDismiss); + Widget buildAnchored(HelperEntity helperEntity, Function(BuildContext?) onDismiss); - Widget buildUpdate( - HelperEntity helperEntity, Function(BuildContext) onDismiss); + Widget buildUpdate(HelperEntity helperEntity, Function(BuildContext?) onDismiss); } class EditorPreviewPage extends StatelessWidget implements EditorPreviewView { - final EditorPreviewArguments args; + final EditorPreviewArguments? args; EditorPreviewPage({ - Key key, - @required this.args, + Key? key, + required this.args, }); final _mvvmPageBuilder = @@ -60,8 +56,8 @@ class EditorPreviewPage extends StatelessWidget implements EditorPreviewView { key: ValueKey('EditorPreviewPage_Builder'), context: context, presenterBuilder: (context) => EditorPreviewPresenter(this, - args: this.args, - helperService: EditorInjector.of(context).helperService), + args: this.args!, + helperService: EditorInjector.of(context)!.helperService), builder: (context, presenter, model) { return Scaffold( key: _scaffoldKey, @@ -82,38 +78,37 @@ class EditorPreviewPage extends StatelessWidget implements EditorPreviewView { : Stack( fit: StackFit.expand, children: [ - presenter.getHelper(), + presenter.getHelper()!, ], ); } @override - Widget buildFullscreen( - HelperEntity helperEntity, Function(BuildContext) onDismiss) { + Widget buildFullscreen(HelperEntity helperEntity, Function(BuildContext?) onDismiss) { return UserFullScreenHelperPage( helperBoxViewModel: HelperSharedFactory.parseBoxBackground( FullscreenHelperKeys.BACKGROUND_KEY, - helperEntity?.helperBoxes, - ), + helperEntity.helperBoxes!, + )!, titleLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.TITLE_KEY, - helperEntity?.helperTexts, - ), + helperEntity.helperTexts!, + )!, descriptionLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.DESCRIPTION_KEY, - helperEntity?.helperTexts, - ), + helperEntity.helperTexts!, + )!, headerImageViewModel: HelperSharedFactory.parseImageUrl( FullscreenHelperKeys.IMAGE_KEY, - helperEntity?.helperImages, + helperEntity.helperImages, ), negativLabel: HelperSharedFactory.parseButtonLabel( FullscreenHelperKeys.NEGATIV_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), positivLabel: HelperSharedFactory.parseButtonLabel( FullscreenHelperKeys.POSITIV_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), onNegativButtonTap: () => onDismiss(_scaffoldKey.currentContext), onPositivButtonTap: () => onDismiss(_scaffoldKey.currentContext), @@ -121,14 +116,13 @@ class EditorPreviewPage extends StatelessWidget implements EditorPreviewView { } @override - Widget buildSimple( - HelperEntity helperEntity, Function(BuildContext) onDismiss) { + Widget buildSimple(HelperEntity helperEntity, Function(BuildContext?) onDismiss) { SimpleHelperPage content = SimpleHelperPage( // helperBoxViewModel: HelperSharedFactory.parseBoxNotifier(model.bodyBox), descriptionLabel: HelperSharedFactory.parseTextLabel( SimpleHelperKeys.CONTENT_KEY, - helperEntity?.helperTexts, - ), + helperEntity.helperTexts!, + )!, ); return SimpleHelperLayout( toaster: content, @@ -137,59 +131,56 @@ class EditorPreviewPage extends StatelessWidget implements EditorPreviewView { } @override - Widget buildAnchored( - HelperEntity helperEntity, Function(BuildContext) onDismiss) { + Widget buildAnchored(HelperEntity helperEntity, Function(BuildContext?) onDismiss) { return AnchoredHelper.fromEntity( finderService: - EditorInjector.of(_scaffoldKey.currentContext).finderService, + EditorInjector.of(_scaffoldKey.currentContext!)!.finderService, positivButtonLabel: HelperSharedFactory.parseButtonLabel( FullscreenHelperKeys.POSITIV_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), titleLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.TITLE_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), descriptionLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.DESCRIPTION_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), negativButtonLabel: HelperSharedFactory.parseButtonLabel( FullscreenHelperKeys.NEGATIV_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), helperBoxViewModel: HelperBoxViewModel( - id: helperEntity.helperBoxes?.first?.id, - backgroundColor: HexColor?.fromHex( - helperEntity.helperBoxes.first.backgroundColor)), - anchorKey: helperEntity.helperBoxes?.first?.key, + id: helperEntity.helperBoxes?.first.id, + backgroundColor: HexColor.fromHex( + helperEntity.helperBoxes!.first.backgroundColor!)), + anchorKey: helperEntity.helperBoxes?.first.key, onNegativButtonTap: () => onDismiss(_scaffoldKey.currentContext), onPositivButtonTap: () => onDismiss(_scaffoldKey.currentContext), ); } @override - Widget buildUpdate( - HelperEntity helperEntity, Function(BuildContext) onDismiss) { + Widget buildUpdate(HelperEntity helperEntity, Function(BuildContext?) onDismiss) { Map changelogsMap = {}; List changelogs = HelperSharedFactory.parseTextsLabel( UpdatescreenHelperKeys.LINES_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ); - - if (changelogs != null && changelogs.length > 0) { + if (changelogs.length > 0) { int index = 0; for (var changelog in changelogs) { changelogsMap.putIfAbsent( 'template_${changelog.id.toString()}', () => EditableTextFormData( - changelog?.id, + changelog.id, '${UpdatescreenHelperKeys.LINES_KEY}_${index++}', - text: changelog?.text ?? '', - fontColor: changelog?.fontColor ?? Colors.white, - fontSize: changelog?.fontSize?.toInt() ?? 18, - fontFamily: changelog?.fontFamily, - fontWeight: FontWeightMapper.toFontKey(changelog?.fontWeight), + text: changelog.text ?? '', + fontColor: changelog.fontColor ?? Colors.white, + fontSize: changelog.fontSize?.toInt() ?? 18, + fontFamily: changelog.fontFamily, + fontWeight: FontWeightMapper.toFontKey(changelog.fontWeight), ), ); } @@ -197,24 +188,24 @@ class EditorPreviewPage extends StatelessWidget implements EditorPreviewView { return UserUpdateHelperPage( helperBoxViewModel: HelperSharedFactory.parseBoxBackground( SimpleHelperKeys.BACKGROUND_KEY, - helperEntity?.helperBoxes, - ), + helperEntity.helperBoxes!, + )!, titleLabel: HelperSharedFactory.parseTextLabel( UpdatescreenHelperKeys.TITLE_KEY, - helperEntity?.helperTexts, - ), + helperEntity.helperTexts!, + )!, thanksButtonLabel: HelperSharedFactory.parseButtonLabel( UpdatescreenHelperKeys.POSITIV_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), changelogLabels: changelogs, helperImageViewModel: HelperSharedFactory.parseImageUrl( UpdatescreenHelperKeys.IMAGE_KEY, - helperEntity?.helperImages, + helperEntity.helperImages, ), onPositivButtonTap: () => onDismiss(_scaffoldKey.currentContext), packageVersionReader: - EditorInjector.of(_scaffoldKey.currentContext).packageVersionReader, + EditorInjector.of(_scaffoldKey.currentContext!)!.packageVersionReader, ); } } diff --git a/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview_presenter.dart b/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview_presenter.dart index a331a1e2..ff9dae16 100644 --- a/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview_presenter.dart @@ -14,8 +14,8 @@ class EditorPreviewPresenter EditorPreviewPresenter( EditorPreviewView viewInterface, { - @required this.helperService, - @required EditorPreviewArguments args, + required this.helperService, + required EditorPreviewArguments args, }) : super( EditorPreviewModel( args.helperId, args.onDismiss, args.preBuiltHelper), @@ -38,28 +38,25 @@ class EditorPreviewPresenter } } - Widget getHelper() { + Widget? getHelper() { if (this.viewModel.preBuiltHelper != null) return this.viewModel.preBuiltHelper; // PARSING AND CREATING HELPER ENTITY - switch (this.viewModel.helperEntity.type) { + switch (this.viewModel.helperEntity!.type) { case HelperType.HELPER_FULL_SCREEN: return this.viewInterface.buildFullscreen( - this.viewModel.helperEntity, this.viewModel.onDismiss); + this.viewModel.helperEntity!, this.viewModel.onDismiss as dynamic Function(BuildContext?)); case HelperType.SIMPLE_HELPER: return this .viewInterface - .buildSimple(this.viewModel.helperEntity, this.viewModel.onDismiss); - break; + .buildSimple(this.viewModel.helperEntity!, this.viewModel.onDismiss as dynamic Function(BuildContext?)); case HelperType.ANCHORED_OVERLAYED_HELPER: return this.viewInterface.buildAnchored( - this.viewModel.helperEntity, this.viewModel.onDismiss); - break; + this.viewModel.helperEntity!, this.viewModel.onDismiss as dynamic Function(BuildContext?)); case HelperType.UPDATE_HELPER: return this .viewInterface - .buildUpdate(this.viewModel.helperEntity, this.viewModel.onDismiss); - break; + .buildUpdate(this.viewModel.helperEntity!, this.viewModel.onDismiss as dynamic Function(BuildContext?)); default: return null; } diff --git a/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview_viewmodel.dart index 66944eda..ef26f49f 100644 --- a/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/editor_preview/editor_preview_viewmodel.dart @@ -4,14 +4,14 @@ import 'package:pal/src/database/entity/helper/helper_entity.dart'; class EditorPreviewModel extends MVVMModel { // CORE ATTRIBUTES - final String helperId; - final Widget preBuiltHelper; + final String? helperId; + final Widget? preBuiltHelper; final Function onDismiss; //* BASE HELPER ENTITY FOR PREVIEW HELPER - HelperEntity helperEntity; + HelperEntity? helperEntity; // STATE ATTRIBUTES - bool loading; + late bool loading; EditorPreviewModel(this.helperId, this.onDismiss, this.preBuiltHelper); diff --git a/lib/src/ui/editor/pages/helper_editor/editor_router.dart b/lib/src/ui/editor/pages/helper_editor/editor_router.dart index 57681b98..dd3c1b27 100644 --- a/lib/src/ui/editor/pages/helper_editor/editor_router.dart +++ b/lib/src/ui/editor/pages/helper_editor/editor_router.dart @@ -18,13 +18,13 @@ import 'helpers/editor_update_helper/editor_update_helper.dart'; /// we don't use a navigator push as we use the overlay feature for /// reaching the overlayed page elements (@see anchoredHelper) class EditorRouter { - final GlobalKey hostedAppNavigatorKey; + final GlobalKey? hostedAppNavigatorKey; EditorRouter(this.hostedAppNavigatorKey); /// Open editor page as an overlay Future createHelper( - final String currentPageRoute, final CreateHelperModel model) async { + final String? currentPageRoute, final CreateHelperModel model) async { // var elementFinder = ElementFinder(hostedAppNavigatorKey.currentContext); HelperEditorPageArguments args = HelperEditorPageArguments( hostedAppNavigatorKey, @@ -68,12 +68,12 @@ class EditorRouter { default: throw 'HELPER TYPE NOT HANDLED'; } - showOverlayed(hostedAppNavigatorKey, builder); + showOverlayed(hostedAppNavigatorKey!, builder); } - Future editHelper(final String currentPageRoute, final String helperId, - final HelperType type, final String groupId, - {BuildContext con}) async { + Future editHelper(final String? currentPageRoute, final String helperId, + final HelperType type, final String? groupId, + {BuildContext? con}) async { // var elementFinder = ElementFinder(hostedAppNavigatorKey.currentContext); HelperEditorPageArguments args = HelperEditorPageArguments( hostedAppNavigatorKey, @@ -117,9 +117,9 @@ class EditorRouter { throw 'HELPER TYPE NOT HANDLED'; } return showOverlayed( - hostedAppNavigatorKey, + hostedAppNavigatorKey!, builder, - onPop: () => Navigator.of(con).pushNamed( + onPop: () => Navigator.of(con!).pushNamed( '/editor/group/details', arguments: { "id": groupId, @@ -136,7 +136,7 @@ class EditorRouter { class InnerEditorRouter extends StatefulWidget { final Widget child; - InnerEditorRouter({@required this.child}); + InnerEditorRouter({required this.child}); @override _InnerEditorRouterState createState() => _InnerEditorRouterState(); @@ -145,7 +145,7 @@ class InnerEditorRouter extends StatefulWidget { class _InnerEditorRouterState extends State { final GlobalKey innerEditorNavKey = GlobalKey(); - InnerEditorRouterDelegate _routerDelegate; + late InnerEditorRouterDelegate _routerDelegate; void initState() { super.initState(); @@ -170,9 +170,9 @@ abstract class InnerEditorRoutePath {} class InnerEditorRouterDelegate extends RouterDelegate with ChangeNotifier, PopNavigatorRouterDelegateMixin { - final GlobalKey innerEditorNavKey; + final GlobalKey? innerEditorNavKey; - Widget child; + Widget? child; InnerEditorRouterDelegate({this.child, this.innerEditorNavKey}); @@ -184,25 +184,25 @@ class InnerEditorRouterDelegate extends RouterDelegate // TODO: Remove unused font family et font weight switch (settings.name) { case '/editor/new/font-family': - FontFamilyPickerArguments args = settings.arguments; + FontFamilyPickerArguments? args = settings.arguments as FontFamilyPickerArguments?; return MaterialPageRoute( builder: (context) => FontFamilyPickerPage( arguments: args, )); case '/editor/new/font-weight': - FontWeightPickerArguments args = settings.arguments; + FontWeightPickerArguments? args = settings.arguments as FontWeightPickerArguments?; return MaterialPageRoute( builder: (context) => FontWeightPickerPage( arguments: args, )); case '/editor/media-gallery': - MediaGalleryPageArguments args = settings.arguments; + MediaGalleryPageArguments? args = settings.arguments as MediaGalleryPageArguments?; return MaterialPageRoute( builder: (context) => MediaGalleryPage( - mediaId: args.mediaId, + mediaId: args!.mediaId, )); case '/editor/preview': - EditorPreviewArguments args = settings.arguments; + EditorPreviewArguments? args = settings.arguments as EditorPreviewArguments?; return PageRouteBuilder( pageBuilder: (context, _, __) => EditorPreviewPage( args: args, @@ -210,7 +210,7 @@ class InnerEditorRouterDelegate extends RouterDelegate ); default: return MaterialPageRoute( - builder: (context) => child, + builder: (context) => child!, maintainState: true, ); } @@ -223,7 +223,7 @@ class InnerEditorRouterDelegate extends RouterDelegate } @override - GlobalKey get navigatorKey => innerEditorNavKey; + GlobalKey? get navigatorKey => innerEditorNavKey; @override Future setNewRoutePath(InnerEditorRoutePath configuration) { diff --git a/lib/src/ui/editor/pages/helper_editor/helper_editor.dart b/lib/src/ui/editor/pages/helper_editor/helper_editor.dart index ae4357e8..0612bf5a 100644 --- a/lib/src/ui/editor/pages/helper_editor/helper_editor.dart +++ b/lib/src/ui/editor/pages/helper_editor/helper_editor.dart @@ -3,13 +3,13 @@ import 'package:pal/src/services/pal/pal_state_service.dart'; import 'package:pal/src/ui/shared/widgets/overlayed.dart'; class HelperEditorPageArguments { - final GlobalKey hostedAppNavigatorKey; + final GlobalKey? hostedAppNavigatorKey; - final String pageId; + final String? pageId; - final String helperMinVersion; + final String? helperMinVersion; - final String helperMaxVersion; + final String? helperMaxVersion; final bool isOnEditMode; @@ -23,11 +23,11 @@ class HelperEditorPageArguments { } mixin EditorNavigationMixin { - BuildContext context; - PalEditModeStateService palEditModeStateService; + BuildContext? context; + late PalEditModeStateService palEditModeStateService; Future closeEditor(bool showList, bool showBubble) async { - Overlayed.removeOverlay(context, OverlayKeys.EDITOR_OVERLAY_KEY); + Overlayed.removeOverlay(context!, OverlayKeys.EDITOR_OVERLAY_KEY); if (showBubble) palEditModeStateService.showBubble(context, showBubble); if (showList) palEditModeStateService.showHelpersList(context); } diff --git a/lib/src/ui/editor/pages/helper_editor/helper_editor_data.dart b/lib/src/ui/editor/pages/helper_editor/helper_editor_data.dart index a626f395..3bce9afe 100644 --- a/lib/src/ui/editor/pages/helper_editor/helper_editor_data.dart +++ b/lib/src/ui/editor/pages/helper_editor/helper_editor_data.dart @@ -3,52 +3,52 @@ import 'package:flutter/widgets.dart'; import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_loader.dart'; abstract class EditableData { - int id; - String key; - bool isSelected; + int? id; + String? key; + bool? isSelected; EditableData(this.id, this.key); } abstract class EditableTextData extends EditableData { - String text; - String fontFamily; - String fontWeight; - Color fontColor; - int fontSize; + String? text; + String? fontFamily; + String? fontWeight; + Color? fontColor; + int? fontSize; - EditableTextData(int id, String key, - {@required String text, - @required Color fontColor, - String fontFamily, - String fontWeight, - @required int fontSize, - String hintText}) - : super(id, key) { - this.text = text; - this.fontColor = fontColor; - this.fontFamily = fontFamily ?? 'Montserrat'; - this.fontWeight = - fontWeight ?? FontWeightMapper.toFontKey(FontWeight.normal); - this.fontSize = fontSize ?? 14; + EditableTextData( + int? id, + String key, { + required this.text, + required this.fontColor, + String? fontFamily, + String? fontWeight, + required this.fontSize, + String? hintText, + }) : super(id, key) { + this.fontWeight = fontWeight != null + ? fontWeight + : FontWeightMapper.toFontKey(FontWeight.normal); + this.fontFamily = fontFamily != null ? fontFamily : 'Montserrat'; } } class EditableButtonFormData extends EditableTextData { - Color borderColor; - Color backgroundColor; + Color? borderColor; + Color? backgroundColor; EditableButtonFormData( - int id, + int? id, String key, { - @required String text, - @required Color fontColor, - String fontFamily, - String fontWeight, - Color backgroundColor, - Color borderColor, - @required int fontSize, - String hintText, + required String text, + required Color fontColor, + String? fontFamily, + String? fontWeight, + Color? backgroundColor, + Color? borderColor, + required int fontSize, + String? hintText, }) : super( id, key, @@ -66,14 +66,14 @@ class EditableButtonFormData extends EditableTextData { class EditableTextFormData extends EditableTextData { EditableTextFormData( - int id, + int? id, String key, { - @required String text, - @required Color fontColor, - String fontFamily, - String fontWeight, - @required int fontSize, - String hintText, + required String text, + required Color fontColor, + String? fontFamily, + String? fontWeight, + required int fontSize, + String? hintText, }) : super( id, key, @@ -87,14 +87,14 @@ class EditableTextFormData extends EditableTextData { } class EditableMediaFormData extends EditableData { - String uuid; - String url; + String? uuid; + String? url; EditableMediaFormData( - int id, + int? id, String key, { - String url, - String uuid, + String? url, + String? uuid, }) : super(id, key) { this.uuid = uuid; this.url = url; @@ -112,21 +112,21 @@ class EditableMediaFormData extends EditableData { // } class EditableBoxFormData extends EditableData { - Color backgroundColor; + Color? backgroundColor; EditableBoxFormData( - int id, - String key, { - Color backgroundColor, + int? id, + String? key, { + Color? backgroundColor, }) : super(id, key) { this.backgroundColor = backgroundColor ?? Colors.blueAccent; } } class EditableBorderFormData extends EditableData { - Color color; - String style; - double width; + Color? color; + String? style; + double? width; EditableBorderFormData(int id, String key, {this.color, this.style}) : super(id, key); } diff --git a/lib/src/ui/editor/pages/helper_editor/helper_editor_factory.dart b/lib/src/ui/editor/pages/helper_editor/helper_editor_factory.dart index 700320d5..8aaa18c7 100644 --- a/lib/src/ui/editor/pages/helper_editor/helper_editor_factory.dart +++ b/lib/src/ui/editor/pages/helper_editor/helper_editor_factory.dart @@ -12,8 +12,8 @@ import 'package:pal/src/extensions/color_extension.dart'; class EditorViewModelFactory { @deprecated - static HelperViewModel transform(HelperViewModel model) { - switch (model?.helperType) { + static HelperViewModel? transform(HelperViewModel model) { + switch (model.helperType) { case HelperType.HELPER_FULL_SCREEN: return FullscreenHelperViewModel.fromHelperViewModel(model); case HelperType.SIMPLE_HELPER: @@ -27,8 +27,8 @@ class EditorViewModelFactory { } } - static HelperViewModel build(HelperEntity helperEntity) { - switch (helperEntity?.type) { + static HelperViewModel? build(HelperEntity helperEntity) { + switch (helperEntity.type) { case HelperType.HELPER_FULL_SCREEN: return FullscreenHelperViewModel.fromHelperEntity(helperEntity); case HelperType.SIMPLE_HELPER: @@ -89,11 +89,11 @@ class EditorEntityFactory { fontFamily: model.negativButtonForm?.fontFamily, ), helperGroup: HelperGroupConfig( - id: model.helperGroup.id, - name: model.helperGroup.name, - maxVersion: model.helperGroup.maxVersionCode, - minVersion: model.helperGroup.minVersionCode, - triggerType:model.helperGroup.triggerType ==null ? null : helperTriggerTypeToString(model.helperGroup.triggerType), + id: model.helperGroup!.id, + name: model.helperGroup!.name, + maxVersion: model.helperGroup!.maxVersionCode, + minVersion: model.helperGroup!.minVersionCode, + triggerType:model.helperGroup!.triggerType ==null ? null : helperTriggerTypeToString(model.helperGroup!.triggerType), )); static CreateSimpleHelper buildSimpleArgs( @@ -112,24 +112,24 @@ class EditorEntityFactory { fontFamily: model.contentTextForm?.fontFamily, ), helperGroup: HelperGroupConfig( - id: model.helperGroup.id, - name: model.helperGroup.name, - minVersion: model.helperGroup.minVersionCode, - maxVersion: model.helperGroup.maxVersionCode, - triggerType:model.helperGroup.triggerType ==null ? null : helperTriggerTypeToString(model.helperGroup.triggerType))); + id: model.helperGroup!.id, + name: model.helperGroup!.name, + minVersion: model.helperGroup!.minVersionCode, + maxVersion: model.helperGroup!.maxVersionCode, + triggerType:model.helperGroup!.triggerType ==null ? null : helperTriggerTypeToString(model.helperGroup!.triggerType))); static CreateUpdateHelper buildUpdateArgs( CreateHelperConfig config, UpdateHelperViewModel model) { List lines = []; - for (var changelogNote in model.changelogsTextsForm.entries) { + for (var changelogNote in model.changelogsTextsForm!.entries) { lines.add( HelperTextConfig( - id: changelogNote?.value?.id, - text: changelogNote?.value?.text, - fontColor: changelogNote?.value?.fontColor?.toHex(), - fontWeight: changelogNote?.value?.fontWeight, - fontSize: changelogNote?.value?.fontSize, - fontFamily: changelogNote?.value?.fontFamily, + id: changelogNote.value.id, + text: changelogNote.value.text, + fontColor: changelogNote.value.fontColor?.toHex(), + fontWeight: changelogNote.value.fontWeight, + fontSize: changelogNote.value.fontSize, + fontFamily: changelogNote.value.fontFamily, ), ); } @@ -161,11 +161,11 @@ class EditorEntityFactory { fontFamily: model.positivButtonForm?.fontFamily, ), helperGroup: HelperGroupConfig( - id: model.helperGroup.id, - name: model.helperGroup.name, - maxVersion: model.helperGroup.maxVersionCode, - minVersion: model.helperGroup.minVersionCode, - triggerType:model.helperGroup.triggerType ==null ? null : helperTriggerTypeToString(model.helperGroup.triggerType), + id: model.helperGroup!.id, + name: model.helperGroup!.name, + maxVersion: model.helperGroup!.maxVersionCode, + minVersion: model.helperGroup!.minVersionCode, + triggerType:model.helperGroup!.triggerType ==null ? null : helperTriggerTypeToString(model.helperGroup!.triggerType), )); } @@ -174,47 +174,47 @@ class EditorEntityFactory { CreateAnchoredHelper( config: config, title: HelperTextConfig( - id: model.titleField?.id, - text: model.titleField?.text, - fontColor: model.titleField?.fontColor?.toHex(), - fontWeight: model.titleField?.fontWeight, - fontSize: model.titleField?.fontSize, - fontFamily: model.titleField?.fontFamily, + id: model.titleField.id, + text: model.titleField.text, + fontColor: model.titleField.fontColor?.toHex(), + fontWeight: model.titleField.fontWeight, + fontSize: model.titleField.fontSize, + fontFamily: model.titleField.fontFamily, ), description: HelperTextConfig( - id: model.descriptionField?.id, - text: model.descriptionField?.text, - fontColor: model.descriptionField?.fontColor?.toHex(), - fontWeight: model.descriptionField?.fontWeight, - fontSize: model.descriptionField?.fontSize, - fontFamily: model.descriptionField?.fontFamily, + id: model.descriptionField.id, + text: model.descriptionField.text, + fontColor: model.descriptionField.fontColor?.toHex(), + fontWeight: model.descriptionField.fontWeight, + fontSize: model.descriptionField.fontSize, + fontFamily: model.descriptionField.fontFamily, ), positivButton: HelperTextConfig( - id: model.positivBtnField?.id, - text: model.positivBtnField?.text, - fontColor: model.positivBtnField?.fontColor?.toHex(), - fontWeight: model.positivBtnField?.fontWeight, - fontSize: model.positivBtnField?.fontSize, - fontFamily: model.positivBtnField?.fontFamily, + id: model.positivBtnField.id, + text: model.positivBtnField.text, + fontColor: model.positivBtnField.fontColor?.toHex(), + fontWeight: model.positivBtnField.fontWeight, + fontSize: model.positivBtnField.fontSize, + fontFamily: model.positivBtnField.fontFamily, ), negativButton: HelperTextConfig( - id: model.negativBtnField?.id, - text: model.negativBtnField?.text, - fontColor: model.negativBtnField?.fontColor?.toHex(), - fontWeight: model.negativBtnField?.fontWeight, - fontSize: model.negativBtnField?.fontSize, - fontFamily: model.negativBtnField?.fontFamily, + id: model.negativBtnField.id, + text: model.negativBtnField.text, + fontColor: model.negativBtnField.fontColor?.toHex(), + fontWeight: model.negativBtnField.fontWeight, + fontSize: model.negativBtnField.fontSize, + fontFamily: model.negativBtnField.fontFamily, ), bodyBox: HelperBoxConfig( id: model.backgroundBox.id, key: model.selectedAnchorKey, - color: model.backgroundBox?.backgroundColor?.toHex(), + color: model.backgroundBox.backgroundColor?.toHex(), ), helperGroup: HelperGroupConfig( - id: model.helperGroup.id, - name: model.helperGroup.name, - maxVersion: model.helperGroup.maxVersionCode, - minVersion: model.helperGroup.minVersionCode, - triggerType: model.helperGroup.triggerType ==null ? null : helperTriggerTypeToString(model.helperGroup.triggerType), + id: model.helperGroup!.id, + name: model.helperGroup!.name, + maxVersion: model.helperGroup!.maxVersionCode, + minVersion: model.helperGroup!.minVersionCode, + triggerType: model.helperGroup!.triggerType ==null ? null : helperTriggerTypeToString(model.helperGroup!.triggerType), )); } diff --git a/lib/src/ui/editor/pages/helper_editor/helper_editor_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/helper_editor_viewmodel.dart index 5277b191..35168b68 100644 --- a/lib/src/ui/editor/pages/helper_editor/helper_editor_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/helper_editor_viewmodel.dart @@ -6,18 +6,18 @@ import 'package:pal/src/database/entity/helper/helper_theme.dart'; class HelperViewModel extends MVVMModel { - final String id; - final String name; - final int priority; - final HelperTheme helperTheme; - final HelperType helperType; - final HelperGroupModel helperGroup; + final String? id; + final String? name; + final int? priority; + final HelperTheme? helperTheme; + final HelperType? helperType; + final HelperGroupModel? helperGroup; HelperViewModel({ this.id, - @required this.name, - @required this.helperType, - @required this.priority, + required this.name, + required this.helperType, + required this.priority, this.helperTheme, this.helperGroup }); @@ -25,11 +25,11 @@ class HelperViewModel extends MVVMModel { } class HelperGroupModel { - final String id; - final String name; - final String minVersionCode; - final String maxVersionCode; - final HelperTriggerType triggerType; + final String? id; + final String? name; + final String? minVersionCode; + final String? maxVersionCode; + final HelperTriggerType? triggerType; HelperGroupModel({ this.id, this.name, this.minVersionCode, this.maxVersionCode, diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_anchored_helper/editor_anchored_helper.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_anchored_helper/editor_anchored_helper.dart index 4dee0233..76430ac7 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_anchored_helper/editor_anchored_helper.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_anchored_helper/editor_anchored_helper.dart @@ -41,7 +41,7 @@ abstract class EditorAnchoredFullscreenHelperView { void showTutorial(String title, String content); Future showPreviewOfHelper(AnchoredFullscreenHelperViewModel model, - FinderService finderService, bool isTestingMode); + FinderService finderService, bool? isTestingMode); } /// ------------------------------------------------------------ @@ -53,54 +53,54 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { StreamController.broadcast(); final PresenterBuilder presenterBuilder; - final FinderService finderService; + final FinderService? finderService; final bool isTestingMode; EditorAnchoredFullscreenHelper._({ - Key key, - @required this.presenterBuilder, + Key? key, + required this.presenterBuilder, this.finderService, this.isTestingMode = false, }) : super(key: key); factory EditorAnchoredFullscreenHelper.create( - {Key key, - HelperEditorPageArguments parameters, - EditorHelperService helperService, - FinderService finderService, - bool isTestingMode, - @required HelperViewModel helperViewModel}) => + {Key? key, + HelperEditorPageArguments? parameters, + EditorHelperService? helperService, + FinderService? finderService, + bool? isTestingMode, + required HelperViewModel helperViewModel}) => EditorAnchoredFullscreenHelper._( key: key, presenterBuilder: (context) => EditorAnchoredFullscreenPresenter( AnchoredFullscreenHelperViewModel.fromModel(helperViewModel), _EditorAnchoredFullscreenHelperView( - context, EditorInjector.of(context).palEditModeStateService), - finderService ?? EditorInjector.of(context).finderService, + context, EditorInjector.of(context)!.palEditModeStateService), + finderService ?? EditorInjector.of(context)!.finderService, isTestingMode, - helperService ?? EditorInjector.of(context).helperService, + helperService ?? EditorInjector.of(context)!.helperService, parameters, ), ); factory EditorAnchoredFullscreenHelper.edit( - {Key key, - HelperEditorPageArguments parameters, - EditorHelperService helperService, - PalEditModeStateService palEditModeStateService, - FinderService finderService, - bool isTestingMode, - @required String helperId}) => + {Key? key, + HelperEditorPageArguments? parameters, + EditorHelperService? helperService, + PalEditModeStateService? palEditModeStateService, + FinderService? finderService, + bool? isTestingMode, + required String? helperId}) => EditorAnchoredFullscreenHelper._( key: key, presenterBuilder: (context) => EditorAnchoredFullscreenPresenter( AnchoredFullscreenHelperViewModel.fromEntity(HelperEntity( id: helperId, helperTexts: [])), _EditorAnchoredFullscreenHelperView(context, - EditorInjector.of(context).palEditModeStateService), - finderService ?? EditorInjector.of(context).finderService, + EditorInjector.of(context)!.palEditModeStateService), + finderService ?? EditorInjector.of(context)!.finderService, isTestingMode, - helperService ?? EditorInjector.of(context).helperService, + helperService ?? EditorInjector.of(context)!.helperService, parameters, )); @@ -123,7 +123,7 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { ], animListener: (context, presenter, model) { if (model.selectedAnchorKey != null) { - context.animationsControllers[1].forward(from: 0); + context.animationsControllers![1].forward(from: 0); } }, builder: (context, presenter, model) => Material( @@ -133,7 +133,7 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { : EditorToolboxPage( boxViewHandler: BoxViewHandler( callback: presenter.updateBackgroundColor, - selectedColor: model.backgroundBox?.backgroundColor), + selectedColor: model.backgroundBox.backgroundColor), onValidate: (model.canValidate?.value == true) ? presenter.onValidate : null, @@ -149,8 +149,8 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { children: [ _createAnchoredWidget( model, - context.animationsControllers[0], - context.animationsControllers[1]), + context.animationsControllers![0], + context.animationsControllers![1]), _buildEditableTexts(presenter, model), ..._createSelectableElements(presenter, model), _buildRefreshButton(presenter), @@ -187,8 +187,8 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { visible: model.selectedAnchor != null, child: AnimatedAnchoredFullscreenCircle( listenable: animationController, - currentPos: element?.value?.offset, - anchorSize: element?.value?.rect?.size, + currentPos: element?.value.offset, + anchorSize: element?.value.rect?.size, bgColor: model.backgroundBox.backgroundColor, padding: 4), ), @@ -203,10 +203,10 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { if (model.selectedAnchor == null || model.anchorValidated) return Container(); return Positioned( - left: model.selectedAnchor.value.offset.dx, - top: model.selectedAnchor.value.offset.dy, + left: model.selectedAnchor!.value.offset!.dx, + top: model.selectedAnchor!.value.offset!.dy, child: EditorButton.validate( - PalTheme.of(context), presenter.validateSelection, + PalTheme.of(context)!, presenter.validateSelection, key: ValueKey("validateSelectionBtn"))); } @@ -257,8 +257,8 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { child: EditableTextField( data: model.titleField, onTap: presenter.onNewEditableSelect, - backgroundColor: model.backgroundBox?.backgroundColor, - isSelected: model.currentEditableItemNotifier?.value?.key == + backgroundColor: model.backgroundBox.backgroundColor, + isSelected: model.currentEditableItemNotifier.value?.key == model.titleField.key, ), ), @@ -267,8 +267,8 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { child: EditableTextField( data: model.descriptionField, onTap: presenter.onNewEditableSelect, - backgroundColor: model.backgroundBox?.backgroundColor, - isSelected: model.currentEditableItemNotifier?.value?.key == + backgroundColor: model.backgroundBox.backgroundColor, + isSelected: model.currentEditableItemNotifier.value?.key == model.descriptionField.key, ), ), @@ -281,9 +281,9 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { data: model.negativBtnField, outline: true, onTap: presenter.onNewEditableSelect, - backgroundColor: model.backgroundBox?.backgroundColor, + backgroundColor: model.backgroundBox.backgroundColor, isSelected: - model.currentEditableItemNotifier?.value?.key == + model.currentEditableItemNotifier.value?.key == model.negativBtnField.key, ), ), @@ -291,9 +291,9 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { child: EditableButton( data: model.positivBtnField, onTap: presenter.onNewEditableSelect, - backgroundColor: model.backgroundBox?.backgroundColor, + backgroundColor: model.backgroundBox.backgroundColor, isSelected: - model.currentEditableItemNotifier?.value?.key == + model.currentEditableItemNotifier.value?.key == model.positivBtnField.key, ), ), @@ -312,11 +312,11 @@ class EditorAnchoredFullscreenHelper extends StatelessWidget { class _EditorAnchoredFullscreenHelperView with EditorSendingOverlayMixin, EditorNavigationMixin implements EditorAnchoredFullscreenHelperView { - BuildContext context; + BuildContext? context; final PalEditModeStateService palEditModeStateService; - EditorSendingOverlay sendingOverlay; + EditorSendingOverlay? sendingOverlay; _EditorAnchoredFullscreenHelperView( this.context, this.palEditModeStateService) { @@ -351,7 +351,7 @@ class _EditorAnchoredFullscreenHelperView @override Future showPreviewOfHelper(AnchoredFullscreenHelperViewModel model, - FinderService finderService, bool isTestingMode) async { + FinderService finderService, bool? isTestingMode) async { AnchoredHelper page = AnchoredHelper.fromEntity( finderService: finderService, positivButtonLabel: @@ -365,8 +365,8 @@ class _EditorAnchoredFullscreenHelperView HelperSharedFactory.parseBoxNotifier(model.backgroundBox), anchorKey: model.selectedAnchorKey, isTestingMode: isTestingMode, - onNegativButtonTap: () => Navigator.of(context).pop(), - onPositivButtonTap: () => Navigator.of(context).pop(), + onNegativButtonTap: () => Navigator.of(context!).pop(), + onPositivButtonTap: () => Navigator.of(context!).pop(), ); EditorPreviewArguments arguments = EditorPreviewArguments( @@ -374,7 +374,7 @@ class _EditorAnchoredFullscreenHelperView preBuiltHelper: page, ); await Navigator.pushNamed( - context, + context!, '/editor/preview', arguments: arguments, ); @@ -387,14 +387,14 @@ class _WidgetElementModelTransformer { Widget apply(String key, WidgetElementModel model, OnTapElement onTap) { // debugPrint("$key: w:${model.rect.width} h:${model.rect.height} => ${model.offset.dx} ${model.offset.dy}"); return Positioned( - left: model.offset.dx, - top: model.offset.dy, + left: model.offset!.dx, + top: model.offset!.dy, child: InkWell( key: ValueKey("elementContainer"), onTap: () => onTap(key), child: Container( - width: model.rect.width, - height: model.rect.height, + width: model.rect!.width, + height: model.rect!.height, decoration: BoxDecoration( border: Border.all( color: Colors.white.withOpacity(model.selected ? 1 : .5), diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_anchored_helper/editor_anchored_helper_presenter.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_anchored_helper/editor_anchored_helper_presenter.dart index 9beab691..71b1f0bb 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_anchored_helper/editor_anchored_helper_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_anchored_helper/editor_anchored_helper_presenter.dart @@ -19,15 +19,15 @@ const EDITOR_PARENT_NODE_KEY = "EditorPage"; class EditorAnchoredFullscreenPresenter extends Presenter { final FinderService finderService; - final bool isTestingMode; + final bool? isTestingMode; final EditorHelperService helperEditorService; - final HelperEditorPageArguments parameters; + final HelperEditorPageArguments? parameters; - bool editMode; + late bool editMode; - Map scannedElements; + late Map scannedElements; EditorAnchoredFullscreenPresenter(AnchoredFullscreenHelperViewModel viewModel, EditorAnchoredFullscreenHelperView viewInterface, this.finderService, this.isTestingMode, this.helperEditorService, this.parameters) @@ -64,7 +64,7 @@ class EditorAnchoredFullscreenPresenter extends Presenter debugPrint("=> $element")); + if (!viewModel.userPageElements!.containsKey(key)) { + debugPrint("key cannot be found : ${viewModel.userPageElements!.keys.length} keys found"); + viewModel.userPageElements!.keys.forEach((element) => debugPrint("=> $element")); viewInterface.showErrorMessage("Key cannot be found on page. Did you remove this element?"); return; } - viewModel.userPageElements[key].selected = true; - var element = this.scannedElements[key]; + viewModel.userPageElements![key!]!.selected = true; + var element = this.scannedElements[key]!; viewModel.writeArea = await finderService.getLargestAvailableSpace(element); this.viewModel.backgroundBox.key = key; refreshView(); @@ -125,7 +125,7 @@ class EditorAnchoredFullscreenPresenter extends Presenter status = new ValueNotifier(SendingStatus.SENDING); - final config = CreateHelperConfig.from(parameters.pageId, viewModel); + final config = CreateHelperConfig.from(parameters!.pageId, viewModel); try { await viewInterface.showLoadingScreen(status); await Future.delayed(Duration(seconds: 1)); @@ -168,35 +168,35 @@ class EditorAnchoredFullscreenPresenter extends Presenter viewModel.titleField.text.isNotEmpty && viewModel.descriptionField.text.isNotEmpty; + bool isValid() => viewModel.titleField.text!.isNotEmpty && viewModel.descriptionField.text!.isNotEmpty; onPreview() { this.viewInterface.showPreviewOfHelper(this.viewModel, this.finderService, this.isTestingMode); } onTextPickerDone(String newVal) { - EditableTextData formData = this.viewModel.currentEditableItemNotifier.value; + EditableTextData formData = this.viewModel.currentEditableItemNotifier.value as EditableTextData; formData.text = newVal; this.refreshView(); this._updateValidState(); } onFontPickerDone(EditedFontModel newVal) { - EditableTextData formData = this.viewModel.currentEditableItemNotifier.value; - formData.fontSize = newVal.size.toInt(); - formData.fontFamily = newVal.fontKeys.fontFamilyNameKey; - formData.fontWeight = newVal.fontKeys.fontWeightNameKey; + EditableTextData formData = this.viewModel.currentEditableItemNotifier.value as EditableTextData; + formData.fontSize = newVal.size!.toInt(); + formData.fontFamily = newVal.fontKeys!.fontFamilyNameKey; + formData.fontWeight = newVal.fontKeys!.fontWeightNameKey; this.refreshView(); this._updateValidState(); } onMediaPickerDone(GraphicEntity newVal) { - EditableMediaFormData formData = this.viewModel.currentEditableItemNotifier.value; + EditableMediaFormData formData = this.viewModel.currentEditableItemNotifier.value as EditableMediaFormData; formData.url = newVal.url; formData.uuid = newVal.id; this.refreshView(); @@ -204,13 +204,13 @@ class EditorAnchoredFullscreenPresenter extends Presenter userPageElements; + Map? userPageElements; /// Rect where we will write our helper text - Rect writeArea; + Rect? writeArea; /// background color notifier EditableBoxFormData backgroundBox; /// enables the save button - ValueNotifier canValidate; + ValueNotifier? canValidate; /// titleField notifier including style EditableTextFormData titleField; @@ -32,28 +33,28 @@ class AnchoredFullscreenHelperViewModel extends HelperViewModel { /// buttons textNotifiers EditableButtonFormData positivBtnField, negativBtnField; - ValueNotifier currentEditableItemNotifier; + ValueNotifier currentEditableItemNotifier; /// true if user has validated the current anchor selection bool anchorValidated; - bool loading; + bool? loading; AnchoredFullscreenHelperViewModel._( - {String id, - String name, - String groupId, - String groupName, - HelperTriggerType triggerType, - int priority, - String minVersionCode, - String maxVersionCode, - HelperTheme helperTheme, - EditableBoxFormData backgroundBox, - HelperTextViewModel titleViewModel, - HelperTextViewModel descriptionLabel, - HelperTextViewModel positivButtonLabel, - HelperTextViewModel negativButtonLabel, + {String? id, + String? name, + String? groupId, + String? groupName, + HelperTriggerType? triggerType, + int? priority, + String? minVersionCode, + String? maxVersionCode, + HelperTheme? helperTheme, + EditableBoxFormData? backgroundBox, + HelperTextViewModel? titleViewModel, + HelperTextViewModel? descriptionLabel, + HelperTextViewModel? positivButtonLabel, + HelperTextViewModel? negativButtonLabel, this.anchorValidated = false}) : titleField = EditableTextFormData( titleViewModel?.id, @@ -99,7 +100,7 @@ class AnchoredFullscreenHelperViewModel extends HelperViewModel { EditableBoxFormData( backgroundBox?.id, AnchoredscreenHelperKeys.BACKGROUND_KEY, backgroundColor: Colors.lightGreenAccent.withOpacity(.6)), - currentEditableItemNotifier = ValueNotifier(null), + currentEditableItemNotifier = ValueNotifier(null), super( id: id, helperType: HelperType.ANCHORED_OVERLAYED_HELPER, @@ -115,13 +116,12 @@ class AnchoredFullscreenHelperViewModel extends HelperViewModel { )); /// the current selected element to show anchor - MapEntry get selectedAnchor => - userPageElements?.entries - ?.firstWhere((element) => element.value.selected, orElse: () => null); + MapEntry? get selectedAnchor => + userPageElements?.entries.firstWhereOrNull((element) => element.value.selected); /// the current selected element's key to show anchor - String get selectedAnchorKey => backgroundBox.key ?? userPageElements.entries - .firstWhere((element) => element.value.selected, orElse: () => null) + String? get selectedAnchorKey => backgroundBox.key ?? userPageElements!.entries + .firstWhereOrNull((element) => element.value.selected) ?.key; /// [userPageElements] without selected anchor @@ -138,40 +138,41 @@ class AnchoredFullscreenHelperViewModel extends HelperViewModel { minVersionCode: model.helperGroup?.minVersionCode, maxVersionCode: model.helperGroup?.maxVersionCode, triggerType: model.helperGroup?.triggerType, - groupId: model.helperGroup.id, - groupName: model.helperGroup.name, + groupId: model.helperGroup!.id, + groupName: model.helperGroup!.name, ); } factory AnchoredFullscreenHelperViewModel.fromEntity(HelperEntity entity) { return AnchoredFullscreenHelperViewModel._( - id: entity?.id, - name: entity?.name, + id: entity.id, + name: entity.name, priority: entity.priority, helperTheme: null, - triggerType: entity?.triggerType, + triggerType: entity.triggerType, // TODO : Finish factory for multiple boxes backgroundBox: entity.helperBoxes == null ? null : EditableBoxFormData( - entity.helperBoxes?.first?.id, entity.helperBoxes?.first?.key, - backgroundColor: - HexColor?.fromHex(entity.helperBoxes.first.backgroundColor)), + entity.helperBoxes?.first.id, + entity.helperBoxes?.first.key, + backgroundColor: HexColor.fromHex(entity.helperBoxes!.first.backgroundColor!) + ), titleViewModel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.TITLE_KEY, - entity?.helperTexts, + entity.helperTexts!, ), descriptionLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.DESCRIPTION_KEY, - entity?.helperTexts, + entity.helperTexts!, ), positivButtonLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.POSITIV_KEY, - entity?.helperTexts, + entity.helperTexts!, ), negativButtonLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.NEGATIV_KEY, - entity?.helperTexts, + entity.helperTexts!, ), ); } @@ -181,9 +182,9 @@ class AnchoredFullscreenHelperViewModel extends HelperViewModel { } class WidgetElementModel { - final Rect rect; - final Offset offset; - bool selected; + final Rect? rect; + final Offset? offset; + late bool selected; WidgetElementModel(this.rect, this.offset) { selected = false; diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper.dart index 36ed0c18..f7bebfae 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper.dart @@ -25,9 +25,9 @@ import 'editor_fullscreen_helper_presenter.dart'; import 'editor_fullscreen_helper_viewmodel.dart'; abstract class EditorFullScreenHelperView { - Future pushToMediaGallery(final String mediaId); + Future pushToMediaGallery(final String? mediaId); - TextStyle googleCustomFont(String fontFamily); + TextStyle? googleCustomFont(String fontFamily); Future showLoadingScreen(ValueNotifier status); @@ -41,11 +41,11 @@ abstract class EditorFullScreenHelperView { class EditorFullScreenHelper with EditorSendingOverlayMixin, EditorNavigationMixin implements EditorFullScreenHelperView { - BuildContext context; + BuildContext? context; final PalEditModeStateService palEditModeStateService; - EditorSendingOverlay sendingOverlay; + EditorSendingOverlay? sendingOverlay; EditorFullScreenHelper(this.context, this.palEditModeStateService) { overlayContext = context; @@ -54,18 +54,18 @@ class EditorFullScreenHelper void closeColorPickerDialog() => closeOverlayed(OverlayKeys.PAGE_OVERLAY_KEY); @override - Future pushToMediaGallery(final String mediaId) async { - final media = await Navigator.of(context).pushNamed( + Future pushToMediaGallery(final String? mediaId) async { + final media = await Navigator.of(context!).pushNamed( '/editor/media-gallery', arguments: MediaGalleryPageArguments( mediaId, ), - ) as GraphicEntity; + ) as GraphicEntity?; return media; } @override - TextStyle googleCustomFont(String fontFamily) { + TextStyle? googleCustomFont(String fontFamily) { return (fontFamily != null && fontFamily.length > 0) ? GoogleFonts.getFont(fontFamily) : null; @@ -75,18 +75,18 @@ class EditorFullScreenHelper Future showPreviewOfHelper(FullscreenHelperViewModel model) async { UserFullScreenHelperPage page = UserFullScreenHelperPage( helperBoxViewModel: - HelperSharedFactory.parseBoxNotifier(model.backgroundBoxForm), - titleLabel: HelperSharedFactory.parseTextNotifier(model.titleTextForm), + HelperSharedFactory.parseBoxNotifier(model.backgroundBoxForm!), + titleLabel: HelperSharedFactory.parseTextNotifier(model.titleTextForm!), descriptionLabel: - HelperSharedFactory.parseTextNotifier(model.descriptionTextForm), + HelperSharedFactory.parseTextNotifier(model.descriptionTextForm!), headerImageViewModel: - HelperSharedFactory.parseMediaNotifier(model.headerMediaForm), + HelperSharedFactory.parseMediaNotifier(model.headerMediaForm!), negativLabel: - HelperSharedFactory.parseButtonNotifier(model.negativButtonForm), + HelperSharedFactory.parseButtonNotifier(model.negativButtonForm!), positivLabel: - HelperSharedFactory.parseButtonNotifier(model.positivButtonForm), - onNegativButtonTap: () => Navigator.pop(context), - onPositivButtonTap: () => Navigator.pop(context), + HelperSharedFactory.parseButtonNotifier(model.positivButtonForm!), + onNegativButtonTap: () => Navigator.pop(context!), + onPositivButtonTap: () => Navigator.pop(context!), ); EditorPreviewArguments arguments = EditorPreviewArguments( @@ -94,7 +94,7 @@ class EditorFullScreenHelper preBuiltHelper: page, ); await Navigator.pushNamed( - context, + context!, '/editor/preview', arguments: arguments, ); @@ -112,43 +112,43 @@ class EditorFullScreenHelperPage extends StatelessWidget { final GlobalKey formKey = GlobalKey(); EditorFullScreenHelperPage._({ - Key key, - @required this.presenterBuilder, + Key? key, + required this.presenterBuilder, }) : super(key: key); factory EditorFullScreenHelperPage.create( - {Key key, - HelperEditorPageArguments parameters, - EditorHelperService helperService, - PalEditModeStateService palEditModeStateService, - @required HelperViewModel helperViewModel}) => + {Key? key, + HelperEditorPageArguments? parameters, + EditorHelperService? helperService, + PalEditModeStateService? palEditModeStateService, + required HelperViewModel helperViewModel}) => EditorFullScreenHelperPage._( key: key, presenterBuilder: (context) => EditorFullScreenHelperPresenter( new EditorFullScreenHelper( context, palEditModeStateService ?? - EditorInjector.of(context).palEditModeStateService), + EditorInjector.of(context)!.palEditModeStateService), FullscreenHelperViewModel.fromHelperViewModel(helperViewModel), - helperService ?? EditorInjector.of(context).helperService, + helperService ?? EditorInjector.of(context)!.helperService, parameters), ); factory EditorFullScreenHelperPage.edit( - {Key key, - HelperEditorPageArguments parameters, - EditorHelperService helperService, - PalEditModeStateService palEditModeStateService, - @required String helperId}) => + {Key? key, + HelperEditorPageArguments? parameters, + EditorHelperService? helperService, + PalEditModeStateService? palEditModeStateService, + required String? helperId}) => EditorFullScreenHelperPage._( key: key, presenterBuilder: (context) => EditorFullScreenHelperPresenter( new EditorFullScreenHelper( context, palEditModeStateService ?? - EditorInjector.of(context).palEditModeStateService), + EditorInjector.of(context)!.palEditModeStateService), FullscreenHelperViewModel(id: helperId), - helperService ?? EditorInjector.of(context).helperService, + helperService ?? EditorInjector.of(context)!.helperService, parameters), ); @@ -162,7 +162,7 @@ class EditorFullScreenHelperPage extends StatelessWidget { context: context, presenterBuilder: presenterBuilder, builder: (context, presenter, model) => - _buildPage(context.buildContext, presenter, model), + _buildPage(context.buildContext, presenter as EditorFullScreenHelperPresenter, model as FullscreenHelperViewModel), ); } @@ -198,7 +198,7 @@ class EditorFullScreenHelperPage extends StatelessWidget { key: formKey, autovalidateMode: AutovalidateMode.onUserInteraction, child: EditableBackground( - backgroundColor: model.backgroundBoxForm.backgroundColor, + backgroundColor: model.backgroundBoxForm!.backgroundColor, widget: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), @@ -217,7 +217,7 @@ class EditorFullScreenHelperPage extends StatelessWidget { model.backgroundBoxForm?.backgroundColor, isSelected: model.currentEditableItemNotifier ?.value?.key == - model.headerMediaForm.key, + model.headerMediaForm!.key, ), SizedBox(height: 24), EditableTextField( @@ -227,7 +227,7 @@ class EditorFullScreenHelperPage extends StatelessWidget { model.backgroundBoxForm?.backgroundColor, isSelected: model.currentEditableItemNotifier ?.value?.key == - model.titleTextForm.key, + model.titleTextForm!.key, ), SizedBox(height: 24), EditableTextField( @@ -237,7 +237,7 @@ class EditorFullScreenHelperPage extends StatelessWidget { model.backgroundBoxForm?.backgroundColor, isSelected: model.currentEditableItemNotifier ?.value?.key == - model.descriptionTextForm.key, + model.descriptionTextForm!.key, ), Padding( padding: const EdgeInsets.only(top: 40.0), @@ -247,7 +247,7 @@ class EditorFullScreenHelperPage extends StatelessWidget { onTap: presenter.onNewEditableSelect, isSelected: model.currentEditableItemNotifier ?.value?.key == - model.positivButtonForm.key, + model.positivButtonForm!.key, backgroundColor: model.backgroundBoxForm?.backgroundColor, ), @@ -259,7 +259,7 @@ class EditorFullScreenHelperPage extends StatelessWidget { onTap: presenter.onNewEditableSelect, isSelected: model.currentEditableItemNotifier ?.value?.key == - model.negativButtonForm.key, + model.negativButtonForm!.key, backgroundColor: model.backgroundBoxForm?.backgroundColor, ) diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper_presenter.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper_presenter.dart index acc30995..20f83b4c 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper_presenter.dart @@ -18,9 +18,9 @@ class EditorFullScreenHelperPresenter extends Presenter { final EditorHelperService editorHelperService; - final HelperEditorPageArguments parameters; + final HelperEditorPageArguments? parameters; - bool editMode; + late bool editMode; EditorFullScreenHelperPresenter( EditorFullScreenHelperView viewInterface, @@ -45,7 +45,7 @@ class EditorFullScreenHelperPresenter this.viewModel.loading = false; this .viewModel - .currentEditableItemNotifier + .currentEditableItemNotifier! .addListener(removeSelectedEditableItems); this.refreshView(); }); @@ -55,7 +55,7 @@ class EditorFullScreenHelperPresenter this.viewModel.loading = false; this .viewModel - .currentEditableItemNotifier + .currentEditableItemNotifier! .addListener(removeSelectedEditableItems); this.refreshView(); } @@ -67,7 +67,7 @@ class EditorFullScreenHelperPresenter Future onDestroy() async { this .viewModel - .currentEditableItemNotifier + .currentEditableItemNotifier! .removeListener(removeSelectedEditableItems); } @@ -80,7 +80,7 @@ class EditorFullScreenHelperPresenter Future onValidate() async { ValueNotifier status = new ValueNotifier(SendingStatus.SENDING); - final config = CreateHelperConfig.from(parameters.pageId, viewModel); + final config = CreateHelperConfig.from(parameters!.pageId, viewModel); try { await viewInterface.showLoadingScreen(status); await Future.delayed(Duration(seconds: 1)); @@ -104,10 +104,10 @@ class EditorFullScreenHelperPresenter } //TODO move to view - TextStyle googleCustomFont(String fontFamily) => + TextStyle? googleCustomFont(String fontFamily) => this.viewInterface.googleCustomFont(fontFamily); - String validateTitleTextField(String currentValue) { + String? validateTitleTextField(String currentValue) { if (currentValue.length <= 0) { return 'Please enter some text'; } @@ -118,7 +118,7 @@ class EditorFullScreenHelperPresenter } updateBackgroundColor(Color aColor) { - viewModel.backgroundBoxForm.backgroundColor = aColor; + viewModel.backgroundBoxForm!.backgroundColor = aColor; // this.viewInterface.closeColorPickerDialog(); this._updateValidState(); this.refreshView(); @@ -139,15 +139,15 @@ class EditorFullScreenHelperPresenter // ---------------------------------- _updateValidState() { - viewModel.canValidate.value = isValid(); + viewModel.canValidate!.value = isValid(); this.refreshView(); } bool isValid() => - viewModel.positivButtonForm.text.isNotEmpty && - viewModel.negativButtonForm.text.isNotEmpty && - viewModel.titleTextForm.text.isNotEmpty && - viewModel.descriptionTextForm.text.isNotEmpty; + viewModel.positivButtonForm!.text!.isNotEmpty && + viewModel.negativButtonForm!.text!.isNotEmpty && + viewModel.titleTextForm!.text!.isNotEmpty && + viewModel.descriptionTextForm!.text!.isNotEmpty; onPreview() { this.viewInterface.showPreviewOfHelper(this.viewModel); @@ -155,7 +155,7 @@ class EditorFullScreenHelperPresenter onTextPickerDone(String newVal) { EditableTextData formData = - this.viewModel.currentEditableItemNotifier.value; + this.viewModel.currentEditableItemNotifier!.value as EditableTextData; formData.text = newVal; this.refreshView(); this._updateValidState(); @@ -163,10 +163,10 @@ class EditorFullScreenHelperPresenter onFontPickerDone(EditedFontModel newVal) { EditableTextData formData = - this.viewModel.currentEditableItemNotifier.value; - formData.fontSize = newVal.size.toInt(); - formData.fontFamily = newVal.fontKeys.fontFamilyNameKey; - formData.fontWeight = newVal.fontKeys.fontWeightNameKey; + this.viewModel.currentEditableItemNotifier!.value as EditableTextData; + formData.fontSize = newVal.size!.toInt(); + formData.fontFamily = newVal.fontKeys!.fontFamilyNameKey; + formData.fontWeight = newVal.fontKeys!.fontWeightNameKey; this.refreshView(); this._updateValidState(); @@ -174,23 +174,23 @@ class EditorFullScreenHelperPresenter onMediaPickerDone(GraphicEntity newVal) { EditableMediaFormData formData = - this.viewModel.currentEditableItemNotifier.value; + this.viewModel.currentEditableItemNotifier!.value as EditableMediaFormData; formData.url = newVal.url; formData.uuid = newVal.id; this.refreshView(); this._updateValidState(); } - onTextColorPickerDone(Color newVal) { + onTextColorPickerDone(Color? newVal) { EditableTextData formData = - this.viewModel.currentEditableItemNotifier.value; + this.viewModel.currentEditableItemNotifier!.value as EditableTextData; formData.fontColor = newVal; this.refreshView(); this._updateValidState(); } - onNewEditableSelect(EditableData editedData) { - this.viewModel.currentEditableItemNotifier.value = editedData; + onNewEditableSelect(EditableData? editedData) { + this.viewModel.currentEditableItemNotifier!.value = editedData; this.refreshView(); } } diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper_viewmodel.dart index c9f78f0a..3d856551 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper/editor_fullscreen_helper_viewmodel.dart @@ -13,41 +13,41 @@ import 'package:pal/src/ui/shared/helper_shared_viewmodels.dart'; class FullscreenHelperViewModel extends HelperViewModel { // form - double helperOpacity; - ValueNotifier canValidate; + double? helperOpacity; + ValueNotifier? canValidate; // StreamController editableTextFieldController; - ValueNotifier currentEditableItemNotifier; + ValueNotifier? currentEditableItemNotifier; // helper properties // LanguageNotifier language; - EditableBoxFormData backgroundBoxForm; - EditableMediaFormData headerMediaForm; - EditableTextFormData titleTextForm; - EditableTextFormData descriptionTextForm; - EditableButtonFormData positivButtonForm; - EditableButtonFormData negativButtonForm; + EditableBoxFormData? backgroundBoxForm; + EditableMediaFormData? headerMediaForm; + EditableTextFormData? titleTextForm; + EditableTextFormData? descriptionTextForm; + EditableButtonFormData? positivButtonForm; + EditableButtonFormData? negativButtonForm; - bool loading; + bool? loading; FullscreenHelperViewModel({ - String id, - String name, - String groupId, - String groupName, - HelperTriggerType triggerType, - int priority, - HelperTheme helperTheme, - String minVersionCode, - String maxVersionCode, - int versionMaxId, - int languageId, + String? id, + String? name, + String? groupId, + String? groupName, + HelperTriggerType? triggerType, + int? priority, + HelperTheme? helperTheme, + String? minVersionCode, + String? maxVersionCode, + int? versionMaxId, + int? languageId, // For edit mode only - HelperBoxViewModel boxViewModel, - HelperImageViewModel helperImageViewModel, - HelperTextViewModel titleViewModel, - HelperTextViewModel descriptionLabel, - HelperTextViewModel positivButtonLabel, - HelperTextViewModel negativButtonLabel, + HelperBoxViewModel? boxViewModel, + HelperImageViewModel? helperImageViewModel, + HelperTextViewModel? titleViewModel, + HelperTextViewModel? descriptionLabel, + HelperTextViewModel? positivButtonLabel, + HelperTextViewModel? negativButtonLabel, }) : super( id: id, name: name, @@ -116,7 +116,7 @@ class FullscreenHelperViewModel extends HelperViewModel { fontSize: negativButtonLabel?.fontSize?.toInt() ?? 13, fontFamily: negativButtonLabel?.fontFamily, ); - this.currentEditableItemNotifier = ValueNotifier(null); + this.currentEditableItemNotifier = ValueNotifier(null); } factory FullscreenHelperViewModel.fromHelperViewModel(HelperViewModel model) { @@ -128,17 +128,17 @@ class FullscreenHelperViewModel extends HelperViewModel { maxVersionCode: model.helperGroup?.maxVersionCode, triggerType: model.helperGroup?.triggerType, helperTheme: model.helperTheme, - groupId: model.helperGroup.id, - groupName: model.helperGroup.name + groupId: model.helperGroup!.id, + groupName: model.helperGroup!.name ); if (model is FullscreenHelperViewModel) { - fullscreenHelper.backgroundBoxForm = model?.backgroundBoxForm; + fullscreenHelper.backgroundBoxForm = model.backgroundBoxForm; // fullscreenHelper.language = model?.language; - fullscreenHelper.titleTextForm = model?.titleTextForm; - fullscreenHelper.descriptionTextForm = model?.descriptionTextForm; - fullscreenHelper.positivButtonForm = model?.positivButtonForm; - fullscreenHelper.negativButtonForm = model?.negativButtonForm; - fullscreenHelper.headerMediaForm = model?.headerMediaForm; + fullscreenHelper.titleTextForm = model.titleTextForm; + fullscreenHelper.descriptionTextForm = model.descriptionTextForm; + fullscreenHelper.positivButtonForm = model.positivButtonForm; + fullscreenHelper.negativButtonForm = model.negativButtonForm; + fullscreenHelper.headerMediaForm = model.headerMediaForm; } return fullscreenHelper; @@ -146,38 +146,38 @@ class FullscreenHelperViewModel extends HelperViewModel { factory FullscreenHelperViewModel.fromHelperEntity(HelperEntity helperEntity) => FullscreenHelperViewModel( - id: helperEntity?.id, - name: helperEntity?.name, - triggerType: helperEntity?.triggerType, - priority: helperEntity?.priority, + id: helperEntity.id, + name: helperEntity.name, + triggerType: helperEntity.triggerType, + priority: helperEntity.priority, helperTheme: null, boxViewModel: HelperSharedFactory.parseBoxBackground( FullscreenHelperKeys.BACKGROUND_KEY, - helperEntity?.helperBoxes, + helperEntity.helperBoxes!, ), titleViewModel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.TITLE_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), descriptionLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.DESCRIPTION_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), positivButtonLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.POSITIV_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), negativButtonLabel: HelperSharedFactory.parseTextLabel( FullscreenHelperKeys.NEGATIV_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), helperImageViewModel: HelperSharedFactory.parseImageUrl( FullscreenHelperKeys.IMAGE_KEY, - helperEntity?.helperImages, + helperEntity.helperImages, ), ); - List get fields => [ + List get fields => [ titleTextForm, descriptionTextForm, positivButtonForm, diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper.dart index 31eacb5b..51b1a31d 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper.dart @@ -35,11 +35,11 @@ abstract class EditorSimpleHelperView { class EditorSimpleHelperPage extends StatelessWidget { final SimpleHelperViewModel baseviewModel; - final HelperEditorPageArguments arguments; + final HelperEditorPageArguments? arguments; - final EditorHelperService helperService; + final EditorHelperService? helperService; - final PalEditModeStateService palEditModeStateService; + final PalEditModeStateService? palEditModeStateService; final GlobalKey _scaffoldKey = GlobalKey(); @@ -48,19 +48,19 @@ class EditorSimpleHelperPage extends StatelessWidget { final GlobalKey _textKey = GlobalKey(); EditorSimpleHelperPage._( - {Key key, + {Key? key, this.helperService, - @required this.baseviewModel, - @required this.arguments, + required this.baseviewModel, + required this.arguments, this.palEditModeStateService}) : super(key: key); factory EditorSimpleHelperPage.create( - {Key key, - HelperEditorPageArguments parameters, - EditorHelperService helperService, - PalEditModeStateService palEditModeStateService, - @required HelperViewModel helperViewModel}) => + {Key? key, + HelperEditorPageArguments? parameters, + EditorHelperService? helperService, + PalEditModeStateService? palEditModeStateService, + required HelperViewModel helperViewModel}) => EditorSimpleHelperPage._( key: key, helperService: helperService, @@ -71,11 +71,11 @@ class EditorSimpleHelperPage extends StatelessWidget { ); factory EditorSimpleHelperPage.edit( - {Key key, - HelperEditorPageArguments parameters, - EditorHelperService helperService, - PalEditModeStateService palEditModeStateService, - @required String helperId}) => + {Key? key, + HelperEditorPageArguments? parameters, + EditorHelperService? helperService, + PalEditModeStateService? palEditModeStateService, + required String? helperId}) => EditorSimpleHelperPage._( key: key, helperService: helperService, @@ -96,9 +96,9 @@ class EditorSimpleHelperPage extends StatelessWidget { context, null, palEditModeStateService ?? - EditorInjector.of(context).palEditModeStateService), + EditorInjector.of(context)!.palEditModeStateService), baseviewModel, - helperService ?? EditorInjector.of(context).helperService, + helperService ?? EditorInjector.of(context)!.helperService, arguments), builder: (context, presenter, model) => _buildPage(context.buildContext, presenter, model), @@ -163,7 +163,7 @@ class EditorSimpleHelperPage extends StatelessWidget { child: Container( width: constraints.maxWidth * 0.8, decoration: BoxDecoration( - color: PalTheme.of(context).colors.black, + color: PalTheme.of(context)!.colors.black, borderRadius: BorderRadius.all( Radius.circular(12), ), @@ -179,7 +179,7 @@ class EditorSimpleHelperPage extends StatelessWidget { .currentSelectedEditableNotifier ?.value ?.key, - backgroundColor: PalTheme.of(context) + backgroundColor: PalTheme.of(context)! .colors .black, // Currently we can't change background ), @@ -204,7 +204,7 @@ class _EditorSimpleHelperPage implements EditorSimpleHelperView { final BuildContext context; - final GlobalKey scaffoldKey; + final GlobalKey? scaffoldKey; final PalEditModeStateService palEditModeStateService; @@ -218,7 +218,7 @@ class _EditorSimpleHelperPage SimpleHelperPage page = SimpleHelperPage( // helperBoxViewModel: HelperSharedFactory.parseBoxNotifier(model.bodyBox), descriptionLabel: - HelperSharedFactory.parseTextNotifier(model.contentTextForm), + HelperSharedFactory.parseTextNotifier(model.contentTextForm!), ); SimpleHelperLayout layout = SimpleHelperLayout( toaster: page, diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper_presenter.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper_presenter.dart index 1e11db91..d453dad1 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper_presenter.dart @@ -17,7 +17,7 @@ class EditorSimpleHelperPresenter extends Presenter { final EditorHelperService editorHelperService; - final HelperEditorPageArguments parameters; + final HelperEditorPageArguments? parameters; bool editMode = false; @@ -42,7 +42,7 @@ class EditorSimpleHelperPresenter viewModel.currentSelectedEditableNotifier = ValueNotifier(null); this .viewModel - .currentSelectedEditableNotifier + .currentSelectedEditableNotifier! .addListener(removeSelectedEditableItems); this.viewModel.loading = false; this.refreshView(); @@ -52,7 +52,7 @@ class EditorSimpleHelperPresenter viewModel.currentSelectedEditableNotifier = ValueNotifier(null); this .viewModel - .currentSelectedEditableNotifier + .currentSelectedEditableNotifier! .addListener(removeSelectedEditableItems); this.viewModel.loading = false; this.refreshView(); @@ -81,7 +81,7 @@ class EditorSimpleHelperPresenter Future onValidate() async { ValueNotifier status = new ValueNotifier(SendingStatus.SENDING); - final config = CreateHelperConfig.from(parameters.pageId, viewModel); + final config = CreateHelperConfig.from(parameters!.pageId, viewModel); try { await viewInterface.showLoadingScreen(status); await Future.delayed(Duration(seconds: 1)); @@ -104,7 +104,7 @@ class EditorSimpleHelperPresenter viewInterface.closeEditor(!this.editMode,false); } - String validateDetailsTextField(String currentValue) { + String? validateDetailsTextField(String currentValue) { if (currentValue.length <= 0) { return 'Please enter some text'; } @@ -125,37 +125,37 @@ class EditorSimpleHelperPresenter } onFontPickerDone(EditedFontModel newFont) { - this.viewModel.contentTextForm.fontFamily = - newFont.fontKeys.fontFamilyNameKey; - this.viewModel.contentTextForm.fontWeight = - newFont.fontKeys.fontWeightNameKey; - this.viewModel.contentTextForm.fontSize = newFont.size.toInt(); + this.viewModel.contentTextForm!.fontFamily = + newFont.fontKeys!.fontFamilyNameKey; + this.viewModel.contentTextForm!.fontWeight = + newFont.fontKeys!.fontWeightNameKey; + this.viewModel.contentTextForm!.fontSize = newFont.size!.toInt(); this._updateValidState(); } onTextPickerDone(String newVal) { - this.viewModel.contentTextForm.text = newVal; + this.viewModel.contentTextForm!.text = newVal; this._updateValidState(); } onTextColorPickerDone(Color newColor) { - this.viewModel.contentTextForm.fontColor = newColor; + this.viewModel.contentTextForm!.fontColor = newColor; this._updateValidState(); } - onNewEditableSelect(EditableData editedData) { - this.viewModel.currentSelectedEditableNotifier.value = editedData; + onNewEditableSelect(EditableData? editedData) { + this.viewModel.currentSelectedEditableNotifier!.value = editedData; this.refreshView(); } - bool isValid() => viewModel.contentTextForm.text.isNotEmpty; + bool isValid() => viewModel.contentTextForm!.text!.isNotEmpty; // ---------------------------------- // PRIVATES // ---------------------------------- _updateValidState() { - viewModel.canValidate.value = isValid(); + viewModel.canValidate!.value = isValid(); this.refreshView(); } } diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper_viewmodel.dart index d74a2918..695c7318 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_simple_helper/editor_simple_helper_viewmodel.dart @@ -12,30 +12,30 @@ import 'package:pal/src/ui/shared/helper_shared_viewmodels.dart'; class SimpleHelperViewModel extends HelperViewModel { // form validation boolean - ValueNotifier canValidate; + ValueNotifier? canValidate; // LanguageNotifier language; // TODO : Add background box attribute // EditableBoxFormData bodyBox; - EditableTextFormData contentTextForm; - ValueNotifier currentSelectedEditableNotifier; + EditableTextFormData? contentTextForm; + ValueNotifier? currentSelectedEditableNotifier; - bool loading; + bool? loading; SimpleHelperViewModel({ - String id, - @required String name, - @required HelperTriggerType triggerType, - @required int priority, - String groupId, - String groupName, - String minVersionCode, - String maxVersionCode, - HelperTheme helperTheme, - int versionMaxId, - int languageId, + String? id, + required String? name, + required HelperTriggerType? triggerType, + required int? priority, + String? groupId, + String? groupName, + String? minVersionCode, + String? maxVersionCode, + HelperTheme? helperTheme, + int? versionMaxId, + int? languageId, // HelperBoxViewModel helperBoxViewModel, - HelperTextViewModel contentTextViewModel, + HelperTextViewModel? contentTextViewModel, }) : super( id: id, name: name, @@ -70,31 +70,31 @@ class SimpleHelperViewModel extends HelperViewModel { factory SimpleHelperViewModel.fromHelperViewModel(HelperViewModel model) { final simpleHelper = SimpleHelperViewModel( - id: model?.id, + id: model.id, name: model.name, priority: model.priority, helperTheme: model.helperTheme, triggerType: model.helperGroup?.triggerType, minVersionCode: model.helperGroup?.minVersionCode, maxVersionCode: model.helperGroup?.maxVersionCode, - groupId: model.helperGroup.id, - groupName: model.helperGroup.name + groupId: model.helperGroup!.id, + groupName: model.helperGroup!.name ); if (model is SimpleHelperViewModel) { // simpleHelper.bodyBox = model?.bodyBox; // simpleHelper.language = model?.language; - simpleHelper.contentTextForm = model?.contentTextForm; + simpleHelper.contentTextForm = model.contentTextForm; } return simpleHelper; } factory SimpleHelperViewModel.fromHelperEntity(HelperEntity helperEntity) { return SimpleHelperViewModel( - id: helperEntity?.id, - name: helperEntity?.name, - triggerType: helperEntity?.triggerType, - priority: helperEntity?.priority, + id: helperEntity.id, + name: helperEntity.name, + triggerType: helperEntity.triggerType, + priority: helperEntity.priority, helperTheme: null, // helperBoxViewModel: HelperSharedFactory.parseBoxBackground( // SimpleHelperKeys.BACKGROUND_KEY, @@ -102,7 +102,7 @@ class SimpleHelperViewModel extends HelperViewModel { // ), contentTextViewModel: HelperSharedFactory.parseTextLabel( SimpleHelperKeys.CONTENT_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), ); } diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper.dart index fd23f6b7..e6ce87a0 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper.dart @@ -28,7 +28,7 @@ import 'editor_update_helper_viewmodel.dart'; abstract class EditorUpdateHelperView { void hidePalBubble(); Future scrollToBottomChangelogList(); - Future pushToMediaGallery(final String mediaId); + Future pushToMediaGallery(final String? mediaId); Future showLoadingScreen(ValueNotifier status); Future closeEditor(bool list, bool bubble); void closeLoadingScreen(); @@ -38,35 +38,35 @@ abstract class EditorUpdateHelperView { class EditorUpdateHelperPage extends StatelessWidget { // required params final UpdateHelperViewModel baseviewModel; - final HelperEditorPageArguments arguments; - final EditorHelperService helperService; - final PalEditModeStateService palEditModeStateService; + final HelperEditorPageArguments? arguments; + final EditorHelperService? helperService; + final PalEditModeStateService? palEditModeStateService; // inner page widgets final GlobalKey _scaffoldKey = GlobalKey(); final GlobalKey formKey = GlobalKey(); final ScrollController scrollController = ScrollController(); - final PackageVersionReader packageVersionReader; + final PackageVersionReader? packageVersionReader; // final GlobalKey _titleKey = GlobalKey(); // final GlobalKey _thanksButtonKey = GlobalKey(); EditorUpdateHelperPage._({ - Key key, + Key? key, this.helperService, this.palEditModeStateService, this.packageVersionReader, - @required this.baseviewModel, - @required this.arguments, + required this.baseviewModel, + required this.arguments, }) : super(key: key); factory EditorUpdateHelperPage.create( - {Key key, - HelperEditorPageArguments parameters, - EditorHelperService helperService, - PalEditModeStateService palEditModeStateService, - PackageVersionReader packageVersionReader, - @required HelperViewModel helperViewModel}) => + {Key? key, + HelperEditorPageArguments? parameters, + EditorHelperService? helperService, + PalEditModeStateService? palEditModeStateService, + PackageVersionReader? packageVersionReader, + required HelperViewModel helperViewModel}) => EditorUpdateHelperPage._( key: key, helperService: helperService, @@ -78,12 +78,12 @@ class EditorUpdateHelperPage extends StatelessWidget { ); factory EditorUpdateHelperPage.edit( - {Key key, - HelperEditorPageArguments parameters, - PalEditModeStateService palEditModeStateService, - EditorHelperService helperService, - PackageVersionReader packageVersionReader, - @required String helperId}) => + {Key? key, + HelperEditorPageArguments? parameters, + PalEditModeStateService? palEditModeStateService, + EditorHelperService? helperService, + PackageVersionReader? packageVersionReader, + required String? helperId}) => EditorUpdateHelperPage._( key: key, helperService: helperService, @@ -112,11 +112,11 @@ class EditorUpdateHelperPage extends StatelessWidget { _scaffoldKey, scrollController, palEditModeStateService ?? - EditorInjector.of(context).palEditModeStateService, + EditorInjector.of(context)!.palEditModeStateService, packageVersionReader ?? - EditorInjector.of(context).packageVersionReader), + EditorInjector.of(context)!.packageVersionReader), baseviewModel, - helperService ?? EditorInjector.of(context).helperService, + helperService ?? EditorInjector.of(context)!.helperService, arguments); return presenter; }, @@ -206,7 +206,7 @@ class EditorUpdateHelperPage extends StatelessWidget { viewModel.backgroundBoxForm?.backgroundColor, isSelected: viewModel.currentEditableItemNotifier?.value?.key == - viewModel.headerMediaForm.key, + viewModel.headerMediaForm!.key, ), SizedBox(height: 40), EditableTextField( @@ -216,7 +216,7 @@ class EditorUpdateHelperPage extends StatelessWidget { viewModel.backgroundBoxForm?.backgroundColor, isSelected: viewModel.currentEditableItemNotifier?.value?.key == - viewModel.titleTextForm.key, + viewModel.titleTextForm!.key, ), SizedBox(height: 25.0), _buildChangelogFields(context, presenter, viewModel), @@ -243,7 +243,7 @@ class EditorUpdateHelperPage extends StatelessWidget { final UpdateHelperViewModel viewmodel, ) { List changelogsTextfieldWidgets = []; - viewmodel.changelogsTextsForm.forEach((key, field) { + viewmodel.changelogsTextsForm!.forEach((key, field) { changelogsTextfieldWidgets.add( EditableTextField( data: field, @@ -292,13 +292,13 @@ class EditorUpdateHelperPage extends StatelessWidget { onTap: presenter.onNewEditableSelect, backgroundColor: viewModel.backgroundBoxForm?.backgroundColor, isSelected: viewModel.currentEditableItemNotifier?.value?.key == - viewModel.positivButtonForm.key, + viewModel.positivButtonForm!.key, ), ); } //FIXME CONsider extension - TextStyle googleCustomFont(String fontFamily) { + TextStyle? googleCustomFont(String fontFamily) { return (fontFamily != null && fontFamily.length > 0) ? GoogleFonts.getFont(fontFamily) : null; @@ -325,14 +325,14 @@ class _EditorUpdateHelperPage BuildContext get overlayContext => context; @override - Future pushToMediaGallery(final String mediaId) async { + Future pushToMediaGallery(final String? mediaId) async { final media = await Navigator.pushNamed( - scaffoldKey.currentContext, + scaffoldKey.currentContext!, '/editor/media-gallery', arguments: MediaGalleryPageArguments( mediaId, ), - ) as GraphicEntity; + ) as GraphicEntity?; return media; } @@ -350,15 +350,15 @@ class _EditorUpdateHelperPage Future showPreviewOfHelper(UpdateHelperViewModel model) async { UserUpdateHelperPage page = UserUpdateHelperPage( helperBoxViewModel: - HelperSharedFactory.parseBoxNotifier(model.backgroundBoxForm), - titleLabel: HelperSharedFactory.parseTextNotifier(model.titleTextForm), + HelperSharedFactory.parseBoxNotifier(model.backgroundBoxForm!), + titleLabel: HelperSharedFactory.parseTextNotifier(model.titleTextForm!), thanksButtonLabel: - HelperSharedFactory.parseButtonNotifier(model.positivButtonForm), - changelogLabels: model.changelogsTextsForm.entries + HelperSharedFactory.parseButtonNotifier(model.positivButtonForm!), + changelogLabels: model.changelogsTextsForm!.entries .map((e) => HelperSharedFactory.parseTextNotifier(e.value)) .toList(), helperImageViewModel: - HelperSharedFactory.parseMediaNotifier(model.headerMediaForm), + HelperSharedFactory.parseMediaNotifier(model.headerMediaForm!), onPositivButtonTap: () => Navigator.pop(context), packageVersionReader: this.packageVersionReader, ); diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper_presenter.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper_presenter.dart index aaf39357..6618b771 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper_presenter.dart @@ -17,11 +17,11 @@ import 'editor_update_helper_viewmodel.dart'; class EditorUpdateHelperPresenter extends Presenter { final EditorHelperService editorHelperService; - final HelperEditorPageArguments parameters; + final HelperEditorPageArguments? parameters; final StreamController editableTextFieldController; - final GlobalKey titleKey; - final GlobalKey thanksButtonKey; + final GlobalKey? titleKey; + final GlobalKey? thanksButtonKey; // EDIT MODE bool editMode = false; @@ -49,7 +49,7 @@ class EditorUpdateHelperPresenter this.viewModel.isKeyboardVisible = false; this .viewModel - .currentEditableItemNotifier + .currentEditableItemNotifier! .addListener(removeSelectedEditableItems); this.refreshView(); }); @@ -58,7 +58,7 @@ class EditorUpdateHelperPresenter this.viewModel.isKeyboardVisible = false; this .viewModel - .currentEditableItemNotifier + .currentEditableItemNotifier! .addListener(removeSelectedEditableItems); this.refreshView(); } @@ -70,7 +70,7 @@ class EditorUpdateHelperPresenter void onDestroy() { this .viewModel - .currentEditableItemNotifier + .currentEditableItemNotifier! .removeListener(removeSelectedEditableItems); } @@ -86,38 +86,38 @@ class EditorUpdateHelperPresenter } onTextPickerDone(String newVal) { - (this.viewModel.currentEditableItemNotifier.value as EditableTextData) + (this.viewModel.currentEditableItemNotifier!.value as EditableTextData) .text = newVal; this.refreshView(); this._updateValidState(); } onFontPickerDone(EditedFontModel newVal) { - (this.viewModel.currentEditableItemNotifier.value as EditableTextData) - .fontFamily = newVal.fontKeys.fontFamilyNameKey; - (this.viewModel.currentEditableItemNotifier.value as EditableTextData) - .fontSize = newVal.size.toInt(); - (this.viewModel.currentEditableItemNotifier.value as EditableTextData) - .fontWeight = newVal.fontKeys.fontWeightNameKey; + (this.viewModel.currentEditableItemNotifier!.value as EditableTextData) + .fontFamily = newVal.fontKeys!.fontFamilyNameKey; + (this.viewModel.currentEditableItemNotifier!.value as EditableTextData) + .fontSize = newVal.size!.toInt(); + (this.viewModel.currentEditableItemNotifier!.value as EditableTextData) + .fontWeight = newVal.fontKeys!.fontWeightNameKey; this.refreshView(); } onMediaPickerDone(GraphicEntity newVal) { - (this.viewModel.currentEditableItemNotifier.value as EditableMediaFormData) + (this.viewModel.currentEditableItemNotifier!.value as EditableMediaFormData) .url = newVal.url; - (this.viewModel.currentEditableItemNotifier.value as EditableMediaFormData) + (this.viewModel.currentEditableItemNotifier!.value as EditableMediaFormData) .uuid = newVal.id; this.refreshView(); } onTextColorPickerDone(Color newVal) { - (this.viewModel.currentEditableItemNotifier.value as EditableTextData) + (this.viewModel.currentEditableItemNotifier!.value as EditableTextData) .fontColor = newVal; this.refreshView(); } - onNewEditableSelect(EditableData editedData) { - this.viewModel.currentEditableItemNotifier.value = editedData; + onNewEditableSelect(EditableData? editedData) { + this.viewModel.currentEditableItemNotifier!.value = editedData; this.refreshView(); } @@ -137,7 +137,7 @@ class EditorUpdateHelperPresenter Future onValidate() async { ValueNotifier status = new ValueNotifier(SendingStatus.SENDING); - final config = CreateHelperConfig.from(parameters.pageId, viewModel); + final config = CreateHelperConfig.from(parameters!.pageId, viewModel); try { await viewInterface.showLoadingScreen(status); await Future.delayed(Duration(seconds: 1)); @@ -156,7 +156,7 @@ class EditorUpdateHelperPresenter } updateBackgroundColor(Color aColor) { - viewModel.backgroundBoxForm.backgroundColor = aColor; + viewModel.backgroundBoxForm!.backgroundColor = aColor; this._updateValidState(); this.refreshView(); } @@ -172,7 +172,7 @@ class EditorUpdateHelperPresenter this.refreshView(); } - String validateTitleTextField(String currentValue) { + String? validateTitleTextField(String currentValue) { if (currentValue.length <= 0) { return 'Please enter some text'; } @@ -182,7 +182,7 @@ class EditorUpdateHelperPresenter return null; } - String validateChangelogTextField(String currentValue) { + String? validateChangelogTextField(String currentValue) { if (currentValue.length <= 0) { return 'Please enter some text'; } @@ -197,12 +197,12 @@ class EditorUpdateHelperPresenter // ---------------------------------- _updateValidState() { - viewModel.canValidate.value = isValid(); + viewModel.canValidate!.value = isValid(); } bool isValid() => - viewModel.titleTextForm.text.isNotEmpty && - viewModel.changelogsTextsForm.length > 0; + viewModel.titleTextForm!.text!.isNotEmpty && + viewModel.changelogsTextsForm!.length > 0; onPreview() { this.viewInterface.showPreviewOfHelper(this.viewModel); diff --git a/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper_viewmodel.dart index 80bcbb03..156aaaa8 100644 --- a/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/helpers/editor_update_helper/editor_update_helper_viewmodel.dart @@ -11,36 +11,36 @@ import 'package:pal/src/ui/shared/helper_shared_viewmodels.dart'; class UpdateHelperViewModel extends HelperViewModel { // form validation boolean - ValueNotifier canValidate; - bool isKeyboardVisible; + ValueNotifier? canValidate; + bool? isKeyboardVisible; // LanguageNotifier language; - ValueNotifier currentEditableItemNotifier; - EditableBoxFormData backgroundBoxForm; - Map changelogsTextsForm; - EditableMediaFormData headerMediaForm; - EditableButtonFormData positivButtonForm; - EditableTextFormData titleTextForm; + ValueNotifier? currentEditableItemNotifier; + EditableBoxFormData? backgroundBoxForm; + Map? changelogsTextsForm; + EditableMediaFormData? headerMediaForm; + EditableButtonFormData? positivButtonForm; + EditableTextFormData? titleTextForm; - bool loading; + bool? loading; UpdateHelperViewModel({ - String id, - @required String name, - @required HelperTriggerType triggerType, - @required int priority, - @required HelperTheme helperTheme, - String groupId, - String groupName, - String minVersionCode, - String maxVersionCode, - int versionMaxId, - int languageId, - HelperBoxViewModel helperBoxViewModel, - Map changelogsLabels, - HelperImageViewModel helperImageViewModel, - HelperTextViewModel titleLabel, - HelperTextViewModel positivButtonLabel, + String? id, + required String? name, + required HelperTriggerType? triggerType, + required int? priority, + required HelperTheme? helperTheme, + String? groupId, + String? groupName, + String? minVersionCode, + String? maxVersionCode, + int? versionMaxId, + int? languageId, + HelperBoxViewModel? helperBoxViewModel, + Map? changelogsLabels, + HelperImageViewModel? helperImageViewModel, + HelperTextViewModel? titleLabel, + HelperTextViewModel? positivButtonLabel, }) : super( id: id, name: name, @@ -87,7 +87,7 @@ class UpdateHelperViewModel extends HelperViewModel { fontFamily: titleLabel?.fontFamily, hintText: 'Enter your title here...', ); - this.currentEditableItemNotifier = ValueNotifier(null); + this.currentEditableItemNotifier = ValueNotifier(null); } factory UpdateHelperViewModel.fromHelperViewModel(HelperViewModel model) { @@ -96,19 +96,19 @@ class UpdateHelperViewModel extends HelperViewModel { name: model.name, priority: model.priority, helperTheme: model.helperTheme, - triggerType: model?.helperGroup?.triggerType, - minVersionCode: model?.helperGroup?.minVersionCode, - maxVersionCode: model?.helperGroup?.maxVersionCode, + triggerType: model.helperGroup?.triggerType, + minVersionCode: model.helperGroup?.minVersionCode, + maxVersionCode: model.helperGroup?.maxVersionCode, groupId: model.helperGroup?.id, groupName: model.helperGroup?.name); if (model is UpdateHelperViewModel) { - updateHelper.backgroundBoxForm = model?.backgroundBoxForm; + updateHelper.backgroundBoxForm = model.backgroundBoxForm; // updateHelper.language = model?.language; - updateHelper.titleTextForm = model?.titleTextForm; - updateHelper.positivButtonForm = model?.positivButtonForm; - updateHelper.changelogsTextsForm = model?.changelogsTextsForm; - updateHelper.headerMediaForm = model?.headerMediaForm; + updateHelper.titleTextForm = model.titleTextForm; + updateHelper.positivButtonForm = model.positivButtonForm; + updateHelper.changelogsTextsForm = model.changelogsTextsForm; + updateHelper.headerMediaForm = model.headerMediaForm; } return updateHelper; @@ -118,7 +118,7 @@ class UpdateHelperViewModel extends HelperViewModel { Map changelogsMap = {}; List changelogs = HelperSharedFactory.parseTextsLabel( UpdatescreenHelperKeys.LINES_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ); if (changelogs != null && changelogs.length > 0) { @@ -127,38 +127,38 @@ class UpdateHelperViewModel extends HelperViewModel { changelogsMap.putIfAbsent( 'template_${changelog.id.toString()}', () => EditableTextFormData( - changelog?.id, + changelog.id, '${UpdatescreenHelperKeys.LINES_KEY}_${index++}', - text: changelog?.text ?? '', - fontColor: changelog?.fontColor ?? Colors.white, - fontSize: changelog?.fontSize?.toInt() ?? 18, - fontFamily: changelog?.fontFamily, - fontWeight: FontWeightMapper.toFontKey(changelog?.fontWeight), + text: changelog.text ?? '', + fontColor: changelog.fontColor ?? Colors.white, + fontSize: changelog.fontSize?.toInt() ?? 18, + fontFamily: changelog.fontFamily, + fontWeight: FontWeightMapper.toFontKey(changelog.fontWeight), ), ); } } return UpdateHelperViewModel( - id: helperEntity?.id, - name: helperEntity?.name, - triggerType: helperEntity?.triggerType, - priority: helperEntity?.priority, + id: helperEntity.id, + name: helperEntity.name, + triggerType: helperEntity.triggerType, + priority: helperEntity.priority, helperTheme: null, helperBoxViewModel: HelperSharedFactory.parseBoxBackground( SimpleHelperKeys.BACKGROUND_KEY, - helperEntity?.helperBoxes, + helperEntity.helperBoxes!, ), titleLabel: HelperSharedFactory.parseTextLabel( UpdatescreenHelperKeys.TITLE_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), positivButtonLabel: HelperSharedFactory.parseTextLabel( UpdatescreenHelperKeys.POSITIV_KEY, - helperEntity?.helperTexts, + helperEntity.helperTexts!, ), helperImageViewModel: HelperSharedFactory.parseImageUrl( UpdatescreenHelperKeys.IMAGE_KEY, - helperEntity?.helperImages, + helperEntity.helperImages, ), changelogsLabels: changelogsMap, // TODO: Add changelog edit @@ -166,12 +166,12 @@ class UpdateHelperViewModel extends HelperViewModel { } String addChangelog() { - String textFieldId = changelogsTextsForm.length.toString(); - this.changelogsTextsForm.putIfAbsent( + String textFieldId = changelogsTextsForm!.length.toString(); + this.changelogsTextsForm!.putIfAbsent( textFieldId, () => EditableTextFormData( null, - '${UpdatescreenHelperKeys.LINES_KEY}_${changelogsTextsForm.length}', + '${UpdatescreenHelperKeys.LINES_KEY}_${changelogsTextsForm!.length}', text: '', fontSize: 18, fontColor: Colors.white, @@ -182,7 +182,7 @@ class UpdateHelperViewModel extends HelperViewModel { List get fields => [ titleTextForm, - ...changelogsTextsForm.values, + ...changelogsTextsForm!.values, positivButtonForm, ]; } diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_button.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_button.dart index e3c471c0..798e6e1d 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_button.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_button.dart @@ -4,10 +4,10 @@ import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/shared/widgets/circle_button.dart'; class EditorButton extends StatelessWidget { - final Function onPressed; - final double size; - final Icon icon; - final Color bgColor, iconColor; + final Function? onPressed; + final double? size; + final Icon? icon; + final Color? bgColor, iconColor; final bool bordered; final bool isEnabled; @@ -19,11 +19,11 @@ class EditorButton extends StatelessWidget { this.iconColor, this.bordered = false, this.isEnabled = true, - Key key, + Key? key, }) : super(key: key); factory EditorButton.validate(PalThemeData theme, Function onPressed, - {Key key, bool isEnabled = true}) => + {Key? key, bool isEnabled = true}) => EditorButton( onPressed: onPressed, size: 52, @@ -34,7 +34,7 @@ class EditorButton extends StatelessWidget { ); factory EditorButton.cancel(PalThemeData theme, Function onPressed, - {Key key, bool isEnabled = true}) => + {Key? key, bool isEnabled = true}) => EditorButton( onPressed: onPressed, size: 40, @@ -45,7 +45,7 @@ class EditorButton extends StatelessWidget { ); factory EditorButton.editMode(PalThemeData theme, Function onPressed, - {Key key, bool isEnabled = true}) => + {Key? key, bool isEnabled = true}) => EditorButton( onPressed: onPressed, size: 52, @@ -60,7 +60,7 @@ class EditorButton extends StatelessWidget { Widget build(BuildContext context) { return CircleIconButton( icon: icon, - radius: size / 2, + radius: size! / 2, backgroundColor: bgColor, onTapCallback: (onPressed != null && this.isEnabled) ? onPressed : null, ); diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_sending_overlay.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_sending_overlay.dart index 03a2be9b..d8c48e43 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_sending_overlay.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_sending_overlay.dart @@ -17,10 +17,10 @@ enum SendingStatus { /// ... /// } mixin EditorSendingOverlayMixin { - EditorSendingOverlay sendingOverlay; - BuildContext overlayContext; + EditorSendingOverlay? sendingOverlay; + BuildContext? overlayContext; - void closeLoadingScreen() => sendingOverlay.dismiss(); + void closeLoadingScreen() => sendingOverlay!.dismiss(); Future showLoadingScreen(ValueNotifier status) async { sendingOverlay = EditorSendingOverlay( @@ -30,7 +30,7 @@ mixin EditorSendingOverlayMixin { errorMessage: "Error occured, please try again later", status: status ); - await sendingOverlay.show(overlayContext); + await sendingOverlay!.show(overlayContext!); } } @@ -43,14 +43,14 @@ class EditorSendingOverlay { String errorMessage; ValueNotifier status; - OverlayEntry _entry; + OverlayEntry? _entry; EditorSendingOverlay({ - @required this.loadingOpacity, - @required this.loadingMessage, - @required this.successMessage, - @required this.errorMessage, - @required this.status + required this.loadingOpacity, + required this.loadingMessage, + required this.successMessage, + required this.errorMessage, + required this.status }); Future show(BuildContext context) async { @@ -64,12 +64,12 @@ class EditorSendingOverlay { ) ); } - Overlay.of(context).insert(_entry); + Overlay.of(context)!.insert(_entry!); } dismiss() { if(_entry != null) { - _entry.remove(); + _entry!.remove(); _entry = null; } } @@ -77,7 +77,7 @@ class EditorSendingOverlay { Widget _build() { return ValueListenableBuilder( valueListenable: status, - builder: (BuildContext context, SendingStatus currentStatus, Widget child) + builder: (BuildContext context, SendingStatus currentStatus, Widget? child) => AnimatedOpacity( duration: Duration(milliseconds: 400), opacity: loadingOpacity, diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox.dart index 1573dd76..b7b486c5 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox.dart @@ -15,11 +15,11 @@ import 'editor_toolbox_presenter.dart'; import 'editor_toolbox_viewmodel.dart'; abstract class EditorToolboxView { - Future openTextPicker(String currentText); - Future openFontPicker( - String family, int size, String weight); - Future openColorPicker(Color selectedColor); - Future openMediaPicker(String mediaId); + Future openTextPicker(String? currentText); + Future openFontPicker( + String? family, int? size, String? weight); + Future openColorPicker(Color? selectedColor); + Future openMediaPicker(String? mediaId); void refreshAnimations() {} @@ -30,27 +30,27 @@ class EditorToolboxPage extends StatefulWidget { /// the editor helper final Widget child; // Save button function - final Function onValidate; - final Function onPreview; - final Function onCloseEditor; - final BoxViewHandler boxViewHandler; + final Function? onValidate; + final Function? onPreview; + final Function? onCloseEditor; + final BoxViewHandler? boxViewHandler; // Pickers - final Function(String) onTextPickerDone; - final Function(Color) onTextColorPickerDone; - final Function(EditedFontModel) onFontPickerDone; - final Function(dynamic) onBorderPickerDone; - final Function(GraphicEntity) onMediaPickerDone; + final Function(String)? onTextPickerDone; + final Function(Color)? onTextColorPickerDone; + final Function(EditedFontModel)? onFontPickerDone; + final Function(dynamic)? onBorderPickerDone; + final Function(GraphicEntity)? onMediaPickerDone; - final ValueNotifier currentEditableItemNotifier; - final GlobalKey scaffoldKey; + final ValueNotifier? currentEditableItemNotifier; + final GlobalKey? scaffoldKey; final bool isToolsVisible; EditorToolboxPage({ - Key key, - @required this.child, - @required this.currentEditableItemNotifier, + Key? key, + required this.child, + required this.currentEditableItemNotifier, this.scaffoldKey, this.onValidate, this.onBorderPickerDone, @@ -73,10 +73,10 @@ class _EditorToolboxPageState extends State implements EditorToolboxView { final GlobalKey _scaffoldKey = GlobalKey(); - List controllers; + late List controllers; - EditorToolboxModel model; - EditorToolboxPresenter presenter; + EditorToolboxModel? model; + late EditorToolboxPresenter presenter; _EditorToolboxPageState(); @@ -123,10 +123,10 @@ class _EditorToolboxPageState extends State @override void didUpdateWidget(covariant EditorToolboxPage oldWidget) { - if (model.boxViewHandler != null &&(oldWidget.boxViewHandler.selectedColor != - widget.boxViewHandler.selectedColor)) - this.model.boxViewHandler.selectedColor = - widget.boxViewHandler.selectedColor; + if (model!.boxViewHandler != null &&(oldWidget.boxViewHandler!.selectedColor != + widget.boxViewHandler!.selectedColor)) + this.model!.boxViewHandler!.selectedColor = + widget.boxViewHandler!.selectedColor; super.didUpdateWidget(oldWidget); } @@ -140,14 +140,14 @@ class _EditorToolboxPageState extends State backgroundColor: Colors.transparent, floatingActionButtonLocation: FloatingActionButtonLocation.miniCenterDocked, - floatingActionButton: widget.isToolsVisible && model.animationTarget == 1 + floatingActionButton: widget.isToolsVisible && model!.animationTarget == 1 ? EditorSaveFloatingButton(onTap: this.widget.onValidate) : null, bottomNavigationBar: widget.isToolsVisible ? EditorActionBar( animation: this.controllers[0], iconsColor: Colors.white, - onPreview: widget.onPreview, + onPreview: widget.onPreview as dynamic Function()?, onCancel: () => this.widget.onCloseEditor?.call(), ) : null, @@ -157,7 +157,7 @@ class _EditorToolboxPageState extends State Widget _buildPage( final BuildContext context, final EditorToolboxPresenter presenter, - final EditorToolboxModel model, + final EditorToolboxModel? model, ) { return Stack( children: [ @@ -171,7 +171,7 @@ class _EditorToolboxPageState extends State // vertical editor toolbar if (widget.isToolsVisible) EditorToolBar( - editableElementActions: model.editableElementActions, + editableElementActions: model!.editableElementActions, globalActions: model.globalActions, isBottomBarVisibleNotifier: model.isBottomVisible, drawerAnimation: this.controllers[0], @@ -184,9 +184,9 @@ class _EditorToolboxPageState extends State } @override - Future openColorPicker(Color selectedColor) async { + Future openColorPicker(Color? selectedColor) async { return await showDialog( - context: _scaffoldKey.currentContext, + context: _scaffoldKey.currentContext!, builder: (context) => ColorPickerDialog( placeholderColor: selectedColor, ), @@ -194,13 +194,13 @@ class _EditorToolboxPageState extends State } @override - Future openFontPicker( - String family, int size, String weight) async { + Future openFontPicker( + String? family, int? size, String? weight) async { TextStyle style = TextStyle( - fontSize: size.toDouble(), + fontSize: size!.toDouble(), fontWeight: FontWeightMapper.toFontWeight(weight)); return await showDialog( - context: _scaffoldKey.currentContext, + context: _scaffoldKey.currentContext!, builder: (context) => FontEditorDialogPage( actualTextStyle: style, fontFamilyKey: family, @@ -209,38 +209,38 @@ class _EditorToolboxPageState extends State } @override - Future openTextPicker(String currentText) async { + Future openTextPicker(String? currentText) async { return await showDialog( - context: _scaffoldKey.currentContext, - builder: (context) => EditableTextDialog(currentText), + context: _scaffoldKey.currentContext!, + builder: (context) => EditableTextDialog(currentText!), ); } @override - Future openMediaPicker(String currentMediaId) async { - GraphicEntity graphicEntity = - await Navigator.of(_scaffoldKey.currentContext).pushNamed( + Future openMediaPicker(String? currentMediaId) async { + GraphicEntity? graphicEntity = + await Navigator.of(_scaffoldKey.currentContext!).pushNamed( '/editor/media-gallery', arguments: MediaGalleryPageArguments( currentMediaId, ), - ) as GraphicEntity; + ) as GraphicEntity?; return graphicEntity; } @override void refreshAnimations() { - if (model.animateActionBar) { + if (model!.animateActionBar) { this .controllers[0] - .animateTo(model.animationTarget, curve: Curves.easeOut); - model.animateActionBar = false; + .animateTo(model!.animationTarget!, curve: Curves.easeOut); + model!.animateActionBar = false; } - if (model.animateIcons) { + if (model!.animateIcons!) { this.controllers[1].value = 0; this.controllers[1].animateTo(1, curve: Curves.elasticOut); - model.animateIcons = false; + model!.animateIcons = false; } this.refresh(); } diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_presenter.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_presenter.dart index c7095fb3..0c1596a1 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_presenter.dart @@ -9,12 +9,12 @@ import 'editor_toolbox.dart'; class EditorToolboxPresenter { final EditorToolboxModel viewModel; - final ValueNotifier currentEditableItemNotifier; + final ValueNotifier? currentEditableItemNotifier; final EditorToolboxView viewInterface; - final Function onTextColorPickerDone; - final Function onFontPickerDone; - final Function onMediaPickerDone; - final Function onTextPickerDone; + final Function? onTextColorPickerDone; + final Function? onFontPickerDone; + final Function? onMediaPickerDone; + final Function? onTextPickerDone; EditorToolboxPresenter( this.viewModel, this.currentEditableItemNotifier, this.viewInterface, @@ -43,9 +43,9 @@ class EditorToolboxPresenter { this.viewModel.isBottomVisible = ValueNotifier(true); // BOTTOM ANIMATION - this.viewModel.isBottomVisible.addListener(animateActionBar); + this.viewModel.isBottomVisible!.addListener(animateActionBar); - if(this.currentEditableItemNotifier != null)this.currentEditableItemNotifier.addListener(() { + if(this.currentEditableItemNotifier != null)this.currentEditableItemNotifier!.addListener(() { this.displayEditableItemActions(); }); @@ -53,7 +53,7 @@ class EditorToolboxPresenter { } dispose() { - this.viewModel.isBottomVisible.removeListener(animateActionBar); + this.viewModel.isBottomVisible!.removeListener(animateActionBar); } void animateActionBar() { @@ -62,13 +62,13 @@ class EditorToolboxPresenter { // this.viewInterface.refresh(); // this.refreshView(); this.viewModel.animationTarget = - this.viewModel.isBottomVisible.value ? 1 : 0; + this.viewModel.isBottomVisible!.value ? 1 : 0; this.viewInterface.refresh(); } void displayEditableItemActions() { - switch (this.currentEditableItemNotifier.value?.runtimeType) { + switch (this.currentEditableItemNotifier!.value?.runtimeType) { case EditableButtonFormData: this.viewModel.editableElementActions = [ ToolBarActionButton.text, @@ -91,16 +91,16 @@ class EditorToolboxPresenter { default: } this.viewModel.animateIcons = true; - if (this.currentEditableItemNotifier.value != null) + if (this.currentEditableItemNotifier!.value != null) this.viewInterface.refreshAnimations(); } void onOutsideTap() { this.viewModel.editableElementActions = []; - this.currentEditableItemNotifier.value = null; + this.currentEditableItemNotifier!.value = null; // Hide bottom bar & toolbar here - this.viewModel.isBottomVisible.value = false; + this.viewModel.isBottomVisible!.value = false; this.viewInterface.refresh(); } @@ -109,41 +109,41 @@ class EditorToolboxPresenter { switch (toolBarActionButton) { case ToolBarActionButton.color: EditableTextData editableFormField = - this.currentEditableItemNotifier?.value; - Color newColor = await this + this.currentEditableItemNotifier?.value as EditableTextData; + Color? newColor = await this .viewInterface .openColorPicker(editableFormField.fontColor); if (newColor != null) { - this.onTextColorPickerDone(newColor); + this.onTextColorPickerDone!(newColor); } break; case ToolBarActionButton.font: EditableTextData editableFormField = - this.currentEditableItemNotifier?.value; - EditedFontModel newFont = await this.viewInterface.openFontPicker( + this.currentEditableItemNotifier?.value as EditableTextData; + EditedFontModel? newFont = await this.viewInterface.openFontPicker( editableFormField.fontFamily, editableFormField.fontSize, editableFormField.fontWeight); if (newFont != null) { - this.onFontPickerDone(newFont); + this.onFontPickerDone!(newFont); } break; case ToolBarActionButton.media: - EditableMediaFormData mediaNotifier = - this.currentEditableItemNotifier?.value; - GraphicEntity newGraphicEntity = + EditableMediaFormData? mediaNotifier = + this.currentEditableItemNotifier?.value as EditableMediaFormData?; + GraphicEntity? newGraphicEntity = await this.viewInterface.openMediaPicker(mediaNotifier?.uuid); if (newGraphicEntity != null) { - this.onMediaPickerDone(newGraphicEntity); + this.onMediaPickerDone!(newGraphicEntity); } break; case ToolBarActionButton.text: EditableTextData editableFormField = - this.currentEditableItemNotifier?.value; - String newText = + this.currentEditableItemNotifier?.value as EditableTextData; + String? newText = await this.viewInterface.openTextPicker(editableFormField.text); if (newText != null) { - this.onTextPickerDone(newText); + this.onTextPickerDone!(newText); } break; default: @@ -154,12 +154,12 @@ class EditorToolboxPresenter { ToolBarGlobalActionButton toolBarGlobalActionButton) async { switch (toolBarGlobalActionButton) { case ToolBarGlobalActionButton.backgroundColor: - Color newColor = await this + Color? newColor = await this .viewInterface .openColorPicker(this.viewModel.boxViewHandler?.selectedColor); if (newColor != null) { - this.viewModel.boxViewHandler.selectedColor = newColor; - this.viewModel.boxViewHandler.callback(newColor); + this.viewModel.boxViewHandler!.selectedColor = newColor; + this.viewModel.boxViewHandler!.callback!(newColor); } break; default: diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_viewmodel.dart index 01c0431d..fdb91218 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_viewmodel.dart @@ -4,8 +4,8 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid typedef OnNewBgColor(Color color); class EditedBorderData { - double thickness; - Color color; + double? thickness; + Color? color; EditedBorderData( Key key, { @@ -15,10 +15,10 @@ class EditedBorderData { } class EditedFontData { - Color color; - double size; - String fontFamily; - FontWeight fontWeight; + Color? color; + double? size; + String? fontFamily; + FontWeight? fontWeight; EditedFontData( Key key, { @@ -30,20 +30,20 @@ class EditedFontData { } class EditorToolboxModel { - bool isActionBarVisible; - bool isToolBarVisible; + bool? isActionBarVisible; + bool? isToolBarVisible; - bool animateIcons; - double animationTarget; + bool? animateIcons; + double? animationTarget; - ValueNotifier isBottomVisible; + ValueNotifier? isBottomVisible; - List globalActions; - List editableElementActions; + List? globalActions; + List? editableElementActions; - BoxViewHandler boxViewHandler; + BoxViewHandler? boxViewHandler; - bool animateActionBar; + late bool animateActionBar; EditorToolboxModel({ this.isActionBarVisible, @@ -58,8 +58,8 @@ class EditorToolboxModel { } class BoxViewHandler{ - Color selectedColor; - OnNewBgColor callback; + Color? selectedColor; + OnNewBgColor? callback; BoxViewHandler({this.selectedColor, this.callback}); } diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_background.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_background.dart index f3abb98b..5d758ff7 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_background.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_background.dart @@ -3,20 +3,20 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; class EditableBackground extends StatelessWidget { - final Color backgroundColor; + final Color? backgroundColor; final Widget widget; - final bool isSelected; + final bool? isSelected; const EditableBackground({ - Key key, - @required this.backgroundColor, - @required this.widget, + Key? key, + required this.backgroundColor, + required this.widget, this.isSelected, }) : super(key: key); @override Widget build(BuildContext context) { - Color _borderColor = this.backgroundColor.computeLuminance() > 0.5 + Color _borderColor = this.backgroundColor!.computeLuminance() > 0.5 ? Colors.black : Colors.white; diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_button.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_button.dart index 2ebbbecf..98eb79fc 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_button.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_button.dart @@ -6,22 +6,22 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid import 'package:pal/src/ui/shared/widgets/bouncing_widget.dart'; class EditableButton extends StatelessWidget { - final EditableButtonFormData data; - final Function(EditableData) onTap; + final EditableButtonFormData? data; + final Function(EditableData?)? onTap; final bool isSelected; - final Color backgroundColor; + final Color? backgroundColor; final bool outline; const EditableButton({ - Key key, - @required this.data, + Key? key, + required this.data, this.onTap, this.isSelected = false, this.backgroundColor, this.outline = false, }) : super(key: key); - TextStyle googleCustomFont(String fontFamily) => + TextStyle? googleCustomFont(String? fontFamily) => (fontFamily != null && fontFamily.length > 0) ? GoogleFonts.getFont(fontFamily) : null; @@ -35,7 +35,7 @@ class EditableButton extends StatelessWidget { : this.data?.fontColor?.withAlpha(120), ).merge(googleCustomFont(this.data?.fontFamily)); - Color get borderColor => this.backgroundColor.computeLuminance() > 0.5 + Color get borderColor => this.backgroundColor!.computeLuminance() > 0.5 ? Colors.black : Colors.white; @@ -73,9 +73,9 @@ class EditableButton extends StatelessWidget { ), ); - _buildEditableBordered({Widget child}) { + _buildEditableBordered({required Widget child}) { final ButtonStyle outlineButtonStyle = OutlinedButton.styleFrom( - primary: borderColor ?? Colors.white, + primary: borderColor, minimumSize: Size(88, 36), padding: EdgeInsets.symmetric(horizontal: 16), shape: const RoundedRectangleBorder( @@ -85,7 +85,8 @@ class EditableButton extends StatelessWidget { ).copyWith( side: MaterialStateProperty.resolveWith( (Set states) => BorderSide( - color: borderColor ?? Colors.white, width: 1, + color: borderColor, + width: 1, ), ), ); diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_media.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_media.dart index bf0dc6d4..7aba4359 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_media.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_media.dart @@ -6,24 +6,24 @@ import 'package:pal/src/ui/editor/pages/helper_editor/helper_editor_data.dart'; import 'package:pal/src/ui/shared/widgets/bouncing_widget.dart'; class EditableMedia extends StatelessWidget { - final EditableMediaFormData data; + final EditableMediaFormData? data; final double size; - final Function(EditableData) onTap; + final Function(EditableData?)? onTap; final bool isSelected; - final Color backgroundColor; + final Color? backgroundColor; EditableMedia({ - Key key, + Key? key, this.size = 200.0, this.onTap, - @required this.data, + required this.data, this.isSelected = false, - @required this.backgroundColor, + required this.backgroundColor, }) : super(key: key); @override Widget build(BuildContext context) { - Color _borderColor = this.backgroundColor.computeLuminance() > 0.5 + Color _borderColor = this.backgroundColor!.computeLuminance() > 0.5 ? Colors.black : Colors.white; @@ -37,9 +37,9 @@ class EditableMedia extends StatelessWidget { strokeWidth: this.isSelected ? 3.0 : 1.0, child: Padding( padding: const EdgeInsets.all(8.0), - child: (this.data?.url != null && this.data.url.length > 0) + child: (this.data?.url != null && this.data!.url!.length > 0) ? CachedNetworkImage( - imageUrl: this.data?.url, + imageUrl: this.data!.url!, width: this.size, placeholder: (context, url) => Center( child: CircularProgressIndicator(), diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_textfield.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_textfield.dart index c01d1d87..0534e792 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_textfield.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editable/editable_textfield.dart @@ -6,16 +6,16 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid import 'package:pal/src/ui/shared/widgets/bouncing_widget.dart'; class EditableTextField extends StatelessWidget { - final EditableTextFormData data; - final Function(EditableData) onTap; + final EditableTextFormData? data; + final Function(EditableData?)? onTap; final bool isSelected; - final Color backgroundColor; + final Color? backgroundColor; const EditableTextField({ - Key key, + Key? key, this.onTap, - @required this.data, - @required this.backgroundColor, + required this.data, + required this.backgroundColor, this.isSelected = false, }) : super(key: key); @@ -30,7 +30,7 @@ class EditableTextField extends StatelessWidget { _googleCustomFont(this.data?.fontFamily), ); - Color _borderColor = this.backgroundColor.computeLuminance() > 0.5 + Color _borderColor = this.backgroundColor!.computeLuminance() > 0.5 ? Colors.black : Colors.white; return BouncingWidget( @@ -54,9 +54,9 @@ class EditableTextField extends StatelessWidget { border: InputBorder.none, enabledBorder: InputBorder.none, hintText: 'Edit me!', - hintStyle: textStyle?.merge( + hintStyle: textStyle.merge( TextStyle( - color: textStyle?.color?.withAlpha(80), + color: textStyle.color?.withAlpha(80), ), ), ), @@ -68,7 +68,7 @@ class EditableTextField extends StatelessWidget { } // TODO : move to extension - TextStyle _googleCustomFont(String fontFamily) { + TextStyle? _googleCustomFont(String? fontFamily) { return (fontFamily != null && fontFamily.length > 0) ? GoogleFonts.getFont(fontFamily) : null; diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_action_bar/editor_action_bar.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_action_bar/editor_action_bar.dart index 51b9dfb8..030859a5 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_action_bar/editor_action_bar.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_action_bar/editor_action_bar.dart @@ -12,13 +12,13 @@ class EditorActionBar extends StatelessWidget { // ANIMATION VALUE BETWEEN [0,1] 0 => Hidden; 1 => Shown final AnimationController animation; // ICONS ATTRIBUTES - final Color iconsColor; - final double iconsSize; + final Color? iconsColor; + final double? iconsSize; // ONTAP FUNCTION - final OnCancel onCancel; - final OnPreview onPreview; - final OnSettings onSettings; - final OnText onText; + final OnCancel? onCancel; + final OnPreview? onPreview; + final OnSettings? onSettings; + final OnText? onText; // CONST ANIMATIONS BOUNDS final double kUpperbound = 65; final double kLowerbound = 0; @@ -30,7 +30,7 @@ class EditorActionBar extends StatelessWidget { this.onPreview, this.onSettings, this.onText, - @required this.animation, + required this.animation, }); @override @@ -40,7 +40,7 @@ class EditorActionBar extends StatelessWidget { builder: (context, child) => Transform.translate( offset: Offset(0, this.animation.value * (MediaQuery.of(context).padding.bottom + kUpperbound)), child: child), child: BottomAppBar( - color: PalTheme.of(context).colors.dark, + color: PalTheme.of(context)!.colors.dark, shape: null, child: Padding( padding: EdgeInsets.symmetric(vertical: 8), diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_action_bar/widgets/editor_action_item.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_action_bar/widgets/editor_action_item.dart index 0528181b..7df0a186 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_action_bar/widgets/editor_action_item.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_action_bar/widgets/editor_action_item.dart @@ -4,19 +4,19 @@ import 'package:pal/src/ui/shared/widgets/bouncing_widget.dart'; class EditorActionItem extends StatelessWidget { final Icon icon; final String text; - final Function onTap; + final Function? onTap; EditorActionItem({ - Key key, - @required this.icon, - @required this.text, + Key? key, + required this.icon, + required this.text, this.onTap, }) : super(key: key); @override Widget build(BuildContext context) { return BouncingWidget( - onTap: this.onTap, + onTap: this.onTap as void Function()?, child: Container( color: Colors.transparent, child: ConstrainedBox( diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_save_floating_button.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_save_floating_button.dart index d9986be2..6e07ac9a 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_save_floating_button.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_save_floating_button.dart @@ -3,10 +3,10 @@ import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/shared/widgets/circle_button.dart'; class EditorSaveFloatingButton extends StatelessWidget { - final Function onTap; + final Function? onTap; const EditorSaveFloatingButton({ - Key key, + Key? key, this.onTap, }) : super(key: key); @@ -16,7 +16,7 @@ class EditorSaveFloatingButton extends StatelessWidget { return CircleIconButton( key: ValueKey('editableActionBarValidateButton'), - backgroundColor: PalTheme.of(context).colors.color2, + backgroundColor: PalTheme.of(context)!.colors.color2, radius: 40.0, borderSide: BorderSide( color: Colors.white, diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_tool_bar.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_tool_bar.dart index 11fe0bed..232d77c5 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_tool_bar.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_tool_bar.dart @@ -18,23 +18,23 @@ enum ToolBarGlobalActionButton { } class EditorToolBar extends StatelessWidget { - final AnimationController drawerAnimation; - final AnimationController iconsAnimation; + final AnimationController? drawerAnimation; + final AnimationController? iconsAnimation; final bool isTesting; - final List globalActions; - final List editableElementActions; + final List? globalActions; + final List? editableElementActions; - final ValueNotifier isBottomBarVisibleNotifier; + final ValueNotifier? isBottomBarVisibleNotifier; - final Function(ToolBarActionButton) onActionTap; - final Function(ToolBarGlobalActionButton) onGlobalActionTap; + final Function(ToolBarActionButton)? onActionTap; + final Function(ToolBarGlobalActionButton)? onGlobalActionTap; const EditorToolBar({ - Key key, - @required this.globalActions, - @required this.editableElementActions, - @required this.isBottomBarVisibleNotifier, + Key? key, + required this.globalActions, + required this.editableElementActions, + required this.isBottomBarVisibleNotifier, this.drawerAnimation, this.iconsAnimation, this.onActionTap, @@ -45,13 +45,13 @@ class EditorToolBar extends StatelessWidget { @override Widget build(BuildContext context) { return AnimatedBuilder( - animation: this.drawerAnimation, + animation: this.drawerAnimation!, builder: (context, child) => Positioned( bottom: (MediaQuery.of(context).padding.bottom + 10) - ((MediaQuery.of(context).padding.bottom - 10) * - drawerAnimation.value), // * this.drawerAnimation.value, + drawerAnimation!.value), // * this.drawerAnimation.value, right: 30.0, - child: child, + child: child!, ), child: Wrap( direction: Axis.vertical, @@ -62,7 +62,7 @@ class EditorToolBar extends StatelessWidget { // TODO: Create it in parent, then factor to create widget ..._buildSpecificItemActions(context), if (this.editableElementActions != null && - this.editableElementActions.length > 0) + this.editableElementActions!.length > 0) SizedBox( width: 20, child: Divider( @@ -71,7 +71,7 @@ class EditorToolBar extends StatelessWidget { ), ), ..._buildGlobalActions(context), - if (this.globalActions != null && this.globalActions.length > 0) + if (this.globalActions != null && this.globalActions!.length > 0) SizedBox( width: 20, child: Divider( @@ -82,20 +82,20 @@ class EditorToolBar extends StatelessWidget { // /!\ BOTTOM DRAWER ICON /!\ AnimatedBuilder( - animation: this.drawerAnimation, + animation: this.drawerAnimation!, builder: (context, child) => Transform.rotate( - angle: -1.5708 * (cos(pi / 2 * this.drawerAnimation.value)), + angle: -1.5708 * (cos(pi / 2 * this.drawerAnimation!.value)), child: child), child: CircleIconButton.animatedIcon( key: ValueKey('EditorToolBar_Menu'), animatedIcon: AnimatedIcon( icon: AnimatedIcons.arrow_menu, color: Colors.white, - progress: this.drawerAnimation), - backgroundColor: PalTheme.of(context).colors.black, + progress: this.drawerAnimation!), + backgroundColor: PalTheme.of(context)!.colors.black, onTapCallback: () { - this.isBottomBarVisibleNotifier.value = - !this.isBottomBarVisibleNotifier.value; + this.isBottomBarVisibleNotifier!.value = + !this.isBottomBarVisibleNotifier!.value; }, ), ), @@ -106,7 +106,7 @@ class EditorToolBar extends StatelessWidget { List _buildSpecificItemActions(BuildContext context) { List actions = []; - for (final elementAction in this.editableElementActions) { + for (final elementAction in this.editableElementActions!) { IconData iconData; Key key; switch (elementAction) { @@ -139,18 +139,18 @@ class EditorToolBar extends StatelessWidget { } Widget globalActionToAdd = AnimatedBuilder( - animation: this.iconsAnimation, + animation: this.iconsAnimation!, builder: (context, child) => - Transform.scale(scale: this.iconsAnimation.value, child: child), + Transform.scale(scale: this.iconsAnimation!.value, child: child), child: CircleIconButton( key: key, icon: Icon( iconData, color: Colors.white, ), - backgroundColor: PalTheme.of(context).colors.dark, + backgroundColor: PalTheme.of(context)!.colors.dark, onTapCallback: () { - this.onActionTap(elementAction); + this.onActionTap!(elementAction); }, ), ); @@ -162,7 +162,7 @@ class EditorToolBar extends StatelessWidget { List _buildGlobalActions(BuildContext context) { List actions = []; - for (final globalAction in this.globalActions) { + for (final globalAction in this.globalActions!) { IconData iconData; Key key; switch (globalAction) { @@ -179,10 +179,10 @@ class EditorToolBar extends StatelessWidget { key: key, icon: Icon( iconData, - color: PalTheme.of(context).colors.dark, + color: PalTheme.of(context)!.colors.dark, ), - backgroundColor: PalTheme.of(context).colors.light, - onTapCallback: () => this.onGlobalActionTap(globalAction), + backgroundColor: PalTheme.of(context)!.colors.light, + onTapCallback: () => this.onGlobalActionTap!(globalAction), ); actions.add(globalActionToAdd); } diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/color_picker/color_picker.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/color_picker/color_picker.dart index b68f088a..11a37dfc 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/color_picker/color_picker.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/color_picker/color_picker.dart @@ -6,10 +6,10 @@ import 'package:pal/src/extensions/color_extension.dart'; import 'package:pal/src/ui/editor/widgets/bordered_text_field.dart'; class ColorPickerDialog extends StatefulWidget { - final Color placeholderColor; + final Color? placeholderColor; const ColorPickerDialog({ - Key key, + Key? key, this.placeholderColor, }) : super(key: key); @@ -20,8 +20,8 @@ class ColorPickerDialog extends StatefulWidget { class _ColorPickerDialogState extends State { final GlobalKey _formKey = new GlobalKey(); final _hexColorController = TextEditingController(); - Color _selectedColor; - bool _isFormValid = false; + Color? _selectedColor; + bool? _isFormValid = false; @override void initState() { @@ -42,13 +42,13 @@ class _ColorPickerDialogState extends State { autovalidateMode: AutovalidateMode.onUserInteraction, onChanged: () { setState(() { - _isFormValid = _formKey?.currentState?.validate(); + _isFormValid = _formKey.currentState?.validate(); }); }, child: Column( children: [ ColorPicker( - pickerColor: _selectedColor, + pickerColor: _selectedColor!, onColorChanged: (Color selectedColor) { _selectedColor = selectedColor; _hexColorController.text = @@ -62,11 +62,11 @@ class _ColorPickerDialogState extends State { controller: _hexColorController, autovalidate: true, hintText: '#FF4287F5', - validator: (String value) => (!HexColor.isHexColor(value)) + validator: (String? value) => !HexColor.isHexColor(value) ? 'Please enter valid color' : null, onValueChanged: (String newValue) { - Color newColor; + Color? newColor; try { newColor = HexColor.fromHex(newValue); } catch (e) { @@ -102,7 +102,7 @@ class _ColorPickerDialogState extends State { fontWeight: FontWeight.bold, ), ), - onPressed: _isFormValid + onPressed: _isFormValid! ? () { HapticFeedback.selectionClick(); Navigator.pop(context, _selectedColor); diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/dialog_editable_textfield.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/dialog_editable_textfield.dart index 6f427fda..01ddf2be 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/dialog_editable_textfield.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/dialog_editable_textfield.dart @@ -11,7 +11,7 @@ class EditableTextDialog extends StatelessWidget { : this.controller = TextEditingController.fromValue( TextEditingValue( text: initialValue, - selection: TextSelection.fromPosition(TextPosition(offset: initialValue?.length ?? 0)) + selection: TextSelection.fromPosition(TextPosition(offset: initialValue.length)) ) ); diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor.dart index 3e3767cb..2a85641e 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor.dart @@ -16,14 +16,14 @@ typedef OnValidatePicker = void Function(); typedef OnFontModified = Future Function(TextStyle, FontKeys); abstract class FontEditorDialogView { - Future openFontFamilyPicker( + Future openFontFamilyPicker( BuildContext context, - FontKeys fontKeys, + FontKeys? fontKeys, ); - Future> openFontWeightPicker( + Future?> openFontWeightPicker( BuildContext context, - FontKeys fontKeys, + FontKeys? fontKeys, ); TextStyle defaultTextFieldPreviewColor(); @@ -31,19 +31,19 @@ abstract class FontEditorDialogView { class FontEditorDialogPage extends StatelessWidget implements FontEditorDialogView { - final OnCancelPicker onCancelPicker; + final OnCancelPicker? onCancelPicker; - final OnValidatePicker onValidatePicker; + final OnValidatePicker? onValidatePicker; final TextStyle actualTextStyle; - final String fontFamilyKey; + final String? fontFamilyKey; - final OnFontModified onFontModified; + final OnFontModified? onFontModified; FontEditorDialogPage({ - Key key, - @required TextStyle actualTextStyle, + Key? key, + required TextStyle actualTextStyle, this.fontFamilyKey, this.onCancelPicker, this.onFontModified, @@ -114,7 +114,7 @@ class FontEditorDialogPage extends StatelessWidget FontListTile( key: ValueKey('pal_FontEditorDialog_List_FontFamily'), title: 'Font family', - subTitle: model.fontKeys.fontFamilyNameKey, + subTitle: model.fontKeys!.fontFamilyNameKey, onTap: () async { HapticFeedback.selectionClick(); presenter.changeFontFamily(context); @@ -123,7 +123,7 @@ class FontEditorDialogPage extends StatelessWidget FontListTile( key: ValueKey('pal_FontEditorDialog_List_FontWeight'), title: 'Font weight', - subTitle: model.fontKeys.fontWeightNameKey, + subTitle: model.fontKeys!.fontWeightNameKey, onTap: () async { HapticFeedback.selectionClick(); presenter.changeFontWeight(context); @@ -163,7 +163,7 @@ class FontEditorDialogPage extends StatelessWidget Navigator.pop( context, EditedFontModel( - model.fontKeys, model.modifiedTextStyle.fontSize)); + model.fontKeys, model.modifiedTextStyle!.fontSize)); // onValidatePicker(); // if (onFontModified != null) { // await onFontModified( @@ -177,33 +177,33 @@ class FontEditorDialogPage extends StatelessWidget } @override - Future openFontFamilyPicker( + Future openFontFamilyPicker( BuildContext context, - FontKeys fontKeys, + FontKeys? fontKeys, ) async { return await Navigator.pushNamed( context, '/editor/new/font-family', arguments: FontFamilyPickerArguments( - fontFamilyName: fontKeys.fontFamilyNameKey, + fontFamilyName: fontKeys!.fontFamilyNameKey, fontWeightName: fontKeys.fontWeightNameKey, ), - ) as String; + ) as String?; } @override - Future> openFontWeightPicker( + Future?> openFontWeightPicker( BuildContext context, - FontKeys fontKeys, + FontKeys? fontKeys, ) async { return await Navigator.pushNamed( context, '/editor/new/font-weight', arguments: FontWeightPickerArguments( - fontFamilyName: fontKeys.fontFamilyNameKey, + fontFamilyName: fontKeys!.fontFamilyNameKey, fontWeightName: fontKeys.fontWeightNameKey, ), - ) as MapEntry; + ) as MapEntry?; } @override diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor_presenter.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor_presenter.dart index 71f8efc8..28f932fc 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor_presenter.dart @@ -8,11 +8,11 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid class FontEditorDialogPresenter extends Presenter { final TextStyle actualTextStyle; - final String fontFamilyKey; + final String? fontFamilyKey; FontEditorDialogPresenter( FontEditorDialogView viewInterface, { - @required this.actualTextStyle, + required this.actualTextStyle, this.fontFamilyKey, }) : super(FontEditorDialogModel(), viewInterface); @@ -20,32 +20,32 @@ class FontEditorDialogPresenter void onInit() { this.viewModel.modifiedTextStyle = TextStyle().merge(actualTextStyle); this.viewModel.fontKeys = FontKeys( - fontFamilyNameKey: (fontFamilyKey != null && fontFamilyKey.length > 0) ? fontFamilyKey : 'Montserrat', + fontFamilyNameKey: (fontFamilyKey != null && fontFamilyKey!.length > 0) ? fontFamilyKey : 'Montserrat', fontWeightNameKey: FontWeightMapper.toFontKey(actualTextStyle.fontWeight), ); - WidgetsBinding.instance.addPostFrameCallback(afterFirstLayout); + WidgetsBinding.instance!.addPostFrameCallback(afterFirstLayout); } void afterFirstLayout(Duration duration) { // Override color to be always visible! this.viewModel.modifiedTextStyle = this .viewModel - .modifiedTextStyle + .modifiedTextStyle! .merge(this.viewInterface.defaultTextFieldPreviewColor()); this.refreshView(); } void changeFontSize(double fontSize) async { - this.viewModel.modifiedTextStyle = this.viewModel.modifiedTextStyle.merge( + this.viewModel.modifiedTextStyle = this.viewModel.modifiedTextStyle!.merge( TextStyle(fontSize: fontSize), ); this.refreshView(); } void changeFontFamily(BuildContext context) async { - final String fontKey = await this.viewInterface.openFontFamilyPicker( + final String? fontKey = await this.viewInterface.openFontFamilyPicker( context, this.viewModel.fontKeys, ); @@ -53,16 +53,16 @@ class FontEditorDialogPresenter if (fontKey == null) { return; } - this.viewModel.fontKeys.fontFamilyNameKey = fontKey; + this.viewModel.fontKeys!.fontFamilyNameKey = fontKey; this.viewModel.modifiedTextStyle = this .viewModel - .modifiedTextStyle - .merge(GoogleFonts.asMap()[fontKey].call()); + .modifiedTextStyle! + .merge(GoogleFonts.asMap()[fontKey]!.call()); this.refreshView(); } void changeFontWeight(BuildContext context) async { - final MapEntry fontWeightMap = + final MapEntry? fontWeightMap = await this.viewInterface.openFontWeightPicker( context, this.viewModel.fontKeys, @@ -71,8 +71,8 @@ class FontEditorDialogPresenter if (fontWeightMap == null) { return; } - this.viewModel.fontKeys.fontWeightNameKey = fontWeightMap.key; - this.viewModel.modifiedTextStyle = this.viewModel.modifiedTextStyle.merge( + this.viewModel.fontKeys!.fontWeightNameKey = fontWeightMap.key; + this.viewModel.modifiedTextStyle = this.viewModel.modifiedTextStyle!.merge( TextStyle( fontWeight: fontWeightMap.value, ), diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor_viewmodel.dart index 3a1748a9..8ca1610b 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_editor_viewmodel.dart @@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; class FontEditorDialogModel extends MVVMModel { - FontKeys fontKeys; - TextStyle modifiedTextStyle; + FontKeys? fontKeys; + TextStyle? modifiedTextStyle; FontEditorDialogModel({ this.fontKeys, @@ -12,8 +12,8 @@ class FontEditorDialogModel extends MVVMModel { } class FontKeys { - String fontFamilyNameKey; - String fontWeightNameKey; + String? fontFamilyNameKey; + String? fontWeightNameKey; FontKeys({ this.fontFamilyNameKey, @@ -22,8 +22,8 @@ class FontKeys { } class EditedFontModel{ - FontKeys fontKeys; - double size; + FontKeys? fontKeys; + double? size; EditedFontModel(this.fontKeys,this.size); } \ No newline at end of file diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_list_tile.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_list_tile.dart index 146ead0b..fe1c8228 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_list_tile.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_list_tile.dart @@ -3,13 +3,13 @@ import 'package:pal/src/theme.dart'; class FontListTile extends StatelessWidget { final String title; - final String subTitle; - final Function onTap; + final String? subTitle; + final Function? onTap; const FontListTile({ - Key key, - @required this.title, - @required this.subTitle, + Key? key, + required this.title, + required this.subTitle, this.onTap, }) : super(key: key); @@ -18,17 +18,17 @@ class FontListTile extends StatelessWidget { return ListTile( title: Text(title), subtitle: Text( - subTitle, + subTitle!, style: TextStyle( - color: PalTheme.of(context).colors.dark.withAlpha(140), + color: PalTheme.of(context)!.colors.dark!.withAlpha(140), ), ), trailing: Icon( Icons.arrow_forward_ios, size: 15, - color: PalTheme.of(context).colors.dark, + color: PalTheme.of(context)!.colors.dark, ), - onTap: onTap, + onTap: onTap as void Function()?, ); } } diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_size_picker.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_size_picker.dart index 01a0a71b..3b677b36 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_size_picker.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/font_size_picker.dart @@ -4,11 +4,11 @@ import 'package:flutter/widgets.dart'; class FontSizePicker extends StatefulWidget { - final TextStyle style; - final Function(double) onFontSizeSelected; + final TextStyle? style; + final Function(double)? onFontSizeSelected; const FontSizePicker({ - Key key, + Key? key, this.style, this.onFontSizeSelected, }) : super(key: key); @@ -19,13 +19,13 @@ class FontSizePicker extends StatefulWidget { class _FontSizePickerState extends State { - double _currentSliderValue; + late double _currentSliderValue; bool _isHapticPlayed = false; @override void initState() { super.initState(); - _currentSliderValue = widget.style.fontSize ?? 20.0; + _currentSliderValue = widget.style!.fontSize ?? 20.0; } @override @@ -53,7 +53,7 @@ class _FontSizePickerState extends State { setState(() { _currentSliderValue = value; }); - widget.onFontSizeSelected(value); + widget.onFontSizeSelected!(value); }, ), ], diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker.dart index 93dfcc1d..cbbbdde9 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker.dart @@ -7,12 +7,12 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_viewmodel.dart'; class FontFamilyPickerArguments { - String fontFamilyName; - String fontWeightName; + String? fontFamilyName; + String? fontWeightName; FontFamilyPickerArguments({ - @required this.fontFamilyName, - @required this.fontWeightName, + required this.fontFamilyName, + required this.fontWeightName, }); } @@ -21,13 +21,13 @@ abstract class FontFamilyPickerView {} /// Use this picker with FontEditor dialog only class FontFamilyPickerPage extends StatelessWidget implements FontFamilyPickerView { - final FontFamilyPickerArguments arguments; - final FontFamilyPickerLoader loader; + final FontFamilyPickerArguments? arguments; + final FontFamilyPickerLoader? loader; FontFamilyPickerPage({ - Key key, + Key? key, this.loader, - @required this.arguments, + required this.arguments, }); final _mvvmPageBuilder = @@ -85,13 +85,13 @@ class FontFamilyPickerPage extends StatelessWidget ), ), Expanded( - child: !model.isLoading + child: !model.isLoading! ? ListView.builder( key: ValueKey('pal_FontFamilyPicker_ListView'), shrinkWrap: true, - itemCount: model.fonts.length, + itemCount: model.fonts!.length, itemBuilder: (context, index) { - final String key = model.fonts[index]; + final String key = model.fonts![index]; TextStyle originalFontStyle = GoogleFonts.getFont(key); TextStyle modifiedFontStyle = originalFontStyle.merge( @@ -110,7 +110,7 @@ class FontFamilyPickerPage extends StatelessWidget Icons.check, key: ValueKey( 'pal_FontFamilyPicker_ListView_ListTile_Check$index'), - color: PalTheme.of(context).colors.dark, + color: PalTheme.of(context)!.colors.dark, ) : null, onTap: () { @@ -126,12 +126,12 @@ class FontFamilyPickerPage extends StatelessWidget child: CircularProgressIndicator(), ), ), - if (!model.isLoading) + if (!model.isLoading!) Padding( key: ValueKey('pal_FontFamilyPicker_ResultsLabel'), padding: const EdgeInsets.only(bottom: 20.0, top: 20.0), child: Text( - '${model.fonts.length.toString()} ${(model.fonts.length <= 1 ? 'result' : 'results')}', + '${model.fonts!.length.toString()} ${(model.fonts!.length <= 1 ? 'result' : 'results')}', ), ), ], diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_loader.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_loader.dart index f7cab82b..e92d803f 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_loader.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_loader.dart @@ -18,7 +18,7 @@ class FontFamilyPickerLoader { // Create font textstyles map in background (other isolate) viewModel.originalFonts = await compute(fontKeysConverter, 0); - viewModel.fonts = List.from(viewModel.originalFonts); + viewModel.fonts = List.from(viewModel.originalFonts!); return viewModel; } diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_presenter.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_presenter.dart index aaf35ec7..6fff9dcc 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_presenter.dart @@ -6,7 +6,7 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid class FontFamilyPickerPresenter extends Presenter { final FontFamilyPickerLoader loader; - final FontFamilyPickerArguments arguments; + final FontFamilyPickerArguments? arguments; FontFamilyPickerPresenter( FontFamilyPickerView viewInterface, @@ -19,7 +19,7 @@ class FontFamilyPickerPresenter this.viewModel.originalFonts = []; this.viewModel.fonts = []; this.viewModel.isLoading = false; - this.viewModel.selectedFontFamilyKey = arguments.fontFamilyName; + this.viewModel.selectedFontFamilyKey = arguments!.fontFamilyName; this.setup(); } @@ -39,7 +39,7 @@ class FontFamilyPickerPresenter void filterSearchResults(String query) { if (query.isNotEmpty) { List dummyListData = []; - this.viewModel.originalFonts.forEach((fontKey) { + this.viewModel.originalFonts!.forEach((fontKey) { final lowerQuery = query.toLowerCase(); final lowerFontName = fontKey.toLowerCase(); @@ -47,11 +47,11 @@ class FontFamilyPickerPresenter dummyListData.add(fontKey); } }); - this.viewModel.fonts.clear(); - this.viewModel.fonts.addAll(dummyListData); + this.viewModel.fonts!.clear(); + this.viewModel.fonts!.addAll(dummyListData); } else { - this.viewModel.fonts.clear(); - this.viewModel.fonts.addAll(this.viewModel.originalFonts); + this.viewModel.fonts!.clear(); + this.viewModel.fonts!.addAll(this.viewModel.originalFonts!); } this.refreshView(); diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_viewmodel.dart index 1b7fdd8c..f7b296e0 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_viewmodel.dart @@ -1,10 +1,10 @@ import 'package:mvvm_builder/mvvm_builder.dart'; class FontFamilyPickerModel extends MVVMModel { - List fonts; - List originalFonts; - bool isLoading; - String selectedFontFamilyKey; + List? fonts; + List? originalFonts; + bool? isLoading; + String? selectedFontFamilyKey; FontFamilyPickerModel({ this.fonts, diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker.dart index ce712925..6959bde1 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker.dart @@ -6,12 +6,12 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_viewmodel.dart'; class FontWeightPickerArguments { - String fontFamilyName; - String fontWeightName; + String? fontFamilyName; + String? fontWeightName; FontWeightPickerArguments({ - @required this.fontFamilyName, - @required this.fontWeightName, + required this.fontFamilyName, + required this.fontWeightName, }); } @@ -20,11 +20,11 @@ abstract class FontWeightPickerView {} /// Use this picker with FontEditor dialog only class FontWeightPickerPage extends StatelessWidget implements FontWeightPickerView { - final FontWeightPickerArguments arguments; + final FontWeightPickerArguments? arguments; FontWeightPickerPage({ - Key key, - @required this.arguments, + Key? key, + required this.arguments, }); final _mvvmPageBuilder = @@ -59,12 +59,12 @@ class FontWeightPickerPage extends StatelessWidget return ListView.builder( key: ValueKey('pal_FontWeightPicker_ListView'), shrinkWrap: true, - itemCount: model.fontWeights.length, + itemCount: model.fontWeights!.length, itemBuilder: (context, index) { - final map = model.fontWeights.entries.elementAt(index); + final map = model.fontWeights!.entries.elementAt(index); TextStyle originalFontStyle = - GoogleFonts.getFont(arguments.fontFamilyName); + GoogleFonts.getFont(arguments!.fontFamilyName!); TextStyle modifiedFontStyle = originalFontStyle.merge( TextStyle( fontSize: 23.0, @@ -82,7 +82,7 @@ class FontWeightPickerPage extends StatelessWidget ? Icon( Icons.check, key: ValueKey('pal_FontWeightPicker_ListView_ListTile_Check$index'), - color: PalTheme.of(context).colors.dark, + color: PalTheme.of(context)!.colors.dark, ) : null, onTap: () { diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_loader.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_loader.dart index b92a2703..ed82b774 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_loader.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_loader.dart @@ -13,12 +13,12 @@ class FontWeightMapper { 'Black': FontWeight.w900, }; - static String toFontKey(FontWeight fontWeight) { + static String? toFontKey(FontWeight? fontWeight) { if (fontWeight == null) { return 'Normal'; } - String key; + String? key; for (var entry in map.entries) { if (fontWeight == entry.value) { key = entry.key; @@ -28,7 +28,7 @@ class FontWeightMapper { return key; } - static FontWeight toFontWeight(String key) { - return map[key]; + static FontWeight? toFontWeight(String? key) { + return map[key!]; } } diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_presenter.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_presenter.dart index 457f2f8f..9243cbd8 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_presenter.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_presenter.dart @@ -6,7 +6,7 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid class FontWeightPickerPresenter extends Presenter { - final FontWeightPickerArguments arguments; + final FontWeightPickerArguments? arguments; FontWeightPickerPresenter( FontWeightPickerView viewInterface, @@ -16,7 +16,7 @@ class FontWeightPickerPresenter @override void onInit() { this.viewModel.fontWeights = FontWeightMapper.map; - this.viewModel.selectedFontWeightKey = arguments.fontWeightName; + this.viewModel.selectedFontWeightKey = arguments!.fontWeightName; // print(this.viewModel.selectedFontWeightKey); } } diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_viewmodel.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_viewmodel.dart index a0e128f3..0177eded 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_viewmodel.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_viewmodel.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; class FontWeightPickerModel extends MVVMModel { - Map fontWeights; - String selectedFontWeightKey; + Map? fontWeights; + String? selectedFontWeightKey; FontWeightPickerModel({ this.fontWeights, diff --git a/lib/src/ui/editor/pages/helper_editor/widgets/editor_tutorial.dart b/lib/src/ui/editor/pages/helper_editor/widgets/editor_tutorial.dart index 77a0388f..cd2a8ca7 100644 --- a/lib/src/ui/editor/pages/helper_editor/widgets/editor_tutorial.dart +++ b/lib/src/ui/editor/pages/helper_editor/widgets/editor_tutorial.dart @@ -8,10 +8,10 @@ class EditorTutorialOverlay extends StatefulWidget { final Function onPressDismiss; const EditorTutorialOverlay( - {Key key, - @required this.title, - @required this.content, - @required this.onPressDismiss}) + {Key? key, + required this.title, + required this.content, + required this.onPressDismiss}) : super(key: key); @override @@ -20,11 +20,11 @@ class EditorTutorialOverlay extends StatefulWidget { class _EditorTutorialOverlayState extends State with SingleTickerProviderStateMixin { - AnimationController fadeAnimController; - Animation backgroundSizeAnimation; - Animation titleOpacityAnimation, titleSizeAnimation; - Animation contentOpacityAnimation, contentSizeAnimation; - Animation buttonOpacityAnimation, buttonSizeAnimation; + late AnimationController fadeAnimController; + late Animation backgroundSizeAnimation; + Animation? titleOpacityAnimation, titleSizeAnimation; + Animation? contentOpacityAnimation, contentSizeAnimation; + Animation? buttonOpacityAnimation, buttonSizeAnimation; @override void didChangeDependencies() { @@ -208,7 +208,7 @@ class _EditorTutorialOverlayState extends State ), onPressed: () { HapticFeedback.selectionClick(); - widget.onPressDismiss?.call(); + widget.onPressDismiss.call(); }, borderSide: BorderSide( color: Colors.white, diff --git a/lib/src/ui/editor/pages/media_gallery/media_gallery.dart b/lib/src/ui/editor/pages/media_gallery/media_gallery.dart index 45aa931c..09d3bf2a 100644 --- a/lib/src/ui/editor/pages/media_gallery/media_gallery.dart +++ b/lib/src/ui/editor/pages/media_gallery/media_gallery.dart @@ -10,7 +10,7 @@ import 'media_gallery_presenter.dart'; import 'media_gallery_viewmodel.dart'; class MediaGalleryPageArguments { - final String mediaId; + final String? mediaId; MediaGalleryPageArguments( this.mediaId, @@ -22,11 +22,11 @@ abstract class MediaGalleryView { } class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { - final String mediaId; - final MediaGalleryLoader loader; + final String? mediaId; + final MediaGalleryLoader? loader; MediaGalleryPage({ - Key key, + Key? key, this.mediaId, this.loader, }); @@ -45,7 +45,7 @@ class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { this, loader: this.loader ?? MediaGalleryLoader( - EditorInjector.of(context).projectGalleryRepository, + EditorInjector.of(context)!.projectGalleryRepository, ), mediaId: mediaId, ), @@ -61,13 +61,13 @@ class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { title: Text( 'My image gallery', style: TextStyle( - color: PalTheme.of(context.buildContext).colors.dark, + color: PalTheme.of(context.buildContext)!.colors.dark, ), ), iconTheme: IconThemeData( - color: PalTheme.of(context.buildContext).colors.dark, + color: PalTheme.of(context.buildContext)!.colors.dark, ), - backgroundColor: PalTheme.of(context.buildContext).colors.light, + backgroundColor: PalTheme.of(context.buildContext)!.colors.light, ), body: this._buildPage(context.buildContext, presenter, model), ), @@ -85,7 +85,7 @@ class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { children: [ Container( key: ValueKey('pal_MediaGalleryPage_Header'), - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1, child: Padding( padding: const EdgeInsets.all(16.0), child: Text( @@ -98,7 +98,7 @@ class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { ), ), Expanded( - child: (model.isLoading) + child: model.isLoading! ? Center(child: CircularProgressIndicator()) : GridView.builder( key: ValueKey('pal_MediaGalleryPage_Body_Grid'), @@ -117,7 +117,7 @@ class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { ), padding: const EdgeInsets.all(2.0), itemBuilder: (context, index) { - GraphicEntity media = model.medias[index]; + GraphicEntity media = model.medias![index]; return MediaCellWidget( // FIXME: Int or String ?? id: media.id.toString(), @@ -126,7 +126,7 @@ class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { onTap: () => presenter.selectMedia(media), ); }, - itemCount: model.medias.length, + itemCount: model.medias!.length, ), ), Padding( @@ -154,14 +154,14 @@ class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { width: double.infinity, child: RaisedButton( key: ValueKey('pal_MediaGalleryPage_SelectButton'), - disabledColor: PalTheme.of(context).colors.color4, + disabledColor: PalTheme.of(context)!.colors.color4, child: Text( 'Select', style: TextStyle( color: Colors.white, ), ), - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1, onPressed: () => this.popBackToEditor(model.selectedMedia), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), @@ -171,7 +171,7 @@ class MediaGalleryPage extends StatelessWidget implements MediaGalleryView { } @override - void popBackToEditor(final GraphicEntity media) { - Navigator.pop(this._scaffoldKey.currentContext, media); + void popBackToEditor(final GraphicEntity? media) { + Navigator.pop(this._scaffoldKey.currentContext!, media); } } diff --git a/lib/src/ui/editor/pages/media_gallery/media_gallery_loader.dart b/lib/src/ui/editor/pages/media_gallery/media_gallery_loader.dart index 93bdf8d9..446555d3 100644 --- a/lib/src/ui/editor/pages/media_gallery/media_gallery_loader.dart +++ b/lib/src/ui/editor/pages/media_gallery/media_gallery_loader.dart @@ -7,7 +7,7 @@ import 'media_gallery_viewmodel.dart'; class MediaGalleryLoader { final ProjectGalleryEditorService _projectGalleryEditorService; final _mediasOffset = 30; - Pageable _pageable; + Pageable? _pageable; MediaGalleryLoader( this._projectGalleryEditorService, @@ -22,18 +22,16 @@ class MediaGalleryLoader { } Future> loadMore() { - return _pageable != null && _pageable.last + return _pageable != null && _pageable!.last! ? Future.value([]) - : this - ._projectGalleryEditorService + : _projectGalleryEditorService .getAllMedias( - _pageable == null ? 0 : ++_pageable.pageNumber, + _pageable == null ? 0 : _pageable!.pageNumber!, _mediasOffset, ) - .then( - (res) { + .then((res) { _pageable = res; - return this._pageable.entities.toList(); + return this._pageable!.entities!.toList(); }, ); } diff --git a/lib/src/ui/editor/pages/media_gallery/media_gallery_presenter.dart b/lib/src/ui/editor/pages/media_gallery/media_gallery_presenter.dart index c539a475..28fe48d4 100644 --- a/lib/src/ui/editor/pages/media_gallery/media_gallery_presenter.dart +++ b/lib/src/ui/editor/pages/media_gallery/media_gallery_presenter.dart @@ -1,4 +1,3 @@ -import 'package:flutter/widgets.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; import 'package:pal/src/database/entity/graphic_entity.dart'; import 'package:pal/src/ui/editor/pages/media_gallery/media_gallery_loader.dart'; @@ -8,13 +7,13 @@ import 'media_gallery_viewmodel.dart'; class MediaGalleryPresenter extends Presenter { - final String mediaId; + final String? mediaId; final MediaGalleryLoader loader; MediaGalleryPresenter( MediaGalleryView viewInterface, { this.mediaId, - @required this.loader, + required this.loader, }) : super(MediaGalleryModel(), viewInterface); @override @@ -26,7 +25,7 @@ class MediaGalleryPresenter this.loader.load().then((MediaGalleryModel res) { this.viewModel.medias = res.medias; this.viewModel.isLoading = false; - for (var media in res.medias) { + for (var media in res.medias!) { if(media.id == mediaId){ this.selectMedia(media); break; @@ -37,7 +36,7 @@ class MediaGalleryPresenter } void loadMore() { - if (!this.viewModel.isNoMore && !this.viewModel.isLoadingMore) { + if (!this.viewModel.isNoMore! && !this.viewModel.isLoadingMore!) { this.viewModel.isLoadingMore = true; this.refreshView(); @@ -45,7 +44,7 @@ class MediaGalleryPresenter if (value.isEmpty) { this.viewModel.isNoMore = true; } else { - this.viewModel.medias.addAll(value); + this.viewModel.medias!.addAll(value); } this.viewModel.isLoadingMore = false; this.refreshView(); diff --git a/lib/src/ui/editor/pages/media_gallery/media_gallery_viewmodel.dart b/lib/src/ui/editor/pages/media_gallery/media_gallery_viewmodel.dart index 1a58fc96..f377688c 100644 --- a/lib/src/ui/editor/pages/media_gallery/media_gallery_viewmodel.dart +++ b/lib/src/ui/editor/pages/media_gallery/media_gallery_viewmodel.dart @@ -2,11 +2,11 @@ import 'package:mvvm_builder/mvvm_builder.dart'; import 'package:pal/src/database/entity/graphic_entity.dart'; class MediaGalleryModel extends MVVMModel { - List medias; - bool isLoading; - bool isLoadingMore; - bool isNoMore; - GraphicEntity selectedMedia; + List? medias; + bool? isLoading; + bool? isLoadingMore; + bool? isNoMore; + GraphicEntity? selectedMedia; MediaGalleryModel({ this.medias, diff --git a/lib/src/ui/editor/pages/media_gallery/widgets/media_cell_widget.dart b/lib/src/ui/editor/pages/media_gallery/widgets/media_cell_widget.dart index 6eccc482..ba461d3d 100644 --- a/lib/src/ui/editor/pages/media_gallery/widgets/media_cell_widget.dart +++ b/lib/src/ui/editor/pages/media_gallery/widgets/media_cell_widget.dart @@ -6,14 +6,14 @@ import 'package:pal/src/theme.dart'; class MediaCellWidget extends StatefulWidget { final String id; - final String url; + final String? url; final bool isSelected; - final Function() onTap; + final Function()? onTap; MediaCellWidget({ - Key key, - @required this.id, - @required this.url, + Key? key, + required this.id, + required this.url, this.isSelected = false, this.onTap, }) : super(key: key); @@ -24,8 +24,8 @@ class MediaCellWidget extends StatefulWidget { class _MediaCellWidgetState extends State with SingleTickerProviderStateMixin { - AnimationController _animationController; - double _scale; + AnimationController? _animationController; + late double _scale; Duration _duration = Duration(milliseconds: 100); @override @@ -49,7 +49,7 @@ class _MediaCellWidgetState extends State @override Widget build(BuildContext context) { - _scale = 1 - _animationController.value; + _scale = 1 - _animationController!.value; return GestureDetector( key: ValueKey('pal_MediaCellWidget_${widget.id}'), @@ -61,16 +61,16 @@ class _MediaCellWidgetState extends State child: Stack( children: [ CachedNetworkImage( - imageUrl: widget.url, + imageUrl: widget.url!, placeholder: (context, url) => Center(child: CircularProgressIndicator()), errorWidget: (context, url, error) => Center(child: Icon(Icons.error)), ), Container( decoration: BoxDecoration( - image: DecorationImage(image: CachedNetworkImageProvider(widget.url), + image: DecorationImage(image: CachedNetworkImageProvider(widget.url!), fit: BoxFit.cover), border: Border.all( - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1!, width: 6.0, style: (widget.isSelected) ? BorderStyle.solid @@ -95,7 +95,7 @@ class _MediaCellWidgetState extends State borderRadius: BorderRadius.only( bottomLeft: const Radius.circular(10.0), ), - color: PalTheme.of(context).colors.color1, + color: PalTheme.of(context)!.colors.color1, ), child: Center( child: Icon( @@ -110,18 +110,18 @@ class _MediaCellWidgetState extends State } _onTapDown(TapDownDetails details) { - _animationController.forward(); + _animationController!.forward(); HapticFeedback.selectionClick(); } _onTapUp(TapUpDetails details) { Future.delayed(_duration, () { - _animationController.reverse(); + _animationController!.reverse(); }); - widget.onTap(); + widget.onTap!(); } _onTapCancel() { - _animationController.reverse(); + _animationController!.reverse(); } } diff --git a/lib/src/ui/editor/pages/page_groups/page_group_list.dart b/lib/src/ui/editor/pages/page_groups/page_group_list.dart index 412d255a..4196779e 100644 --- a/lib/src/ui/editor/pages/page_groups/page_group_list.dart +++ b/lib/src/ui/editor/pages/page_groups/page_group_list.dart @@ -15,7 +15,7 @@ import 'widgets/create_helper_button.dart'; abstract class PageGroupsListView { Future closePage(); - Future navigateCreateHelper(final String pageId); + Future navigateCreateHelper(final String? pageId); void changeBubbleState(bool state); @@ -30,7 +30,7 @@ class PageGroupsListPage extends StatelessWidget { return MVVMPage( key: ValueKey('presenter'), presenter: PageGroupsListPresenter( - editorInjector: EditorInjector.of(context), + editorInjector: EditorInjector.of(context)!, viewInterface: _viewInterface..context = context, navigatorObserver: PalNavigatorObserver.instance(), ), @@ -55,7 +55,7 @@ class PageGroupsListPage extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Text("List of available helper groups on this page", style: - _descrTextStyle(PalTheme.of(context.buildContext))), + _descrTextStyle(PalTheme.of(context.buildContext)!)), ), SizedBox(height: 12), Padding( @@ -71,7 +71,7 @@ class PageGroupsListPage extends StatelessWidget { : _buildItemList(presenter, model), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: _buildCloseButton(PalTheme.of(context.buildContext), + child: _buildCloseButton(PalTheme.of(context.buildContext)!, presenter.onClickClose), ) ], @@ -97,19 +97,21 @@ class PageGroupsListPage extends StatelessWidget { TextSpan( text: 'PAL', style: TextStyle( - fontSize: 26, color: PalTheme.of(context).colors.dark)), + fontSize: 26, color: PalTheme.of(context)!.colors.dark)), TextSpan( text: '\nEDITOR', style: TextStyle( - fontSize: 10, color: PalTheme.of(context).colors.dark)), + fontSize: 10, color: PalTheme.of(context)!.colors.dark)), ]), ), ), - _buildCircleButton( - 'pal_HelpersListModal_Settings', - Icon(Icons.settings, size: 24), - presenter.onClickSettings, - ), + // currently disabled because not supported for desktop & web for now + // https://github.com/ueman/application_icon/issues/9 + // _buildCircleButton( + // 'pal_HelpersListModal_Settings', + // Icon(Icons.settings, size: 24), + // presenter.onClickSettings, + // ), ], ); @@ -118,7 +120,7 @@ class PageGroupsListPage extends StatelessWidget { return Expanded( child: Center( child: Text( - model.errorMessage, + model.errorMessage!, key: ValueKey("ErrorMessage"), ))); } @@ -136,8 +138,8 @@ class PageGroupsListPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 24), - Text(model.groups.keys.elementAt(index).toText(), - style: _triggerTypetextStyle(PalTheme.of(context))), + Text(model.groups.keys.elementAt(index).toText()!, + style: _triggerTypetextStyle(PalTheme.of(context)!)), SizedBox(height: 8), ListView.separated( physics: const NeverScrollableScrollPhysics(), @@ -145,10 +147,10 @@ class PageGroupsListPage extends StatelessWidget { SizedBox(height: 8), shrinkWrap: true, itemCount: model - .groups[model.groups.keys.elementAt(index)].length, + .groups[model.groups.keys.elementAt(index)]!.length, itemBuilder: (context2, itemIndex) { GroupItemViewModel item = - model.groups[model.groups.keys.elementAt(index)] + model.groups[model.groups.keys.elementAt(index)]! [itemIndex]; return InkWell( onTap: () { @@ -183,7 +185,7 @@ class PageGroupsListPage extends StatelessWidget { child: FloatingActionButton( heroTag: key, key: ValueKey(key), - onPressed: callback, + onPressed: callback as void Function()?, child: icon, shape: CircleBorder(), ), @@ -201,8 +203,8 @@ class PageGroupsListPage extends StatelessWidget { color: palThemeData.colors.dark, ), ), - onPressed: onClose, - borderSide: BorderSide(color: palThemeData.colors.dark, width: 1), + onPressed: onClose as void Function()?, + borderSide: BorderSide(color: palThemeData.colors.dark!, width: 1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -223,39 +225,39 @@ class PageGroupsListPage extends StatelessWidget { } class _PageGroupsListView implements PageGroupsListView { - BuildContext context; + late BuildContext context; GlobalKey overlayedPageState = GlobalKey(); @override Future closePage() async { HapticFeedback.selectionClick(); - await overlayedPageState.currentState.closePage(); + await overlayedPageState.currentState!.closePage(); Navigator.of(context).pop(); } @override - Future navigateCreateHelper(final String pageId) async { + Future navigateCreateHelper(final String? pageId) async { HapticFeedback.selectionClick(); // Display the helper creation view final shouldOpenEditor = await Navigator.pushNamed( - EditorInjector.of(context).palNavigatorKey.currentContext, + EditorInjector.of(context)!.palNavigatorKey!.currentContext!, '/editor/new', arguments: CreateHelperPageArguments( - EditorInjector.of(context).hostedAppNavigatorKey, + EditorInjector.of(context)!.hostedAppNavigatorKey, pageId, ), ); - if (shouldOpenEditor != null && shouldOpenEditor) { + if (shouldOpenEditor != null && shouldOpenEditor as bool) { // Dismiss the bottom modal when next was tapped Navigator.pop(context); } - return shouldOpenEditor; + return shouldOpenEditor as Future; } @override void changeBubbleState(bool state) { - EditorInjector.of(context).palEditModeStateService.showBubble( - EditorInjector.of(context).hostedAppNavigatorKey.currentContext, state); + EditorInjector.of(context)!.palEditModeStateService.showBubble( + EditorInjector.of(context)!.hostedAppNavigatorKey!.currentContext, state); Navigator.pop(context); } diff --git a/lib/src/ui/editor/pages/page_groups/page_group_list_model.dart b/lib/src/ui/editor/pages/page_groups/page_group_list_model.dart index 679eab96..6559aa89 100644 --- a/lib/src/ui/editor/pages/page_groups/page_group_list_model.dart +++ b/lib/src/ui/editor/pages/page_groups/page_group_list_model.dart @@ -4,16 +4,16 @@ import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; class PageGroupsListViewModel extends MVVMModel { // list of groups per trigger type - Map> groups; + late Map> groups; - bool isLoading; + bool? isLoading; - String errorMessage; - String route; + String? errorMessage; + String? route; } class GroupItemViewModel { - final String title, date, version, id; + final String? title, date, version, id; GroupItemViewModel(this.title, this.date, this.version, this.id); } @@ -25,6 +25,6 @@ const HelperTriggerTypeStrings = { // "RANDOM_TIPS":"Random tips", }; -extension HelperTriggerTypeText on HelperTriggerType { - String toText() => HelperTriggerTypeStrings[this]; +extension HelperTriggerTypeText on HelperTriggerType? { + String? toText() => HelperTriggerTypeStrings[this!]; } \ No newline at end of file diff --git a/lib/src/ui/editor/pages/page_groups/page_group_list_presenter.dart b/lib/src/ui/editor/pages/page_groups/page_group_list_presenter.dart index 7e7fd088..4a16b6c1 100644 --- a/lib/src/ui/editor/pages/page_groups/page_group_list_presenter.dart +++ b/lib/src/ui/editor/pages/page_groups/page_group_list_presenter.dart @@ -11,17 +11,17 @@ import 'page_group_list_model.dart'; /// [PageGroupsListPresenter] /// business logic for page group list class PageGroupsListPresenter - extends Presenter { + extends Presenter { final EditorHelperGroupService helperGroupService; - final PalNavigatorObserver navigatorObserver; + final PalNavigatorObserver? navigatorObserver; final PageEditorService pageService; // PAGE STATE - String pageId; + String? pageId; PageGroupsListPresenter({ - EditorInjector editorInjector, - PageGroupsListView viewInterface, + required EditorInjector editorInjector, + PageGroupsListView? viewInterface, this.navigatorObserver, }) : this.helperGroupService = editorInjector.helperGroupService, this.pageService = editorInjector.pageEditorService, @@ -33,56 +33,52 @@ class PageGroupsListPresenter viewModel.isLoading = true; this.refreshView(); viewModel.errorMessage = null; - RouteSettings route = await navigatorObserver.routeSettings.first; + RouteSettings route = await navigatorObserver!.routeSettings.first; this.viewModel.route = route.name; // TODO show current page route path - this.pageService.getOrCreatePageId(route.name).catchError((err) { + try { + this.pageId = await this.pageService.getOrCreatePageId(route.name); + var groupsEntities = await helperGroupService.getPageGroups(pageId); + if (viewModel.errorMessage != null) return;// + if (viewModel.groups.isNotEmpty) viewModel.groups.clear(); + groupsEntities.forEach((element) { + if (!viewModel.groups.containsKey(element.triggerType)) { + viewModel.groups.putIfAbsent(element.triggerType, () => []); + } + viewModel.groups[element.triggerType]!.add(GroupItemViewModel( + element.name, + _formatDate(element.creationDate!), + _formatVersion(element.minVersion, element.maxVersion), + element.id)); + }); + viewModel.isLoading = false; + refreshView(); + } catch(err, stack) { viewModel.errorMessage = "Server error while loading data..."; + debugPrintStack(stackTrace: stack); viewModel.isLoading = false; refreshView(); - }).then((id) { - this.pageId = id; - helperGroupService.getPageGroups(id).catchError((err) { - viewModel.errorMessage = "Server error while loading data..."; - viewModel.isLoading = false; - refreshView(); - }).then((groupsEntities) { - if (viewModel.errorMessage != null) return; - if (viewModel.groups.isNotEmpty) viewModel.groups.clear(); - groupsEntities.forEach((element) { - if (!viewModel.groups.containsKey(element.triggerType)) { - viewModel.groups.putIfAbsent(element.triggerType, () => []); - } - viewModel.groups[element.triggerType].add(GroupItemViewModel( - element.name, - _formatDate(element.creationDate), - _formatVersion(element.minVersion, element.maxVersion), - element.id)); - }); - viewModel.isLoading = false; - refreshView(); - }); - }); + } } void onClickClose() { - this.viewInterface.changeBubbleState(true); - viewInterface.closePage(); + this.viewInterface!.changeBubbleState(true); + viewInterface!.closePage(); } Future onClickAddHelper() async { - if (!this.viewModel.isLoading) { - viewInterface.navigateCreateHelper(this.pageId); + if (!this.viewModel.isLoading!) { + viewInterface!.navigateCreateHelper(this.pageId); } } String _formatDate(DateTime date) => "Created on ${date.day}/${date.month}/${date.year}"; - String _formatVersion(String minVersion, String maxVersion) => + String _formatVersion(String? minVersion, String? maxVersion) => "$minVersion - ${maxVersion ?? 'last'}"; Future onClickSettings() { - return this.viewInterface.openAppSettingsPage(); + return this.viewInterface!.openAppSettingsPage(); } } diff --git a/lib/src/ui/editor/pages/page_groups/widgets/create_helper_button.dart b/lib/src/ui/editor/pages/page_groups/widgets/create_helper_button.dart index cc9c81d4..46f135db 100644 --- a/lib/src/ui/editor/pages/page_groups/widgets/create_helper_button.dart +++ b/lib/src/ui/editor/pages/page_groups/widgets/create_helper_button.dart @@ -3,10 +3,10 @@ import 'package:flutter/material.dart'; import '../../../../../theme.dart'; class CreateHelperButton extends StatefulWidget { - final PalThemeData palTheme; - final Function onTap; + final PalThemeData? palTheme; + final Function? onTap; - CreateHelperButton({this.palTheme, this.onTap, Key key}) : super(key: key); + CreateHelperButton({this.palTheme, this.onTap, Key? key}) : super(key: key); @override _CreateHelperButtonState createState() => _CreateHelperButtonState(); @@ -27,7 +27,7 @@ class _CreateHelperButtonState extends State { ) ]), child: Material( - color: PalTheme.of(context).colors.color4, + color: PalTheme.of(context)!.colors.color4, child: InkWell( onTap: _onTap, child: Padding( @@ -53,18 +53,18 @@ class _CreateHelperButtonState extends State { ); void _onTap() { - if (widget.onTap != null) widget.onTap(); + if (widget.onTap != null) widget.onTap!(); } TextStyle get _textStyle1 => TextStyle( fontSize: 18, fontWeight: FontWeight.w400, - color: widget.palTheme.colors.dark, + color: widget.palTheme!.colors.dark, ); TextStyle get _textStyle2 => TextStyle( fontSize: 12, fontWeight: FontWeight.w300, - color: widget.palTheme.colors.dark, + color: widget.palTheme!.colors.dark, ); } diff --git a/lib/src/ui/editor/pages/page_groups/widgets/page_group_list_item.dart b/lib/src/ui/editor/pages/page_groups/widgets/page_group_list_item.dart index 86d8bd32..698cc57d 100644 --- a/lib/src/ui/editor/pages/page_groups/widgets/page_group_list_item.dart +++ b/lib/src/ui/editor/pages/page_groups/widgets/page_group_list_item.dart @@ -3,15 +3,15 @@ import 'package:pal/src/theme.dart'; class PageGroupsListItem extends StatelessWidget { - final String title, subtitle, version; - final PalThemeData palTheme; + final String? title, subtitle, version; + final PalThemeData? palTheme; PageGroupsListItem({ - @required this.title, - @required this.subtitle, - @required this.version, - @required this.palTheme, - Key key + required this.title, + required this.subtitle, + required this.version, + required this.palTheme, + Key? key }) : super(key: key); @override @@ -36,15 +36,15 @@ class PageGroupsListItem extends StatelessWidget { RichText(text: TextSpan( style: TextStyle(height: 1.5), children: [ - TextSpan(text: "$title" ?? "\nNo title found", style: _textStyle1), - TextSpan(text: "\n$subtitle" ?? "\nNo subtitle found", style: _textStyle2), + TextSpan(text: "$title", style: _textStyle1), + TextSpan(text: "\n$subtitle", style: _textStyle2), ] )), RichText(text: TextSpan( style: TextStyle(height: 1.4), children: [ TextSpan(text: "Versions", style: _textStyle3), - TextSpan(text: "\n$version" ?? "\n--", style: _textStyle2), + TextSpan(text: "\n$version", style: _textStyle2), ] )) ], @@ -55,19 +55,19 @@ class PageGroupsListItem extends StatelessWidget { TextStyle get _textStyle1 => TextStyle( fontSize: 18, fontWeight: FontWeight.w400, - color: palTheme.colors.dark, + color: palTheme!.colors.dark, ); TextStyle get _textStyle2 => TextStyle( fontSize: 12, fontWeight: FontWeight.w300, - color: palTheme.colors.dark, + color: palTheme!.colors.dark, ); TextStyle get _textStyle3 => TextStyle( fontSize: 12, fontWeight: FontWeight.bold, - color: palTheme.colors.dark, + color: palTheme!.colors.dark, ); diff --git a/lib/src/ui/editor/pages/page_groups/widgets/page_overlay.dart b/lib/src/ui/editor/pages/page_groups/widgets/page_overlay.dart index e852d31a..f4974627 100644 --- a/lib/src/ui/editor/pages/page_groups/widgets/page_overlay.dart +++ b/lib/src/ui/editor/pages/page_groups/widgets/page_overlay.dart @@ -4,9 +4,9 @@ import 'package:pal/src/theme.dart'; class PartialOverlayedPage extends StatefulWidget { - final Widget child; + final Widget? child; - PartialOverlayedPage({this.child, Key key}) : super(key: key); + PartialOverlayedPage({this.child, Key? key}) : super(key: key); @override PartialOverlayedPageState createState() => PartialOverlayedPageState(); @@ -14,8 +14,8 @@ class PartialOverlayedPage extends StatefulWidget { class PartialOverlayedPageState extends State with SingleTickerProviderStateMixin { - AnimationController fadeAnimController; - Animation backgroundSizeAnimation; + late AnimationController fadeAnimController; + late Animation backgroundSizeAnimation; @override void initState() { @@ -56,7 +56,7 @@ class PartialOverlayedPageState extends State with SingleT ), child: Container( decoration: BoxDecoration( - color: PalTheme.of(context).colors.light, + color: PalTheme.of(context)!.colors.light, borderRadius: BorderRadius.vertical( top: Radius.circular(16.0) ) diff --git a/lib/src/ui/editor/pal_editmode_wrapper.dart b/lib/src/ui/editor/pal_editmode_wrapper.dart index e6386b93..d59a9a79 100644 --- a/lib/src/ui/editor/pal_editmode_wrapper.dart +++ b/lib/src/ui/editor/pal_editmode_wrapper.dart @@ -10,11 +10,11 @@ import 'package:pal/src/ui/shared/widgets/overlayed.dart'; class PalEditModeWrapper extends StatefulWidget { // this is the client embedded application that wanna use our Pal - final Widget userApp; + final Widget? userApp; - final GlobalKey hostedAppNavigatorKey; + final GlobalKey? hostedAppNavigatorKey; - PalEditModeWrapper({@required this.userApp, this.hostedAppNavigatorKey}); + PalEditModeWrapper({required this.userApp, this.hostedAppNavigatorKey}); @override _PalEditModeWrapperState createState() => _PalEditModeWrapperState(); @@ -23,14 +23,14 @@ class PalEditModeWrapper extends StatefulWidget { class _PalEditModeWrapperState extends State { final GlobalKey _repaintBoundaryKey = GlobalKey(); - PalEditModeStateService palEditModeStateService; + PalEditModeStateService? palEditModeStateService; @override void didChangeDependencies() { super.didChangeDependencies(); palEditModeStateService = - EditorInjector.of(context).palEditModeStateService; - palEditModeStateService.showEditorBubble + EditorInjector.of(context)!.palEditModeStateService; + palEditModeStateService!.showEditorBubble .addListener(_onShowBubbleStateChanged); } @@ -38,7 +38,7 @@ class _PalEditModeWrapperState extends State { void dispose() { super.dispose(); if (palEditModeStateService != null) { - palEditModeStateService.showEditorBubble + palEditModeStateService!.showEditorBubble .removeListener(_onShowBubbleStateChanged); } } @@ -53,13 +53,13 @@ class _PalEditModeWrapperState extends State { navigatorKey: palNavigatorGlobalKey, debugShowCheckedModeBanner: false, onGenerateRoute: (RouteSettings settings) => route(settings), - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: NotificationListener( onNotification: (notification) { if (notification is ShowHelpersListNotification) { - _showGroupsList(EditorInjector.of(context).hostedAppNavigatorKey.currentContext); + _showGroupsList(EditorInjector.of(context)!.hostedAppNavigatorKey!.currentContext!); } else if (notification is ShowBubbleNotification) { - palEditModeStateService.showEditorBubble.value = + palEditModeStateService!.showEditorBubble.value = notification.isVisible; } return true; @@ -76,13 +76,13 @@ class _PalEditModeWrapperState extends State { // Build the floating widget above the app BubbleOverlayButton( key: ValueKey('palBubbleOverlay'), - visibility: palEditModeStateService.showEditorBubble, + visibility: palEditModeStateService!.showEditorBubble, screenSize: Size( constraints.maxWidth, constraints.maxHeight, ), onTapCallback: () { - palEditModeStateService.showEditorBubble.value = false; + palEditModeStateService!.showEditorBubble.value = false; return _showGroupsList(_context); }, ), diff --git a/lib/src/ui/editor/widgets/bordered_text_field.dart b/lib/src/ui/editor/widgets/bordered_text_field.dart index c08b87a3..000c4e91 100644 --- a/lib/src/ui/editor/widgets/bordered_text_field.dart +++ b/lib/src/ui/editor/widgets/bordered_text_field.dart @@ -3,25 +3,26 @@ import 'package:flutter/services.dart'; typedef OnValueChanged = void Function(String); +typedef TextFieldValidator = String? Function(String?); typedef OnFieldSubmitted = void Function(String); class BorderedTextField extends StatelessWidget { - final String hintText, initialValue; - final String Function(String) validator; - final OnValueChanged onValueChanged; - final OnFieldSubmitted onFieldSubmitted; - final TextEditingController controller; - final TextInputType textInputType; - final List inputFormatters; + final String? hintText, initialValue; + final TextFieldValidator? validator; + final OnValueChanged? onValueChanged; + final OnFieldSubmitted? onFieldSubmitted; + final TextEditingController? controller; + final TextInputType? textInputType; + final List? inputFormatters; final bool enableSuggestions; final bool autovalidate; final bool isLoading; final TextCapitalization textCapitalization; const BorderedTextField({ - Key key, + Key? key, this.hintText, - @required this.validator, + this.validator, this.controller, this.inputFormatters, this.textInputType, @@ -56,7 +57,7 @@ class BorderedTextField extends StatelessWidget { validator: validator, onChanged: (String newValue) { if (this.onValueChanged != null) { - this.onValueChanged(newValue); + this.onValueChanged!(newValue); } }, onFieldSubmitted: this.onFieldSubmitted, diff --git a/lib/src/ui/editor/widgets/bubble_overlay.dart b/lib/src/ui/editor/widgets/bubble_overlay.dart index 96a7029c..b92fc777 100644 --- a/lib/src/ui/editor/widgets/bubble_overlay.dart +++ b/lib/src/ui/editor/widgets/bubble_overlay.dart @@ -10,12 +10,12 @@ class BubbleOverlayButton extends StatefulWidget { final Size screenSize; - final Function onTapCallback; + final Function? onTapCallback; const BubbleOverlayButton({ - Key key, - @required this.screenSize, - @required this.visibility, + Key? key, + required this.screenSize, + required this.visibility, this.height = 64.0, this.width = 64.0, this.onTapCallback, @@ -27,9 +27,9 @@ class BubbleOverlayButton extends StatefulWidget { class _BubbleOverlayButtonState extends State with SingleTickerProviderStateMixin { - Offset _position; - AnimationController _animationController; - double _scale; + Offset? _position; + AnimationController? _animationController; + late double _scale; Duration _duration = Duration(milliseconds: 100); @override @@ -65,13 +65,13 @@ class _BubbleOverlayButtonState extends State @override Widget build(BuildContext context) { - _scale = 1 - _animationController.value; + _scale = 1 - _animationController!.value; if (_position != null) { return Visibility( visible: widget.visibility.value, child: Positioned( - left: _position.dx, - top: _position.dy, + left: _position!.dx, + top: _position!.dy, child: GestureDetector( onPanUpdate: (details) { setState(() { @@ -92,22 +92,22 @@ class _BubbleOverlayButtonState extends State } _onTapDown(TapDownDetails details) { - _animationController.forward(); + _animationController!.forward(); } _onTapUp(TapUpDetails details) { Future.delayed(_duration, () { - _animationController.reverse(); + _animationController!.reverse(); }); HapticFeedback.selectionClick(); if (widget.onTapCallback != null) { - widget.onTapCallback(); + widget.onTapCallback!(); } } _onTapCancel() { - _animationController.reverse(); + _animationController!.reverse(); } Widget _buildBubble() { @@ -121,7 +121,7 @@ class _BubbleOverlayButtonState extends State child: Transform.scale( scale: _scale, child: CircleImageButton( - backgroundColor: PalTheme.of(context).floatingBubbleBackgroundColor, + backgroundColor: PalTheme.of(context)!.floatingBubbleBackgroundColor, radius: widget.width / 2, shadow: BoxShadow( color: Colors.black.withOpacity(0.15), diff --git a/lib/src/ui/editor/widgets/edit_helper_toolbar.dart b/lib/src/ui/editor/widgets/edit_helper_toolbar.dart index 00244ea6..9fd38d1b 100644 --- a/lib/src/ui/editor/widgets/edit_helper_toolbar.dart +++ b/lib/src/ui/editor/widgets/edit_helper_toolbar.dart @@ -4,7 +4,7 @@ import 'package:pal/src/ui/shared/widgets/circle_button.dart'; class ToolbarAction { final Key key; - final Function onTap; + final Function? onTap; final IconData icon; ToolbarAction( @@ -15,18 +15,18 @@ class ToolbarAction { } class EditHelperToolbar extends StatelessWidget { - final Function onChangeTextFont; - final Function onChangeTextColor; - final Function onChangeBorder; - final Function onCloseTap; + final Function? onChangeTextFont; + final Function? onChangeTextColor; + final Function? onChangeBorder; + final Function? onCloseTap; final num bottomPadding; - final List extraActions; + final List? extraActions; final _toolbarHeight = 40.0; final _iconsRadius = 25.0; const EditHelperToolbar({ - Key key, + Key? key, this.onChangeTextFont, this.onChangeTextColor, this.onChangeBorder, @@ -36,11 +36,11 @@ class EditHelperToolbar extends StatelessWidget { }) : super(key: key); factory EditHelperToolbar.text({ - Key key, - Function onChangeTextFont, - Function onChangeTextColor, - Function onClose, - List extraActions, + Key? key, + Function? onChangeTextFont, + Function? onChangeTextColor, + Function? onClose, + List? extraActions, num bottomPadding = 8.0, }) { return EditHelperToolbar( @@ -53,11 +53,11 @@ class EditHelperToolbar extends StatelessWidget { } factory EditHelperToolbar.border({ - Key key, - Function onChangeTextFont, - Function onChangeTextColor, - Function onChangeBorder, - Function onClose, + Key? key, + Function? onChangeTextFont, + Function? onChangeTextColor, + Function? onChangeBorder, + Function? onClose, num bottomPadding = 8.0, }) { return EditHelperToolbar( @@ -77,11 +77,11 @@ class EditHelperToolbar extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: EdgeInsets.only(bottom: bottomPadding), + padding: EdgeInsets.only(bottom: bottomPadding as double), child: Container( key: ValueKey('pal_EditHelperToolbar'), height: _toolbarHeight, - color: PalTheme.of(context).toolbarBackgroundColor, + color: PalTheme.of(context)!.toolbarBackgroundColor, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 6.0), child: Row( @@ -116,7 +116,7 @@ class EditHelperToolbar extends StatelessWidget { size: _iconsRadius, ), ), - if (extraActions != null && extraActions.length > 0) + if (extraActions != null && extraActions!.length > 0) Wrap( spacing: 4.0, runSpacing: 4.0, @@ -147,7 +147,7 @@ class EditHelperToolbar extends StatelessWidget { List _buildExtraActions() { List children = []; - for (final ToolbarAction action in extraActions) { + for (final ToolbarAction action in extraActions!) { children.add( CircleIconButton( key: action.key, diff --git a/lib/src/ui/editor/widgets/labeled_form.dart b/lib/src/ui/editor/widgets/labeled_form.dart index 2f617d1c..ca6f9a06 100644 --- a/lib/src/ui/editor/widgets/labeled_form.dart +++ b/lib/src/ui/editor/widgets/labeled_form.dart @@ -1,13 +1,13 @@ import 'package:flutter/widgets.dart'; class LabeledForm extends StatelessWidget { - final String label; + final String? label; final Widget widget; const LabeledForm({ - Key key, - @required this.label, - @required this.widget, + Key? key, + required this.label, + required this.widget, }) : super(key: key); @override @@ -18,7 +18,7 @@ class LabeledForm extends StatelessWidget { Padding( padding: const EdgeInsets.only(bottom: 5.0), child: Text( - label, + label!, style: TextStyle( fontSize: 10.0, fontWeight: FontWeight.bold, diff --git a/lib/src/ui/editor/widgets/nested_navigator.dart b/lib/src/ui/editor/widgets/nested_navigator.dart index 63e151b2..56cc249f 100644 --- a/lib/src/ui/editor/widgets/nested_navigator.dart +++ b/lib/src/ui/editor/widgets/nested_navigator.dart @@ -5,12 +5,12 @@ class NestedNavigator extends StatelessWidget { final GlobalKey navigationKey; final String initialRoute; final Map routes; - final Function() onWillPop; + final Function()? onWillPop; NestedNavigator({ - @required this.navigationKey, - @required this.initialRoute, - @required this.routes, + required this.navigationKey, + required this.initialRoute, + required this.routes, this.onWillPop, }); @@ -21,15 +21,15 @@ class NestedNavigator extends StatelessWidget { key: navigationKey, initialRoute: initialRoute, onGenerateRoute: (RouteSettings routeSettings) { - WidgetBuilder builder = routes[routeSettings.name]; + WidgetBuilder? builder = routes[routeSettings.name!]; if (routeSettings.name == initialRoute) { return PageRouteBuilder( - pageBuilder: (context, __, ___) => builder(context), + pageBuilder: (context, __, ___) => builder!(context), settings: routeSettings, ); } else { return MaterialPageRoute( - builder: builder, + builder: builder!, settings: routeSettings, ); } @@ -37,10 +37,10 @@ class NestedNavigator extends StatelessWidget { ), onWillPop: () { if (this.onWillPop != null) { - this.onWillPop(); + this.onWillPop!(); } - if (navigationKey.currentState.canPop()) { - navigationKey.currentState.pop(); + if (navigationKey.currentState!.canPop()) { + navigationKey.currentState!.pop(); return Future.value(false); } return Future.value(true); diff --git a/lib/src/ui/editor/widgets/progress_widget/progress_bar.dart b/lib/src/ui/editor/widgets/progress_widget/progress_bar.dart index 1dc6d7bb..3996e061 100644 --- a/lib/src/ui/editor/widgets/progress_widget/progress_bar.dart +++ b/lib/src/ui/editor/widgets/progress_widget/progress_bar.dart @@ -3,9 +3,9 @@ import 'package:pal/src/theme.dart'; /* Bar render class : Renders the progress bar with the given value */ class ProgressBarRender extends StatefulWidget { - final double value; + final double? value; - const ProgressBarRender({Key key, this.value}) : super(key: key); + const ProgressBarRender({Key? key, this.value}) : super(key: key); @override _ProgressBarRenderState createState() => _ProgressBarRenderState(); @@ -15,18 +15,18 @@ class _ProgressBarRenderState extends State { @override Widget build(BuildContext context) { return FractionallySizedBox( - widthFactor: 0.9, + widthFactor: 0.96, child: DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( //* ANIMATION MOVES THE LEFT GRADIENT COLOR stops: [ - widget.value, + widget.value!, 0 ], // IN THE ORDER BELOW : DARK / GREY colors: [ - PalTheme.of(context).colors.dark, + PalTheme.of(context)!.colors.dark!, Color(0xFFC1BFD6), ]), ), diff --git a/lib/src/ui/editor/widgets/progress_widget/progress_bar_widget.dart b/lib/src/ui/editor/widgets/progress_widget/progress_bar_widget.dart index db32b69f..98315846 100644 --- a/lib/src/ui/editor/widgets/progress_widget/progress_bar_widget.dart +++ b/lib/src/ui/editor/widgets/progress_widget/progress_bar_widget.dart @@ -5,10 +5,10 @@ import 'progress_bar.dart'; /* Controller class : Takes all the variables needed, and transformes them before rendering */ class ProgressBarWidget extends StatefulWidget { - final double nbSteps; - final ValueNotifier step; + final double? nbSteps; + final ValueNotifier? step; - const ProgressBarWidget({Key key, this.nbSteps, this.step}) : super(key: key); + const ProgressBarWidget({Key? key, this.nbSteps, this.step}) : super(key: key); @override _ProgressBarWidgetState createState() => _ProgressBarWidgetState(); @@ -17,31 +17,31 @@ class ProgressBarWidget extends StatefulWidget { class _ProgressBarWidgetState extends State with SingleTickerProviderStateMixin { // CORE ATTRIBUTES - AnimationController controller; - Animation animation; + late AnimationController controller; + late Animation animation; // STATE ATTRIBUTES - double prevStep; + late double prevStep; // STEPS VARIABLES - double _stepScale; + late double _stepScale; @override void initState() { // SETUP // LISTENING TO STEP CHANGES - widget.step.addListener(this.refresh); + widget.step!.addListener(this.refresh); // INITIALIZING STEP SIZE : Bringing them to a smaller scale from 0 to 1* - this._stepScale = 1 / (widget.nbSteps - 1); + this._stepScale = 1 / (widget.nbSteps! - 1); // CONTROLLER AND ANIMATION INIT this.controller = AnimationController(vsync: this, duration: Duration(milliseconds: 500)); // ANIMATES THE PROGRESS BAR FROM [STEP-1] TO [STEP] this.animation = - Tween(begin: 0, end: this._stepScale * widget.step.value) + Tween(begin: 0, end: this._stepScale * widget.step!.value) .animate(this.controller); - this.prevStep = widget.step.value.toDouble(); + this.prevStep = widget.step!.value.toDouble(); // ANIMATES this.controller.forward(); super.initState(); @@ -52,9 +52,9 @@ class _ProgressBarWidgetState extends State // CREATES NEW ANIMATION FROM NEW VALUES this.animation = Tween( begin: this._stepScale * this.prevStep, - end: this._stepScale * widget.step.value) + end: this._stepScale * widget.step!.value) .animate(this.controller); - this.prevStep = widget.step.value.toDouble(); + this.prevStep = widget.step!.value.toDouble(); setState(() { this.controller.forward(); }); @@ -94,13 +94,13 @@ class _ProgressBarWidgetState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, // CREATES AS MANY PUSLING CIRCLES AS THERE OF STEPS children: [ - for (var i = 0; i < widget.nbSteps; i++) + for (var i = 0; i < widget.nbSteps!; i++) // CONTAINER NEEDED TO CREATE AN ALLOCATED SPACE FOR CIRCLE TU PULSE WITHOUR MOVING OTHERS Container( width: 25, child: PulsingCircleWidget( - active: i == widget.step.value, - done: i < widget.step.value, + active: i == widget.step!.value, + done: i < widget.step!.value, key: ValueKey("PulsingCircle"), ), ) diff --git a/lib/src/ui/editor/widgets/progress_widget/pulsing_circle.dart b/lib/src/ui/editor/widgets/progress_widget/pulsing_circle.dart index 5a9b5d24..2f2b0a3c 100644 --- a/lib/src/ui/editor/widgets/progress_widget/pulsing_circle.dart +++ b/lib/src/ui/editor/widgets/progress_widget/pulsing_circle.dart @@ -3,10 +3,10 @@ import 'package:pal/src/theme.dart'; /* Controller class */ class PulsingCircleWidget extends StatefulWidget { - final bool active; - final bool done; + final bool? active; + final bool? done; - const PulsingCircleWidget({Key key, this.active, this.done}) + const PulsingCircleWidget({Key? key, this.active, this.done}) : super(key: key); @override @@ -16,8 +16,8 @@ class PulsingCircleWidget extends StatefulWidget { class _PulsingCircleWidgetState extends State with SingleTickerProviderStateMixin { // CORE ATTRIBUTES - AnimationController controller; - Animation animation; + late AnimationController controller; + late Animation animation; @override void initState() { @@ -45,13 +45,13 @@ class _PulsingCircleWidgetState extends State builder: (context, child) => CircleRender( // COLOR BASED ON IF THE CIRCLE IS DONE / ACTIVE / NONE // IN THE ORDER BELOW : DARK / CYAN / GREY - color: widget.done - ? PalTheme.of(context).colors.dark - : widget.active - ? PalTheme.of(context).colors.color3 + color: widget.done! + ? PalTheme.of(context)!.colors.dark + : widget.active! + ? PalTheme.of(context)!.colors.color3 : Color(0xFFC1BFD6), // IF THE CIRCLE IS ACTIVE : ANIMATED / IF NOT : STATIC - radius: widget.active ? this.animation.value : 8, + radius: widget.active! ? this.animation.value : 8, ), ); } @@ -59,10 +59,10 @@ class _PulsingCircleWidgetState extends State /* Render class */ class CircleRender extends StatelessWidget { - final Color color; - final double radius; + final Color? color; + final double? radius; - const CircleRender({Key key, this.color, this.radius}) : super(key: key); + const CircleRender({Key? key, this.color, this.radius}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/src/ui/editor/widgets/snackbar_mixin.dart b/lib/src/ui/editor/widgets/snackbar_mixin.dart index df23136a..cf053d8d 100644 --- a/lib/src/ui/editor/widgets/snackbar_mixin.dart +++ b/lib/src/ui/editor/widgets/snackbar_mixin.dart @@ -4,10 +4,10 @@ import 'package:pal/src/theme.dart'; class SnackbarMixin { showSnackbarMessage( GlobalKey _scaffoldKey, String message, bool success) { - if (_scaffoldKey?.currentContext == null) { + if (_scaffoldKey.currentContext == null) { return; } - ScaffoldMessenger.of(_scaffoldKey.currentContext).showSnackBar( + ScaffoldMessenger.of(_scaffoldKey.currentContext!).showSnackBar( SnackBar( content: Row( children: [ @@ -15,7 +15,7 @@ class SnackbarMixin { ? Icon(Icons.check, color: Colors.lightGreenAccent) : Icon(Icons.warning, color: - PalTheme.of(_scaffoldKey.currentContext).colors.light), + PalTheme.of(_scaffoldKey.currentContext!)!.colors.light), Flexible( child: Padding( padding: const EdgeInsets.only(left: 8.0), @@ -29,7 +29,7 @@ class SnackbarMixin { ], ), backgroundColor: success - ? PalTheme.of(_scaffoldKey.currentContext).colors.dark + ? PalTheme.of(_scaffoldKey.currentContext!)!.colors.dark : Colors.redAccent, duration: Duration(milliseconds: 1500), ), diff --git a/lib/src/ui/shared/helper_shared_factory.dart b/lib/src/ui/shared/helper_shared_factory.dart index 3adae394..32f944b0 100644 --- a/lib/src/ui/shared/helper_shared_factory.dart +++ b/lib/src/ui/shared/helper_shared_factory.dart @@ -38,87 +38,87 @@ class AnchoredscreenHelperKeys { } class HelperSharedFactory { - static HelperTextViewModel parseTextLabel( + static HelperTextViewModel? parseTextLabel( final String key, final List helperTexts, ) { for (HelperTextEntity helperText in helperTexts) { - if (key == helperText?.key) { + if (key == helperText.key) { return HelperTextViewModel( - id: helperText?.id, - text: helperText?.value, - fontColor: HexColor.fromHex(helperText?.fontColor), - fontSize: helperText?.fontSize?.toDouble(), - fontFamily: helperText?.fontFamily, - fontWeight: FontWeightMapper.toFontWeight(helperText?.fontWeight), + id: helperText.id, + text: helperText.value, + fontColor: HexColor.fromHex(helperText.fontColor!), + fontSize: helperText.fontSize?.toDouble(), + fontFamily: helperText.fontFamily, + fontWeight: FontWeightMapper.toFontWeight(helperText.fontWeight), ); } } return null; } - static HelperButtonViewModel parseButtonLabel( + static HelperButtonViewModel? parseButtonLabel( final String key, final List helperTexts, ) { for (HelperTextEntity helperText in helperTexts) { - if (key == helperText?.key) { + if (key == helperText.key) { return HelperButtonViewModel( - id: helperText?.id, - text: helperText?.value, - fontColor: HexColor.fromHex(helperText?.fontColor), - fontSize: helperText?.fontSize?.toDouble(), - fontFamily: helperText?.fontFamily, - fontWeight: FontWeightMapper.toFontWeight(helperText?.fontWeight), + id: helperText.id, + text: helperText.value, + fontColor: HexColor.fromHex(helperText.fontColor!), + fontSize: helperText.fontSize?.toDouble(), + fontFamily: helperText.fontFamily, + fontWeight: FontWeightMapper.toFontWeight(helperText.fontWeight), ); } } return null; } - static HelperImageViewModel parseImageUrl( + static HelperImageViewModel? parseImageUrl( final String key, - final List helperImages, + final List? helperImages, ) { if (helperImages == null || helperImages.length == 0) { return null; } for (HelperImageEntity helperImage in helperImages) { - if (key == helperImage?.key) { + if (key == helperImage.key) { return HelperImageViewModel( - id: helperImage?.id, - url: helperImage?.url, + id: helperImage.id, + url: helperImage.url, ); } } return null; } - static HelperBoxViewModel parseBoxBackground( + static HelperBoxViewModel? parseBoxBackground( final String key, final List helperBoxes, ) { for (HelperBoxEntity helperBox in helperBoxes) { - if (key == helperBox?.key) { + if (key == helperBox.key) { return HelperBoxViewModel( - id: helperBox?.id, - backgroundColor: HexColor.fromHex(helperBox?.backgroundColor)); + id: helperBox.id, + backgroundColor: HexColor.fromHex(helperBox.backgroundColor!)); } } return null; } - static HelperBorderViewModel parseBorder( + static HelperBorderViewModel? parseBorder( final String key, final List helperBorders, ) { for (HelperBorderEntity helperBorder in helperBorders) { - if (key == helperBorder?.key) { + if (key == helperBorder.key) { return HelperBorderViewModel( - id: helperBorder?.id, - style: helperBorder?.style, - color: HexColor.fromHex(helperBorder?.color), - width: helperBorder?.width, + id: helperBorder.id, + style: helperBorder.style, + color: HexColor.fromHex(helperBorder.color!), + width: helperBorder.width, ); } } @@ -132,15 +132,15 @@ class HelperSharedFactory { // TODO: Reorganize array from back ? List customLabels = []; for (HelperTextEntity helperText in helperTexts) { - if (helperText.key.startsWith(key)) { + if (helperText.key!.startsWith(key)) { customLabels.add( HelperTextViewModel( - id: helperText?.id ?? helperTexts.indexOf(helperText), - text: helperText?.value, - fontColor: HexColor.fromHex(helperText?.fontColor), - fontSize: helperText?.fontSize?.toDouble(), - fontFamily: helperText?.fontFamily, - fontWeight: FontWeightMapper.toFontWeight(helperText?.fontWeight), + id: helperText.id ?? helperTexts.indexOf(helperText), + text: helperText.value, + fontColor: HexColor.fromHex(helperText.fontColor!), + fontSize: helperText.fontSize?.toDouble(), + fontFamily: helperText.fontFamily, + fontWeight: FontWeightMapper.toFontWeight(helperText.fontWeight), ), ); } diff --git a/lib/src/ui/shared/helper_shared_viewmodels.dart b/lib/src/ui/shared/helper_shared_viewmodels.dart index fddcfc11..5020e086 100644 --- a/lib/src/ui/shared/helper_shared_viewmodels.dart +++ b/lib/src/ui/shared/helper_shared_viewmodels.dart @@ -1,42 +1,42 @@ import 'package:flutter/widgets.dart'; class HelperTextViewModel { - int id; - String key; - String text; - Color fontColor; - double fontSize; - String fontFamily; - FontWeight fontWeight; + int? id; + String? key; + String? text; + Color? fontColor; + double? fontSize; + String? fontFamily; + FontWeight? fontWeight; HelperTextViewModel({ this.id, this.text, this.key, - @required this.fontColor, - @required this.fontSize, + required this.fontColor, + required this.fontSize, this.fontFamily, this.fontWeight, }); } class HelperButtonViewModel { - int id; - String key; - String text; - Color fontColor; - double fontSize; - String fontFamily; - FontWeight fontWeight; - Color borderColor; - Color backgroundColor; + int? id; + String? key; + String? text; + Color? fontColor; + double? fontSize; + String? fontFamily; + FontWeight? fontWeight; + Color? borderColor; + Color? backgroundColor; HelperButtonViewModel({ this.id, this.text, this.key, - @required this.fontColor, - @required this.fontSize, + required this.fontColor, + required this.fontSize, this.fontFamily, this.fontWeight, this.backgroundColor, @@ -45,30 +45,30 @@ class HelperButtonViewModel { } class HelperImageViewModel { - int id; - String url; + int? id; + String? url; HelperImageViewModel({ this.id, - @required this.url, + required this.url, }); } class HelperBoxViewModel { - int id; - Color backgroundColor; + int? id; + Color? backgroundColor; HelperBoxViewModel({ this.id, - @required this.backgroundColor, + required this.backgroundColor, }); } class HelperBorderViewModel { - int id; - Color color; - String style; - double width; + int? id; + Color? color; + String? style; + double? width; HelperBorderViewModel({ this.id, diff --git a/lib/src/ui/shared/utilities/element_finder.dart b/lib/src/ui/shared/utilities/element_finder.dart index 9b5e0199..cdb66da0 100644 --- a/lib/src/ui/shared/utilities/element_finder.dart +++ b/lib/src/ui/shared/utilities/element_finder.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/material.dart'; /// This class helps you find element within your app @@ -6,15 +7,15 @@ import 'package:flutter/material.dart'; class ElementFinder { // Prefer use the navigatorContext to get full context tree - final BuildContext context; + final BuildContext? context; ElementFinder(this.context); // this method scan all child recursively to get all widget bounds we could select for an helper - Map scan({Key omitChildsOf, bool debugMode = false}) { + Map scan({Key? omitChildsOf, bool debugMode = false}) { Map results = Map(); - context.visitChildElements((element) => _scanChildElement( - context.findRenderObject(), + context!.visitChildElements((element) => _scanChildElement( + context!.findRenderObject(), element, results, omitChildsOf: omitChildsOf, @@ -26,14 +27,14 @@ class ElementFinder { // List all pages from this context List scanPages() { var pages = []; - context.visitChildElements((element) => _scanPageChildElement(element, pages)); - return pages; + context!.visitChildElements((element) => _scanPageChildElement(element, pages as List)); + return pages as List; } // this method scan all child recursively to find a widget having a key == searchedKey - ElementModel searchChildElement(String key) { - ElementModel result; - context.visitChildElements((element) => result = _searchChildElement(context.findRenderObject(), element, key)); + ElementModel? searchChildElement(String? key) { + ElementModel? result; + context!.visitChildElements((element) => result = _searchChildElement(context!.findRenderObject(), element, key)); if(result == null) return ElementModel.empty(); return result; @@ -42,13 +43,13 @@ class ElementFinder { /// This functions search for the maximum rect available space /// We use it for example to find the most available space to write a text in our anchored helper Rect getLargestAvailableSpace(ElementModel elementModel) { - var parentObject = context.findRenderObject(); - var element = elementModel.element; - var translation = element.renderObject.getTransformTo(parentObject).getTranslation(); + var parentObject = context!.findRenderObject()!; + var element = elementModel.element!; + var translation = element.renderObject!.getTransformTo(parentObject).getTranslation(); var objectX = translation.x; - var objectEndX = objectX + element.size.width; + var objectEndX = objectX + element.size!.width; var objectY = translation.y; - var objectEndY = objectY + element.size.height; + var objectEndY = objectY + element.size!.height; var layerRect = parentObject.paintBounds; Rect availableHSpace; @@ -78,16 +79,16 @@ class ElementFinder { // ----------------------------------------------------------- // ERROR - ElementModel _searchChildElement(RenderObject parentObject, Element element, String key, {int n = 0}) { + ElementModel? _searchChildElement(RenderObject? parentObject, Element element, String? key, {int n = 0}) { if(element.widget.key != null - && element.widget.key.toString().contains(key)) { + && element.widget.key.toString().contains(key!)) { try { // if render element has bounds lets take it var res = _createElementModel(parentObject, element); return res; } catch(_) {} } - ElementModel result; + ElementModel? result; element.visitChildElements((visitor) { var res = _searchChildElement(parentObject, visitor, key, n: n + 1); if(res != null) @@ -99,25 +100,25 @@ class ElementFinder { // omits elements with key starting with anything other than [< // flutter makes key with "[<_myKey_>]" for our keys // scan all elements in the current page tree and add their bounds to the results map - _scanChildElement(RenderObject parentObject, Element element, Map results, {int n = 0, Key omitChildsOf, bool debugMode = true}) { + _scanChildElement(RenderObject? parentObject, Element element, Map results, {int n = 0, Key? omitChildsOf, bool debugMode = true}) { if(debugMode) { var nbChilds = element.debugDescribeChildren().length; var pre = StringBuffer(); for(int i = 0; i $nbChilds "); + debugPrint("$pre ${element.widget.runtimeType} $n => $nbChilds "); } if(element.widget.key != null && omitChildsOf !=null && element.widget.key.toString() == omitChildsOf.toString()) { return; } if(element.widget.key != null && element.widget.key.toString().startsWith("[<") && !results.containsKey(element.widget.key.toString())) { if(debugMode) { - debugPrint(" added ${element?.widget?.key.toString()} : $n"); + debugPrint(" added ${element.widget.key.toString()} : $n"); } try { var model = _createElementModel(parentObject, element); - if(results.values.firstWhere((element) => element.bounds == model.bounds && element.offset == model.offset, orElse: () => null) == null) { + if(results.values.firstWhereOrNull((element) => element.bounds == model.bounds && element.offset == model.offset) == null) { results.putIfAbsent(element.widget.key.toString(), () => model); } } catch (e) { @@ -137,8 +138,8 @@ class ElementFinder { } } - ElementModel _createElementModel(RenderObject parentObject, Element element) { - var renderObject = element.findRenderObject(); + ElementModel _createElementModel(RenderObject? parentObject, Element element) { + var renderObject = element.findRenderObject()!; var bounds = renderObject.paintBounds; var translation = renderObject.getTransformTo(parentObject).getTranslation(); var offset = Offset(translation.x, translation.y); @@ -161,18 +162,18 @@ class PageElement { class ElementModel { - String key; + String? key; - Rect bounds; + Rect? bounds; - Offset offset; + Offset? offset; - Element element; + Element? element; Type runtimeType; ElementModel(this.key, this.bounds, this.offset, this.runtimeType, {this.element}); - factory ElementModel.empty() => ElementModel(null, null, null, null); + factory ElementModel.empty() => ElementModel(null, null, null, ElementModel); } diff --git a/lib/src/ui/shared/widgets/bouncing_widget.dart b/lib/src/ui/shared/widgets/bouncing_widget.dart index a244fa1f..a13fff4a 100644 --- a/lib/src/ui/shared/widgets/bouncing_widget.dart +++ b/lib/src/ui/shared/widgets/bouncing_widget.dart @@ -3,14 +3,14 @@ import 'package:flutter/services.dart'; class BouncingWidget extends StatefulWidget { final Widget child; - final VoidCallback onTap; + final VoidCallback? onTap; final Duration duration; final bool vibrationEnabled; BouncingWidget({ - Key key, - @required this.child, - @required this.onTap, + Key? key, + required this.child, + required this.onTap, this.vibrationEnabled = true, this.duration = const Duration(milliseconds: 100), }) : super(key: key); @@ -21,8 +21,8 @@ class BouncingWidget extends StatefulWidget { class _BouncingWidgetState extends State with SingleTickerProviderStateMixin { - AnimationController _controller; - double _scale; + AnimationController? _controller; + late double _scale; @override void initState() { @@ -46,7 +46,7 @@ class _BouncingWidgetState extends State @override Widget build(BuildContext context) { - _scale = 1 - _controller.value; + _scale = 1 - _controller!.value; return IgnorePointer( ignoring: widget.onTap == null, @@ -69,17 +69,17 @@ class _BouncingWidgetState extends State if (widget.vibrationEnabled) { HapticFeedback.selectionClick(); } - _controller?.forward?.call(); + _controller?.forward.call(); } _onTapUp(TapUpDetails details) { Future.delayed(widget.duration, () { - _controller?.reverse?.call(); + _controller?.reverse.call(); }); widget.onTap?.call(); } _onTapCancel() { - _controller?.reverse?.call(); + _controller?.reverse.call(); } } diff --git a/lib/src/ui/shared/widgets/circle_button.dart b/lib/src/ui/shared/widgets/circle_button.dart index 88fe8e24..40115705 100644 --- a/lib/src/ui/shared/widgets/circle_button.dart +++ b/lib/src/ui/shared/widgets/circle_button.dart @@ -3,20 +3,20 @@ import 'package:pal/src/ui/shared/widgets/bouncing_widget.dart'; // TODO: COnvert to stateless class CircleIconButton extends StatefulWidget { - final Color backgroundColor; - final Color splashColor; + final Color? backgroundColor; + final Color? splashColor; final Color loadingColor; final num radius; - final Icon icon; - final BoxShadow shadow; + final Icon? icon; + final BoxShadow? shadow; final bool displayShadow; - final Function onTapCallback; - final bool isLoading; - final BorderSide borderSide; - final Widget animatedIcon; + final Function? onTapCallback; + final bool? isLoading; + final BorderSide? borderSide; + final Widget? animatedIcon; const CircleIconButton({ - Key key, + Key? key, this.backgroundColor = Colors.blue, this.loadingColor = Colors.white, this.splashColor, @@ -31,17 +31,17 @@ class CircleIconButton extends StatefulWidget { }) : super(key: key); factory CircleIconButton.animatedIcon({ - Key key, - @required AnimatedIcon animatedIcon, - Color backgroundColor = Colors.blue, - Color splashColor, + Key? key, + required AnimatedIcon animatedIcon, + Color? backgroundColor = Colors.blue, + Color? splashColor, Color loadingColor = Colors.white, num radius = 20.0, - BoxShadow shadow, + BoxShadow? shadow, bool displayShadow = true, - Function onTapCallback, + Function? onTapCallback, bool isLoading = false, - BorderSide borderSide, + BorderSide? borderSide, }) { return CircleIconButton( key: key, @@ -59,17 +59,17 @@ class CircleIconButton extends StatefulWidget { } factory CircleIconButton.icon({ - Key key, - @required final Icon icon, + Key? key, + required final Icon icon, Color backgroundColor = Colors.blue, - Color splashColor, + Color? splashColor, Color loadingColor = Colors.white, num radius = 20.0, - BoxShadow shadow, + BoxShadow? shadow, bool displayShadow = true, - Function onTapCallback, + Function? onTapCallback, bool isLoading = false, - BorderSide borderSide, + BorderSide? borderSide, }) { return CircleIconButton( key: key, @@ -94,12 +94,12 @@ class _CircleIconButtonState extends State { @override Widget build(BuildContext context) { return BouncingWidget( - onTap: widget.onTapCallback, + onTap: widget.onTapCallback as void Function()?, child: Container( decoration: BoxDecoration( shape: BoxShape.circle, border: this.widget.borderSide != null - ? Border.fromBorderSide(this.widget.borderSide) + ? Border.fromBorderSide(this.widget.borderSide!) : null, color: Colors.transparent, boxShadow: widget.displayShadow @@ -121,7 +121,7 @@ class _CircleIconButtonState extends State { child: SizedBox( width: widget.radius * 2, height: widget.radius * 2, - child: (widget.isLoading) + child: widget.isLoading! ? Padding( padding: const EdgeInsets.all(12.0), child: CircularProgressIndicator( @@ -137,6 +137,6 @@ class _CircleIconButtonState extends State { ); } - Widget _buildIcon() => + Widget? _buildIcon() => (widget.icon != null) ? widget.icon : widget.animatedIcon; } diff --git a/lib/src/ui/shared/widgets/circle_image.dart b/lib/src/ui/shared/widgets/circle_image.dart index 58329947..de829a51 100644 --- a/lib/src/ui/shared/widgets/circle_image.dart +++ b/lib/src/ui/shared/widgets/circle_image.dart @@ -1,18 +1,18 @@ import 'package:flutter/material.dart'; class CircleImageButton extends StatelessWidget { - final Color backgroundColor; - final Color splashColor; + final Color? backgroundColor; + final Color? splashColor; final num radius; final String image; - final BoxShadow shadow; + final BoxShadow? shadow; const CircleImageButton({ - Key key, + Key? key, this.backgroundColor = Colors.blue, this.splashColor, this.radius = 20.0, this.shadow, - @required this.image, + required this.image, }) : super(key: key); @override diff --git a/lib/src/ui/shared/widgets/overlayed.dart b/lib/src/ui/shared/widgets/overlayed.dart index 5ae1c627..d18dfc64 100644 --- a/lib/src/ui/shared/widgets/overlayed.dart +++ b/lib/src/ui/shared/widgets/overlayed.dart @@ -12,19 +12,18 @@ class Overlayed extends InheritedWidget { final Map entries = new Map(); Overlayed({ - Key key, - @required Widget child, - }) : assert(child != null), - super(key: key, child: child); + Key? key, + required Widget child, + }) : super(key: key, child: child); - static Overlayed of(BuildContext context) => + static Overlayed? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType(); static void removeOverlay(BuildContext context, OverlayKeys key) { var instance = context.dependOnInheritedWidgetOfExactType(); instance?.entries[key]?.popFunction?.call(); instance?.entries[key]?.remove(); - instance?.entries?.remove(key); + instance?.entries.remove(key); } @override @@ -32,9 +31,9 @@ class Overlayed extends InheritedWidget { } class EditorOverlayEntry extends OverlayEntry { - final Function popFunction; + final Function? popFunction; EditorOverlayEntry(this.popFunction, {bool maintainState = false, bool opaque = false, - Widget Function(BuildContext) builder}) + required Widget Function(BuildContext) builder}) : super(builder: builder, maintainState: maintainState, opaque: opaque); } diff --git a/pubspec.lock b/pubspec.lock index 28aa5f2a..456a1f52 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,21 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "19.0.0" + version: "21.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" - application_icon: - dependency: "direct main" - description: - name: application_icon - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" + version: "1.5.0" archive: dependency: transitive description: @@ -35,7 +28,7 @@ packages: name: args url: "https://pub.dartlang.org" source: hosted - version: "1.6.0" + version: "2.1.0" async: dependency: transitive description: @@ -63,56 +56,56 @@ packages: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "0.4.7" + version: "1.0.0" build_daemon: dependency: transitive description: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "2.1.7" + version: "3.0.0" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.12.2" + version: "2.0.1" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "6.1.12" + version: "7.0.0" built_collection: dependency: transitive description: name: built_collection url: "https://pub.dartlang.org" source: hosted - version: "4.3.2" + version: "5.0.0" built_value: dependency: transitive description: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "7.1.0" + version: "8.0.5" cached_network_image: dependency: "direct main" description: name: cached_network_image url: "https://pub.dartlang.org" source: hosted - version: "2.5.1" + version: "3.0.0" characters: dependency: transitive description: @@ -154,9 +147,9 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "3.7.0" + version: "4.0.0" collection: - dependency: transitive + dependency: "direct main" description: name: collection url: "https://pub.dartlang.org" @@ -169,6 +162,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.0" + coverage: + dependency: transitive + description: + name: coverage + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" crypto: dependency: transitive description: @@ -189,7 +189,7 @@ packages: name: dotted_border url: "https://pub.dartlang.org" source: hosted - version: "1.0.7" + version: "2.0.0" fake_async: dependency: transitive description: @@ -217,7 +217,7 @@ packages: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "0.10.11" + version: "1.0.0" flutter: dependency: "direct main" description: flutter @@ -229,14 +229,14 @@ packages: name: flutter_blurhash url: "https://pub.dartlang.org" source: hosted - version: "0.5.0" + version: "0.6.0" flutter_cache_manager: dependency: transitive description: name: flutter_cache_manager url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "3.0.1" flutter_colorpicker: dependency: "direct main" description: @@ -249,6 +249,11 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" glob: dependency: transitive description: @@ -269,14 +274,14 @@ packages: name: graphs url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "2.0.0" hive: dependency: "direct main" description: name: hive url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.4" hive_flutter: dependency: "direct main" description: @@ -285,26 +290,26 @@ packages: source: hosted version: "1.0.0" hive_generator: - dependency: "direct main" + dependency: "direct dev" description: name: hive_generator url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.1.0" http: dependency: "direct main" description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.1" + version: "0.13.2" http_multi_server: dependency: transitive description: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "3.0.1" http_parser: dependency: "direct main" description: @@ -325,14 +330,14 @@ packages: name: io url: "https://pub.dartlang.org" source: hosted - version: "0.3.5" + version: "1.0.0" js: dependency: transitive description: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.2" + version: "0.6.3" json_annotation: dependency: transitive description: @@ -367,28 +372,35 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "0.9.7" - mockito: + version: "1.0.0" + mocktail: dependency: "direct dev" description: - name: mockito + name: mocktail url: "https://pub.dartlang.org" source: hosted - version: "5.0.3" + version: "0.1.2" mvvm_builder: dependency: "direct main" description: name: mvvm_builder url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.0-null.safety" + node_preamble: + dependency: transitive + description: + name: node_preamble + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.13" octo_image: dependency: transitive description: name: octo_image url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "1.0.0+1" package_config: dependency: transitive description: @@ -396,13 +408,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" - package_info: + package_info_plus: dependency: "direct main" description: - name: package_info + name: package_info_plus url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "1.0.1" + package_info_plus_linux: + dependency: transitive + description: + name: package_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + package_info_plus_macos: + dependency: transitive + description: + name: package_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + package_info_plus_web: + dependency: transitive + description: + name: package_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + package_info_plus_windows: + dependency: transitive + description: + name: package_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" path: dependency: transitive description: @@ -416,14 +463,14 @@ packages: name: path_drawing url: "https://pub.dartlang.org" source: hosted - version: "0.4.1+1" + version: "0.5.0" path_parsing: dependency: transitive description: name: path_parsing url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.2.0" path_provider: dependency: "direct main" description: @@ -515,20 +562,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.5" rxdart: dependency: "direct main" description: name: rxdart url: "https://pub.dartlang.org" source: hosted - version: "0.25.0" + version: "0.26.0" shelf: dependency: transitive description: @@ -536,13 +576,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + shelf_static: + dependency: transitive + description: + name: shelf_static + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "0.2.4+1" + version: "1.0.1" sky_engine: dependency: transitive description: flutter @@ -555,6 +609,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + source_maps: + dependency: transitive + description: + name: source_maps + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.10" source_span: dependency: transitive description: @@ -618,6 +693,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + test: + dependency: transitive + description: + name: test + url: "https://pub.dartlang.org" + source: hosted + version: "1.16.5" test_api: dependency: transitive description: @@ -625,13 +707,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.19" + test_core: + dependency: transitive + description: + name: test_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.15" timing: dependency: transitive description: name: timing url: "https://pub.dartlang.org" source: hosted - version: "0.1.1+3" + version: "1.0.0" typed_data: dependency: transitive description: @@ -653,6 +742,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + vm_service: + dependency: transitive + description: + name: vm_service + url: "https://pub.dartlang.org" + source: hosted + version: "6.2.0" watcher: dependency: transitive description: @@ -666,7 +762,14 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "2.0.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" win32: dependency: transitive description: @@ -697,4 +800,4 @@ packages: version: "3.1.0" sdks: dart: ">=2.12.0 <3.0.0" - flutter: ">=1.26.0-17.5.pre" + flutter: ">=1.24.0-10.2.pre" diff --git a/pubspec.yaml b/pubspec.yaml index 38461312..b440fc72 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,38 +1,40 @@ name: pal description: The no code Flutter onboarding editor -version: 1.0.0+1 +version: 2.0.0+1 homepage: https://pal-plugin.tech repository: https://github.com/Apparence-io/pal-plugin issue_tracker: https://github.com/Apparence-io/pal-plugin/issues documentation: https://doc.pal-plugin.tech environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' flutter: ">=1.17.0" dependencies: flutter: sdk: flutter - application_icon: ^2.0.0 - cached_network_image: ^2.5.1 - dotted_border: ^1.0.7 + # application_icon: ^2.0.0 #no web, mac os, windows & linux + cached_network_image: ^3.0.0 + dotted_border: ^2.0.0 flutter_colorpicker: ^0.4.0 google_fonts: ^2.0.0 - hive: ^2.0.1 - hive_flutter: ^1.0.0 - hive_generator: ^1.0.1 - http: ^0.13.1 + hive: ^2.0.4 + hive_flutter: ^1.0.0 #no web + http: ^0.13.2 http_parser: ^4.0.0 - mvvm_builder: ^2.1.5 - package_info: ^2.0.0 path_provider: ^2.0.1 - rxdart: ^0.25.0 + mvvm_builder: ^3.0.0-null.safety + package_info_plus: ^1.0.1 + rxdart: ^0.26.0 + collection: ^1.15.0 dev_dependencies: flutter_test: sdk: flutter - build_runner: ^1.12.2 - mockito: ^5.0.3 + build_runner: ^2.0.1 + mocktail: ^0.1.2 + hive_generator: ^1.1.0 + flutter: assets: diff --git a/test/database/entity/helper_entity_matchers.dart b/test/database/entity/helper_entity_matchers.dart index ab9b87d6..f9ecd825 100644 --- a/test/database/entity/helper_entity_matchers.dart +++ b/test/database/entity/helper_entity_matchers.dart @@ -7,7 +7,7 @@ class HelperEntityMatcher extends Matcher { final bool testId; - const HelperEntityMatcher({@required this.expected, this.testId = true}) : assert(expected != null); + const HelperEntityMatcher({required this.expected, this.testId = true}) : assert(expected != null); @override bool matches(dynamic actual, Map matchState) { @@ -32,17 +32,17 @@ class HelperEntityMatcher extends Matcher { } bool checkTexts(HelperEntity other, Map matchState) { - print("first helper has ${expected.helperTexts.length} texts"); - print("second helper has ${other.helperTexts.length} texts"); + print("first helper has ${expected.helperTexts!.length} texts"); + print("second helper has ${other.helperTexts!.length} texts"); if(other.helperTexts == null && expected.helperTexts == null) return true; - if(other.helperTexts.length != expected.helperTexts.length) { + if(other.helperTexts!.length != expected.helperTexts!.length) { matchState.putIfAbsent("helperBoxes", () => "not same number of items"); return false; } - for(int i = 0; i < other.helperTexts.length; i++) { - HelperTextEntity second = expected.helperTexts.elementAt(i); - HelperTextEntity first = other.helperTexts.elementAt(i); + for(int i = 0; i < other.helperTexts!.length; i++) { + HelperTextEntity second = expected.helperTexts!.elementAt(i); + HelperTextEntity first = other.helperTexts!.elementAt(i); print("[compare] '${first.value}' with '${second.value}' =>> ${first.value == second.value}"); if(testId && first.id != second.id) { print(" ... not same id"); @@ -68,11 +68,11 @@ class HelperEntityMatcher extends Matcher { bool checkBoxes(HelperEntity other, Map matchState) { if(other.helperBoxes == null && expected.helperBoxes == null) return true; - if(other.helperBoxes.length != expected.helperBoxes.length) + if(other.helperBoxes!.length != expected.helperBoxes!.length) return false; - for(int i = 0; i< other.helperBoxes.length; i++) { - HelperBoxEntity second = expected.helperBoxes.elementAt(i); - HelperBoxEntity first = other.helperBoxes.elementAt(i); + for(int i = 0; i< other.helperBoxes!.length; i++) { + HelperBoxEntity second = expected.helperBoxes!.elementAt(i); + HelperBoxEntity first = other.helperBoxes!.elementAt(i); if(testId && first.id != second.id) { return false; } diff --git a/test/pal_test.dart b/test/pal_test.dart index d786c771..f0fff00c 100644 --- a/test/pal_test.dart +++ b/test/pal_test.dart @@ -29,6 +29,7 @@ void main() { testWidgets('Create app with Pal in editor mode should inject EditorInjector', (WidgetTester tester) async { Pal app = _createApp(true); await tester.pumpWidget(app); + await tester.pump(); var palFinder = find.byType(Pal).first; var editorInjectorFinder = find.byType(EditorInjector); var userAppInjectFinder = find.byType(UserInjector); diff --git a/test/pal_test_utilities.dart b/test/pal_test_utilities.dart index cdb6fd56..e7bc123c 100644 --- a/test/pal_test_utilities.dart +++ b/test/pal_test_utilities.dart @@ -29,13 +29,13 @@ const Duration kPressTimeout = Duration(milliseconds: 100); Future initAppWithPal( WidgetTester tester, - Widget userApp, + Widget? userApp, GlobalKey navigatorKey, { - RouteFactory routeFactory, + RouteFactory? routeFactory, bool editorModeEnabled = true, - EditorAppContext editorAppContext, - UserAppContext userAppContext + EditorAppContext? editorAppContext, + UserAppContext? userAppContext }) async { BuildContext context; // ignore: unused_local_variable if (editorAppContext != null) EditorAppContext.create(editorAppContext); @@ -45,16 +45,17 @@ Future initAppWithPal( editorModeEnabled: editorModeEnabled, childApp: new MaterialApp( onGenerateRoute: routeFactory ?? - (_) => MaterialPageRoute(settings: RouteSettings(name: "myPage"), builder: (ctx) { + ((_) => MaterialPageRoute(settings: RouteSettings(name: "myPage"), builder: (ctx) { context = ctx; - return userApp; - }), + return userApp!; + })), navigatorKey: navigatorKey, navigatorObservers: [PalNavigatorObserver.instance()], ), ); await tester.pumpWidget(app); - print(navigatorKey); + await tester.pump(); + await tester.pumpAndSettle(); } /// use this to show an helper editor for each type @@ -66,11 +67,11 @@ Future pumpHelperWidget( HelperTriggerType triggerType, HelperType type, HelperTheme theme, { - EditorHelperService editorHelperService, - PalEditModeStateService palEditModeStateService, - HelperEntity helperEntity, - PackageVersionReader packageVersionReader, - FinderService finderService, + EditorHelperService? editorHelperService, + PalEditModeStateService? palEditModeStateService, + HelperEntity? helperEntity, + PackageVersionReader? packageVersionReader, + FinderService? finderService, }) async { // push helper editor page HelperEditorPageArguments args = HelperEditorPageArguments( @@ -83,7 +84,7 @@ Future pumpHelperWidget( helperTheme: theme, priority: 1, helperGroup: HelperGroupModel( - triggerType: triggerType ?? HelperTriggerType.ON_SCREEN_VISIT, + triggerType: triggerType, minVersionCode: "0.0.0", maxVersionCode: "1.0.1", ), @@ -207,8 +208,7 @@ Future enterTextInTextForm( await tester.pump(Duration(milliseconds: 500)); await tester.pump(Duration(milliseconds: 1500)); - final textToolbarButton = - find.byKey(ValueKey('EditorToolBar_SpecificAction_Text')); + final textToolbarButton = find.byKey(ValueKey('EditorToolBar_SpecificAction_Text')); await tester.tap(textToolbarButton); await tester.pump(Duration(milliseconds: 1500)); diff --git a/test/services/client/helper_client_service_test.dart b/test/services/client/helper_client_service_test.dart index 41e76ea4..0daff0ec 100644 --- a/test/services/client/helper_client_service_test.dart +++ b/test/services/client/helper_client_service_test.dart @@ -2,7 +2,8 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:http/http.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/helper/helper_entity.dart'; import 'package:pal/src/database/entity/helper/helper_group_entity.dart'; import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; @@ -19,14 +20,16 @@ import 'package:pal/src/services/http_client/base_client.dart'; import 'package:pal/src/services/locale_service/locale_service.dart'; class HttpClientMock extends Mock implements HttpClient {} +class LocaleServiceMock extends Mock implements LocaleService {} void main() { HiveClient hiveClient = HiveClient(shouldInit: false) ..initLocal(); - HelperClientService helperClientService; + late HelperClientService helperClientService; HttpClient httpClientMock = HttpClientMock(); + LocaleService localeServiceMock = LocaleServiceMock(); ClientSchemaLocalRepository clientSchemaRepository = ClientSchemaLocalRepository(hiveBoxOpener: hiveClient.openSchemaBox); ClientHelperRepository clientHelperRepository = ClientHelperRepository(httpClient: httpClientMock); HelperGroupUserVisitRepository remoteVisitRepository = HelperGroupUserVisitHttpRepository(httpClient: httpClientMock); @@ -40,7 +43,8 @@ void main() { clientSchemaRepository: clientSchemaRepository, helperRemoteRepository: clientHelperRepository, localVisitRepository: localVisitRepository, - remoteVisitRepository: remoteVisitRepository + remoteVisitRepository: remoteVisitRepository, + userLocale: localeServiceMock ); var schema = SchemaEntity( projectId: "testprojectid", @@ -97,28 +101,28 @@ void main() { }); test('current page = route1, user already see helper id = g2 => returns helper group id g1', () async { - var nextHelperGroup = await helperClientService.getPageNextHelper('route1', inAppUserId, AppVersion.fromString('1.0.1')); - expect(nextHelperGroup.priority, equals(1)); + var nextHelperGroup = await (helperClientService.getPageNextHelper('route1', inAppUserId, AppVersion.fromString('1.0.1'))); + expect(nextHelperGroup!.priority, equals(1)); expect(nextHelperGroup.id, equals("g1")); - expect(nextHelperGroup.page.route, equals('route1')); + expect(nextHelperGroup.page!.route, equals('route1')); }); test('current page = route2, user has not see anything => returns ON_SCREEN_VISIT type, group g4', () async { - var nextHelperGroup = await helperClientService.getPageNextHelper('route2', inAppUserId, AppVersion.fromString('1.0.1')); - expect(nextHelperGroup.id, equals("g4")); + var nextHelperGroup = await (helperClientService.getPageNextHelper('route2', inAppUserId, AppVersion.fromString('1.0.1'))); + expect(nextHelperGroup!.id, equals("g4")); expect(nextHelperGroup.triggerType, equals(HelperTriggerType.ON_SCREEN_VISIT)); - expect(nextHelperGroup.page.route, equals('route2')); + expect(nextHelperGroup.page!.route, equals('route2')); }); test('''current page = route3, user see all ON_SCREEN_VISIT, first ON_NEW_UPDATE min version = 1.0.1 user app version = 1.0.1 => returns ON_NEW_UPDATE type with lower prio, group g7''', () async { - var nextHelperGroup = await helperClientService.getPageNextHelper('route3', inAppUserId, AppVersion.fromString('1.0.1')); - expect(nextHelperGroup.id, equals("g7")); + var nextHelperGroup = await (helperClientService.getPageNextHelper('route3', inAppUserId, AppVersion.fromString('1.0.1'))); + expect(nextHelperGroup!.id, equals("g7")); expect(nextHelperGroup.triggerType, equals(HelperTriggerType.ON_NEW_UPDATE)); expect(nextHelperGroup.priority, equals(1)); - expect(nextHelperGroup.page.route, equals('route3')); + expect(nextHelperGroup.page!.route, equals('route3')); }); test('''current page = route4, user see all ON_SCREEN_VISIT, @@ -149,9 +153,9 @@ void main() { first ON_NEW_UPDATE id g10 min version = 0.1.0 max is null user app version = 0.5.0 => returns group g10''', () async { - var nextHelperGroup = await helperClientService.getPageNextHelper('route6', inAppUserId, AppVersion.fromString('0.5.0')); + var nextHelperGroup = await (helperClientService.getPageNextHelper('route6', inAppUserId, AppVersion.fromString('0.5.0'))); expect(nextHelperGroup, isNotNull); - expect(nextHelperGroup.id, equals("g10")); + expect(nextHelperGroup!.id, equals("g10")); }); test('route not exists, return null', () async { @@ -197,19 +201,21 @@ void main() { var pageId = 'p1'; var helperGroup = HelperGroupEntity(id: "g1", priority: 1, page: PageEntity(id: 'p1', route: 'route1'), helpers: [HelperEntity(id: "1")]); var helperGroupId = helperGroup.id; - var url = 'pal-analytic/users/$inAppUserId/groups/$helperGroupId/helpers/${helperGroup.helpers[0].id}'; + var url = 'pal-analytic/users/$inAppUserId/groups/$helperGroupId/helpers/${helperGroup.helpers![0].id}'; var expectedBody = jsonEncode({ 'answer': true, 'isLast': true, 'language': 'en' }); - when(httpClientMock.post(Uri.parse(url), + when(() => httpClientMock.post(Uri.parse(url), body: expectedBody, headers: {"inAppUserId": inAppUserId}) - ).thenAnswer((_) => Future.value()); + ).thenAnswer((_) => Future.value(Response('', 200))); + var visitsBefore = await localVisitRepository.get(inAppUserId, null); + expect(visitsBefore.length, equals(1)); - await helperClientService.onHelperTrigger(pageId, helperGroup, helperGroup.helpers[0], inAppUserId, true, '1.0.0'); - verify(httpClientMock.post(Uri.parse(url), + await helperClientService.onHelperTrigger(pageId, helperGroup, helperGroup.helpers![0], inAppUserId, true, '1.0.0'); + verify(() => httpClientMock.post(Uri.parse(url), body: expectedBody, headers: {"inAppUserId": inAppUserId}) ).called(1); @@ -223,19 +229,19 @@ void main() { var pageId = 'p1'; var helperGroup = HelperGroupEntity(id: "g1", priority: 1, page: PageEntity(id: 'p1', route: 'route1'), helpers: [HelperEntity(id: "1")]); var helperGroupId = helperGroup.id; - var url = 'pal-analytic/users/$inAppUserId/groups/$helperGroupId/helpers/${helperGroup.helpers[0].id}'; + var url = 'pal-analytic/users/$inAppUserId/groups/$helperGroupId/helpers/${helperGroup.helpers![0].id}'; var expectedBody = jsonEncode({ 'answer': true, 'isLast': true, 'language': 'en' }); - when(httpClientMock.post(Uri.parse(url), + when(() => httpClientMock.post(Uri.parse(url), body: expectedBody, headers: {"inAppUserId": inAppUserId}) ).thenThrow((_) => throw "ERROR"); - await helperClientService.onHelperTrigger(pageId, helperGroup, helperGroup.helpers[0], inAppUserId, true, '1.0.0'); - verify(httpClientMock.post(Uri.parse(url), + await helperClientService.onHelperTrigger(pageId, helperGroup, helperGroup.helpers![0], inAppUserId, true, '1.0.0'); + verify(() => httpClientMock.post(Uri.parse(url), body: expectedBody, headers: {"inAppUserId": inAppUserId}) ).called(1); diff --git a/test/services/client/in_app_user/in_app_user_client_service_test.dart b/test/services/client/in_app_user/in_app_user_client_service_test.dart index f00fcffa..41412bc9 100644 --- a/test/services/client/in_app_user/in_app_user_client_service_test.dart +++ b/test/services/client/in_app_user/in_app_user_client_service_test.dart @@ -2,8 +2,9 @@ import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/in_app_user_entity.dart'; +import 'package:pal/src/database/hive_client.dart'; import 'package:pal/src/database/repository/in_app_user_repository.dart'; import 'package:pal/src/services/client/in_app_user/in_app_user_client_service.dart'; import 'package:pal/src/services/client/in_app_user/in_app_user_client_storage.dart'; @@ -11,27 +12,36 @@ import 'package:pal/src/services/http_client/base_client.dart'; class _HttpClientMock extends Mock implements HttpClient{} -class _InAppUserStorageClientManagerMock extends Mock implements InAppUserStorageClientManager{} - void main() { group('Test in app user service', () { + HiveClient hiveClient = HiveClient(shouldInit: false) + ..initLocal(); + final storageClient = InAppUserLocalRepository(hiveClient.openInAppUserBox); - test('Test get and create in app user => in app user already created', () async { + setUpAll(() { + registerFallbackValue(InAppUserEntity()); + }); + setUp(() async { + await storageClient.clearInAppUser(); + }); + + test('Test get and create in app user => in app user already created', () async { final HttpClient httpClient = _HttpClientMock(); + // final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - when(mockedInAppUserStorageClientManager.readInAppUser()).thenAnswer((_) => Future.value(InAppUserEntity( + await storageClient.storeInAppUser(InAppUserEntity( id: "db6b01e1-b649-4a17-949a-9ab320601001", inAppId: "test", disabledHelpers: false, anonymous: false, - ))); + )); final InAppUserRepository inAppUserRepository = InAppUserRepository(httpClient: httpClient); - final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, inAppUserStorageClientManager: mockedInAppUserStorageClientManager); + final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, storageClient); + final InAppUserEntity inAppUserEntity = await inAppUserClientService.getOrCreate(); assert(inAppUserEntity.id == "db6b01e1-b649-4a17-949a-9ab320601001"); assert(inAppUserEntity.inAppId == "test"); @@ -44,13 +54,10 @@ void main() { final HttpClient httpClient = _HttpClientMock(); final String content = new File("test/services/client/in_app_user/resources/in_app_user_anonymous.json").readAsStringSync(); final String expectedBody = new File("test/services/client/in_app_user/resources/in_app_user_create_body.json").readAsStringSync(); - when(httpClient.post(Uri.parse("pal-analytic/in-app-users"), body: expectedBody)).thenAnswer((_) => Future.value(Response(content, 200))); - - final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - when(mockedInAppUserStorageClientManager.readInAppUser()).thenAnswer((_) => Future.value(null)); + when(() => httpClient.post(Uri.parse("pal-analytic/in-app-users"), body: expectedBody)).thenAnswer((_) => Future.value(Response(content, 200))); final InAppUserRepository inAppUserRepository = InAppUserRepository(httpClient: httpClient); - final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, inAppUserStorageClientManager: mockedInAppUserStorageClientManager); + final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository,storageClient); final InAppUserEntity inAppUserEntity = await inAppUserClientService.getOrCreate(); assert(inAppUserEntity.id == "db6b01e1-b649-4a17-949a-9ab320601001"); assert(inAppUserEntity.inAppId == null); @@ -63,48 +70,45 @@ void main() { final HttpClient httpClient = _HttpClientMock(); - final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - when(mockedInAppUserStorageClientManager.readInAppUser()).thenAnswer((_) => Future.value(InAppUserEntity( + await storageClient.storeInAppUser(InAppUserEntity( id: "db6b01e1-b649-4a17-949a-9ab320601001", inAppId: "test", disabledHelpers: false, anonymous: false, - ))); + )); final InAppUserRepository inAppUserRepository = InAppUserRepository(httpClient: httpClient); - final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, inAppUserStorageClientManager: mockedInAppUserStorageClientManager); - final InAppUserEntity inAppUserEntity = await inAppUserClientService.onConnect("test"); - assert(inAppUserEntity.id == "db6b01e1-b649-4a17-949a-9ab320601001"); - assert(inAppUserEntity.inAppId == "test"); - assert(inAppUserEntity.disabledHelpers == false); - assert(inAppUserEntity.anonymous == false); + final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, storageClient); + final InAppUserEntity? inAppUserEntity = await inAppUserClientService.onConnect("test"); + assert(inAppUserEntity!.id == "db6b01e1-b649-4a17-949a-9ab320601001"); + assert(inAppUserEntity!.inAppId == "test"); + assert(inAppUserEntity!.disabledHelpers == false); + assert(inAppUserEntity!.anonymous == false); }); test('Test on connect => anonymous', () async { final HttpClient httpClient = _HttpClientMock(); + final inAppUser = InAppUserEntity( + id: "db6b01e1-b649-4a17-949a-9ab320601001", + inAppId: "test", + disabledHelpers: false, + anonymous: false, + ); final String content = new File("test/services/client/in_app_user/resources/in_app_user.json").readAsStringSync(); final String expectedBody = new File("test/services/client/in_app_user/resources/in_app_user_on_connect_body.json").readAsStringSync(); - when(httpClient.put(Uri.parse("pal-analytic/in-app-users/db6b01e1-b649-4a17-949a-9ab320601001"), body: expectedBody)).thenAnswer((_) => Future.value(Response(content, 200))); + when(() => httpClient.put(Uri.parse("pal-analytic/in-app-users/db6b01e1-b649-4a17-949a-9ab320601001"), body: expectedBody)) + .thenAnswer((_) => Future.value(Response(content, 200))); - - final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - when(mockedInAppUserStorageClientManager.readInAppUser()).thenAnswer((_) { - return Future.value(InAppUserEntity( - id: "db6b01e1-b649-4a17-949a-9ab320601001", - inAppId: null, - disabledHelpers: false, - anonymous: true, - )); - }); + await storageClient.storeInAppUser(inAppUser); final InAppUserRepository inAppUserRepository = InAppUserRepository(httpClient: httpClient); - final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, inAppUserStorageClientManager: mockedInAppUserStorageClientManager); - final InAppUserEntity inAppUserEntity = await inAppUserClientService.onConnect("test"); - assert(inAppUserEntity.id == "db6b01e1-b649-4a17-949a-9ab320601001"); - assert(inAppUserEntity.inAppId == "test"); - assert(inAppUserEntity.disabledHelpers == false); - assert(inAppUserEntity.anonymous == false); + final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, storageClient); + final InAppUserEntity? inAppUserEntity = await inAppUserClientService.onConnect("test"); + assert(inAppUserEntity!.id == "db6b01e1-b649-4a17-949a-9ab320601001"); + assert(inAppUserEntity!.inAppId == "test"); + assert(inAppUserEntity!.disabledHelpers == false); + assert(inAppUserEntity!.anonymous == false); }); @@ -112,12 +116,9 @@ void main() { final HttpClient httpClient = _HttpClientMock(); - final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - when(mockedInAppUserStorageClientManager.readInAppUser()).thenAnswer((_) => Future.value(null)); - final InAppUserRepository inAppUserRepository = InAppUserRepository(httpClient: httpClient); - final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, inAppUserStorageClientManager: mockedInAppUserStorageClientManager); - final InAppUserEntity inAppUserEntity = await inAppUserClientService.update(true); + final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, storageClient); + final InAppUserEntity? inAppUserEntity = await inAppUserClientService.update(true); assert(inAppUserEntity == null); }); @@ -126,76 +127,67 @@ void main() { final HttpClient httpClient = _HttpClientMock(); final String content = new File("test/services/client/in_app_user/resources/in_app_user.json").readAsStringSync(); final String expectedBody = new File("test/services/client/in_app_user/resources/in_app_user_update_body.json").readAsStringSync(); - when(httpClient.put(Uri.parse("pal-analytic/in-app-users/db6b01e1-b649-4a17-949a-9ab320601001"), body: expectedBody)).thenAnswer((_) => Future.value(Response(content, 200))); + when(() => httpClient.put(Uri.parse("pal-analytic/in-app-users/db6b01e1-b649-4a17-949a-9ab320601001"), body: expectedBody)).thenAnswer((_) => Future.value(Response(content, 200))); - - final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - when(mockedInAppUserStorageClientManager.readInAppUser()).thenAnswer((_) { - return Future.value(InAppUserEntity( + var user = InAppUserEntity( id: "db6b01e1-b649-4a17-949a-9ab320601001", inAppId: null, disabledHelpers: false, - anonymous: true, - )); - }); + anonymous: true); + + await storageClient.storeInAppUser(user); final InAppUserRepository inAppUserRepository = InAppUserRepository(httpClient: httpClient); - final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, inAppUserStorageClientManager: mockedInAppUserStorageClientManager); - final InAppUserEntity inAppUserEntity = await inAppUserClientService.update(false); - assert(inAppUserEntity.id == "db6b01e1-b649-4a17-949a-9ab320601001"); - assert(inAppUserEntity.inAppId == "test"); - assert(inAppUserEntity.disabledHelpers == false); - assert(inAppUserEntity.anonymous == false); + final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, storageClient); + final InAppUserEntity? inAppUserEntity = await inAppUserClientService.update(false); + assert(inAppUserEntity!.id == "db6b01e1-b649-4a17-949a-9ab320601001"); + assert(inAppUserEntity!.inAppId == "test"); + assert(inAppUserEntity!.disabledHelpers == false); + assert(inAppUserEntity!.anonymous == false); }); test('Test disconnected => not anonymous user', () async { - final HttpClient httpClient = _HttpClientMock(); final String content = new File("test/services/client/in_app_user/resources/in_app_user_anonymous.json").readAsStringSync(); final String expectedBody = new File("test/services/client/in_app_user/resources/in_app_user_create_body.json").readAsStringSync(); - when(httpClient.post(Uri.parse("pal-analytic/in-app-users"), body: expectedBody)).thenAnswer((_) => Future.value(Response(content, 200))); + when(() => httpClient.post(Uri.parse("pal-analytic/in-app-users"), body: expectedBody)).thenAnswer((_) => Future.value(Response(content, 200))); - - final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - when(mockedInAppUserStorageClientManager.readInAppUser()).thenAnswer((_) { - return Future.value(InAppUserEntity( + var user = InAppUserEntity( id: "db6b01e1-b649-4a17-949a-9ab320601001", inAppId: 'test', disabledHelpers: false, - anonymous: false, - )); - }); + anonymous: false); + + await storageClient.storeInAppUser(user); final InAppUserRepository inAppUserRepository = InAppUserRepository(httpClient: httpClient); - final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, inAppUserStorageClientManager: mockedInAppUserStorageClientManager); - final InAppUserEntity inAppUserEntity = await inAppUserClientService.onDisconnect(); - assert(inAppUserEntity.id == "db6b01e1-b649-4a17-949a-9ab320601001"); - assert(inAppUserEntity.inAppId == null); - assert(inAppUserEntity.disabledHelpers == false); - assert(inAppUserEntity.anonymous == true); + final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, storageClient); + final InAppUserEntity? inAppUserEntity = await inAppUserClientService.onDisconnect(); + assert(inAppUserEntity!.id == "db6b01e1-b649-4a17-949a-9ab320601001"); + assert(inAppUserEntity!.inAppId == null); + assert(inAppUserEntity!.disabledHelpers == false); + assert(inAppUserEntity!.anonymous == true); }); test('Test disconnected => anonymous user', () async { final HttpClient httpClient = _HttpClientMock(); - final InAppUserStorageClientManager mockedInAppUserStorageClientManager = _InAppUserStorageClientManagerMock(); - when(mockedInAppUserStorageClientManager.readInAppUser()).thenAnswer((_) { - return Future.value(InAppUserEntity( + await storageClient.storeInAppUser(InAppUserEntity( id: "db6b01e1-b649-4a17-949a-9ab320601001", inAppId: 'test', disabledHelpers: false, anonymous: true, - )); - }); + ) + ); final InAppUserRepository inAppUserRepository = InAppUserRepository(httpClient: httpClient); - final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, inAppUserStorageClientManager: mockedInAppUserStorageClientManager); - final InAppUserEntity inAppUserEntity = await inAppUserClientService.onDisconnect(); - assert(inAppUserEntity.id == "db6b01e1-b649-4a17-949a-9ab320601001"); - assert(inAppUserEntity.inAppId == "test"); - assert(inAppUserEntity.disabledHelpers == false); - assert(inAppUserEntity.anonymous == true); + final InAppUserClientService inAppUserClientService = InAppUserClientService.build(inAppUserRepository, storageClient); + final InAppUserEntity? inAppUserEntity = await inAppUserClientService.onDisconnect(); + assert(inAppUserEntity!.id == "db6b01e1-b649-4a17-949a-9ab320601001"); + assert(inAppUserEntity!.inAppId == "test"); + assert(inAppUserEntity!.disabledHelpers == false); + assert(inAppUserEntity!.anonymous == true); }); }); } diff --git a/test/services/editor/finder/finder_service_test.dart b/test/services/editor/finder/finder_service_test.dart index 443d91d3..e107ac55 100644 --- a/test/services/editor/finder/finder_service_test.dart +++ b/test/services/editor/finder/finder_service_test.dart @@ -10,7 +10,7 @@ void main() { final _navigatorKey = GlobalKey(); - FinderService finderService; + FinderService? finderService; _createPage(int n) { return Scaffold( @@ -43,35 +43,35 @@ void main() { }; await initAppWithPal(tester, null, _navigatorKey, routeFactory: routeFactory); // go to page 2 - Navigator.of(_navigatorKey.currentContext).pushNamed("/page1"); + Navigator.of(_navigatorKey.currentContext!).pushNamed("/page1"); await tester.pumpAndSettle(Duration(milliseconds: 500)); expect(find.byKey(ValueKey("p0Text1")), findsNothing); expect(find.byKey(ValueKey("p1Text1")), findsOneWidget); - finderService = EditorInjector.of(_navigatorKey.currentContext).finderService; + finderService = EditorInjector.of(_navigatorKey.currentContext!)!.finderService; expect(finderService, isNotNull); } testWidgets('only current page items should be available', (WidgetTester tester) async { await _before(tester); - var element = await finderService.searchChildElement("p0Text1"); + var element = await finderService!.searchChildElement("p0Text1"); expect(element.element, isNull); - var element2 = await finderService.searchChildElement("p1Text1"); + var element2 = await finderService!.searchChildElement("p1Text1"); expect(element2.element, isNotNull); }); testWidgets('after pop, we find only p0Text', (WidgetTester tester) async { await _before(tester); - Navigator.of(_navigatorKey.currentContext).pop(); + Navigator.of(_navigatorKey.currentContext!).pop(); await tester.pumpAndSettle(Duration(milliseconds: 500)); - var element = await finderService.searchChildElement("p0Text1"); + var element = await finderService!.searchChildElement("p0Text1"); expect(element.element, isNotNull); - var element2 = await finderService.searchChildElement("p1Text1"); + var element2 = await finderService!.searchChildElement("p1Text1"); expect(element2.element, isNull); }); testWidgets('scan should find only page1 items', (WidgetTester tester) async { await _before(tester); - var element = await finderService.scan(); + var element = await finderService!.scan(); expect(element.keys.contains("[<'p0Text1'>]"), isFalse); expect(element.keys.contains("[<'p0Text2'>]"), isFalse); expect(element.keys.contains("[<'p0Text3'>]"), isFalse); diff --git a/test/services/editor/helper/anchored_model_data.dart b/test/services/editor/helper/anchored_model_data.dart index ea054e79..0111fed9 100644 --- a/test/services/editor/helper/anchored_model_data.dart +++ b/test/services/editor/helper/anchored_model_data.dart @@ -4,7 +4,7 @@ import 'package:pal/src/database/entity/helper/helper_type.dart'; import 'package:pal/src/services/editor/helper/helper_editor_models.dart'; import 'package:pal/src/ui/shared/helper_shared_factory.dart'; -generateAnchoredHelperData({HelperGroupConfig helperGroupConfig}) +generateAnchoredHelperData({HelperGroupConfig? helperGroupConfig}) => CreateAnchoredHelper( helperGroup: helperGroupConfig ?? HelperGroupConfig( id: "3872983729JJF" @@ -58,42 +58,42 @@ genExpectedHelperEntity(CreateAnchoredHelper args) priority: 1, helperTexts: [ HelperTextEntity( - value: args.title.text, - fontColor: args.title.fontColor, - fontWeight: args.title.fontWeight, - fontSize: args.title.fontSize, - fontFamily: args.title.fontFamily, + value: args.title!.text, + fontColor: args.title!.fontColor, + fontWeight: args.title!.fontWeight, + fontSize: args.title!.fontSize, + fontFamily: args.title!.fontFamily, key: AnchoredscreenHelperKeys.TITLE_KEY, ), HelperTextEntity( - value: args.description.text, - fontColor: args.description.fontColor, - fontWeight: args.description.fontWeight, - fontSize: args.description.fontSize, - fontFamily: args.description.fontFamily, + value: args.description!.text, + fontColor: args.description!.fontColor, + fontWeight: args.description!.fontWeight, + fontSize: args.description!.fontSize, + fontFamily: args.description!.fontFamily, key: AnchoredscreenHelperKeys.DESCRIPTION_KEY, ), HelperTextEntity( - value: args.positivButton.text, - fontColor: args.positivButton.fontColor, - fontWeight: args.positivButton.fontWeight, - fontSize: args.positivButton.fontSize, - fontFamily: args.positivButton.fontFamily, + value: args.positivButton!.text, + fontColor: args.positivButton!.fontColor, + fontWeight: args.positivButton!.fontWeight, + fontSize: args.positivButton!.fontSize, + fontFamily: args.positivButton!.fontFamily, key: AnchoredscreenHelperKeys.POSITIV_KEY, ), HelperTextEntity( - value: args.negativButton.text, - fontColor: args.negativButton.fontColor, - fontWeight: args.negativButton.fontWeight, - fontSize: args.negativButton.fontSize, - fontFamily: args.negativButton.fontFamily, + value: args.negativButton!.text, + fontColor: args.negativButton!.fontColor, + fontWeight: args.negativButton!.fontWeight, + fontSize: args.negativButton!.fontSize, + fontFamily: args.negativButton!.fontFamily, key: AnchoredscreenHelperKeys.NEGATIV_KEY, ), ], helperBoxes: [ HelperBoxEntity( - key: args.bodyBox.key, - backgroundColor: args.bodyBox.color, + key: args.bodyBox!.key, + backgroundColor: args.bodyBox!.color, ) ] ); diff --git a/test/services/editor/helper/fullscreen_model_data.dart b/test/services/editor/helper/fullscreen_model_data.dart index 0a57a487..93bb5905 100644 --- a/test/services/editor/helper/fullscreen_model_data.dart +++ b/test/services/editor/helper/fullscreen_model_data.dart @@ -4,7 +4,7 @@ import 'package:pal/src/database/entity/helper/helper_type.dart'; import 'package:pal/src/services/editor/helper/helper_editor_models.dart'; import 'package:pal/src/ui/shared/helper_shared_factory.dart'; -genFullscreenModel({HelperGroupConfig groupConfig}) +genFullscreenModel({HelperGroupConfig? groupConfig}) => CreateFullScreenHelper( helperGroup: groupConfig ?? HelperGroupConfig( id: "3872983729JJF" @@ -43,25 +43,25 @@ genExpectedFullscreenEntity(CreateFullScreenHelper args) priority: 1, helperTexts: [ HelperTextEntity( - value: args.title.text, - fontColor: args.title.fontColor, - fontWeight: args.title.fontWeight, - fontSize: args.title.fontSize, - fontFamily: args.title.fontFamily, + value: args.title!.text, + fontColor: args.title!.fontColor, + fontWeight: args.title!.fontWeight, + fontSize: args.title!.fontSize, + fontFamily: args.title!.fontFamily, key: FullscreenHelperKeys.TITLE_KEY, ), HelperTextEntity( - value: args.description.text, - fontColor: args.description.fontColor, - fontWeight: args.description.fontWeight, - fontSize: args.description.fontSize, - fontFamily: args.description.fontFamily, + value: args.description!.text, + fontColor: args.description!.fontColor, + fontWeight: args.description!.fontWeight, + fontSize: args.description!.fontSize, + fontFamily: args.description!.fontFamily, key: FullscreenHelperKeys.DESCRIPTION_KEY, ), ], helperImages: [ HelperImageEntity( - url: args.mediaHeader.url, + url: args.mediaHeader!.url, key: FullscreenHelperKeys.IMAGE_KEY, ) ], diff --git a/test/services/editor/helper/helper_editor_service_test.dart b/test/services/editor/helper/helper_editor_service_test.dart index 210382aa..28dea62a 100644 --- a/test/services/editor/helper/helper_editor_service_test.dart +++ b/test/services/editor/helper/helper_editor_service_test.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/adapter/helper_entity_adapter.dart' as EntityAdapter; import 'package:pal/src/database/adapter/page_entity_adapter.dart' as PageEntityAdapter; import 'package:pal/src/database/adapter/version_entity_adapter.dart' as VersionEntityAdapter; @@ -42,18 +42,18 @@ void main() { var pageResJson = PageEntityAdapter.PageEntityAdapter().toJson(existingPage); var pageablePageResJson = '{"content":[$pageResJson], "numberOfElements":1, "first":true, "last": true, "totalPages":1, "totalElements":1, "pageable": { "offset":1, "pageNumber":1, "pageSize":1 }}'; //var pageReqJson = jsonEncode({'name': args.config.route}); - when(httpClientMock.get(Uri.parse('pal-business/editor/pages?route=${args.config.route}&pageSize=1'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages?route=${args.config.route}&pageSize=1'))) .thenAnswer((_) => Future.value(Response(pageablePageResJson, 200))); // mock save helper var expectedHelperResultJson = EntityAdapter.HelperEntityAdapter().toJson(expectedHelperResult..id = null); - when(httpClientMock.post(Uri.parse('pal-business/editor/groups/${args.helperGroup.id}/helpers'), body: anyNamed("body"))) + when(() => httpClientMock.post(Uri.parse('pal-business/editor/groups/${args.helperGroup.id}/helpers'), body: any(named: "body"))) .thenAnswer((_) => Future.value(Response(expectedHelperResultJson, 200))); await creationCall(); // group exists here and should not been called - verifyNever(httpClientMock.post(Uri.parse('pal-business/editor/pages/${existingPage.id}/groups'), body: captureAnyNamed("body"))); - var capturedCall = verify( + verifyNever(() => httpClientMock.post(Uri.parse('pal-business/editor/pages/${existingPage.id}/groups'), body: captureAny(named: "body"))); + var capturedCall = verify(() => httpClientMock.post(Uri.parse('pal-business/editor/groups/${args.helperGroup.id}/helpers'), - body: captureAnyNamed("body")) + body: captureAny(named: "body")) ).captured; expect(capturedCall[0], equals(expectedHelperResultJson)); } @@ -66,34 +66,34 @@ void main() { var pageResJson = PageEntityAdapter.PageEntityAdapter().toJson(existingPage); var pageablePageResJson = '{"content":[], "numberOfElements":1, "first":true, "last": true, "totalPages":1, "totalElements":1, "pageable": { "offset":1, "pageNumber":1, "pageSize":1 }}'; var pageCreationReqJson = jsonEncode({'route': args.config.route}); - when(httpClientMock.get(Uri.parse('pal-business/editor/pages?route=${args.config.route}&pageSize=1'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages?route=${args.config.route}&pageSize=1'))) .thenAnswer((_) => Future.value(Response(pageablePageResJson, 200))); - when(httpClientMock.post(Uri.parse('pal-business/editor/pages'), body: pageCreationReqJson)).thenAnswer((_) => Future.value(Response(pageResJson, 200))); + when(() => httpClientMock.post(Uri.parse('pal-business/editor/pages'), body: pageCreationReqJson)).thenAnswer((_) => Future.value(Response(pageResJson, 200))); // mock create group var groupCreationReqJson = '{"name":"${args.helperGroup.name}","triggerType":null,"versionMinId":25,"versionMaxId":null}'; var groupCreationResJson = '{"id":"89032803JS", "name":"${args.helperGroup.name}", "minVersionId": 25, "maxVersionId": null}'; - when(httpClientMock.post(Uri.parse('pal-business/editor/pages/${existingPage.id}/groups'), body: anyNamed('body'))) + when(() => httpClientMock.post(Uri.parse('pal-business/editor/pages/${existingPage.id}/groups'), body: any(named: 'body'))) .thenAnswer((_) => Future.value(Response(groupCreationResJson, 200))); // mock get min version request then create VersionEntity versionEntity = VersionEntity(id: 25, name: args.helperGroup.minVersion); var versionReqJson = VersionEntityAdapter.VersionEntityAdapter().toJson(versionEntity); var versionMinCreationReqJson = jsonEncode({'name': args.helperGroup.minVersion}); var versionPageJson = '{"content":[], "numberOfElements":1, "first":true, "last": true, "totalPages":1, "totalElements":1, "pageable": { "offset":1, "pageNumber":1, "pageSize":1 }}'; - when(httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=${args.helperGroup.minVersion}&pageSize=1'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=${args.helperGroup.minVersion}&pageSize=1'))) .thenAnswer((_) => Future.value(Response(versionPageJson, 200))); - when(httpClientMock.post(Uri.parse('pal-business/editor/versions'), body: versionMinCreationReqJson)).thenAnswer((_) => Future.value(Response(versionReqJson, 200))); + when(() => httpClientMock.post(Uri.parse('pal-business/editor/versions'), body: versionMinCreationReqJson)).thenAnswer((_) => Future.value(Response(versionReqJson, 200))); // mock save helper var expectedHelperResultJson = EntityAdapter.HelperEntityAdapter().toJson(expectedHelperRequest); - when(httpClientMock.post(Uri.parse('pal-business/editor/groups/89032803JS/helpers'), body: anyNamed("body"))) + when(() => httpClientMock.post(Uri.parse('pal-business/editor/groups/89032803JS/helpers'), body: any(named: "body"))) .thenAnswer((_) => Future.value(Response(expectedHelperResultJson, 200))); await creationCall(); - verify(httpClientMock.get(Uri.parse('pal-business/editor/pages?route=${args.config.route}&pageSize=1'))).called(1); - verify(httpClientMock.post(Uri.parse('pal-business/editor/pages'), body: pageCreationReqJson)).called(1); - verify(httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=${args.helperGroup.minVersion}&pageSize=1'))).called(1); - verify(httpClientMock.post(Uri.parse('pal-business/editor/versions'), body: versionMinCreationReqJson)).called(1); - var capturedGroupCreationCall = verify(httpClientMock.post(Uri.parse('pal-business/editor/pages/${existingPage.id}/groups'), body: captureAnyNamed("body"))).captured; + verify(() => httpClientMock.get(Uri.parse('pal-business/editor/pages?route=${args.config.route}&pageSize=1'))).called(1); + verify(() => httpClientMock.post(Uri.parse('pal-business/editor/pages'), body: pageCreationReqJson)).called(1); + verify(() => httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=${args.helperGroup.minVersion}&pageSize=1'))).called(1); + verify(() => httpClientMock.post(Uri.parse('pal-business/editor/versions'), body: versionMinCreationReqJson)).called(1); + var capturedGroupCreationCall = verify(() => httpClientMock.post(Uri.parse('pal-business/editor/pages/${existingPage.id}/groups'), body: captureAny(named: "body"))).captured; expect(capturedGroupCreationCall[0], equals(groupCreationReqJson)); - var capturedHelperCreationCall = verify(httpClientMock.post(Uri.parse('pal-business/editor/groups/89032803JS/helpers'), body: captureAnyNamed("body"))).captured; + var capturedHelperCreationCall = verify(() => httpClientMock.post(Uri.parse('pal-business/editor/groups/89032803JS/helpers'), body: captureAny(named: "body"))).captured; expect(capturedHelperCreationCall[0], equals(expectedHelperResultJson)); } @@ -104,27 +104,30 @@ void main() { var pageResJson = PageEntityAdapter.PageEntityAdapter().toJson(existingPage); var pageablePageResJson = '{"content":[$pageResJson], "numberOfElements":1, "first":true, "last": true, "totalPages":1, "totalElements":1, "pageable": { "offset":1, "pageNumber":1, "pageSize":1 }}'; //var pageReqJson = jsonEncode({'name': args.config.route}); - when(httpClientMock.get(Uri.parse('pal-business/editor/pages?route=${args.config.route}&pageSize=1'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages?route=${args.config.route}&pageSize=1'))) .thenAnswer((_) => Future.value(Response(pageablePageResJson, 200))); // mock get min version request VersionEntity versionEntity = VersionEntity(id: 25, name: args.helperGroup.minVersion); var versionReqJson = VersionEntityAdapter.VersionEntityAdapter().toJson(versionEntity); var versionPageJson = '{"content":[$versionReqJson], "numberOfElements":1, "first":true, "last": true, "totalPages":1, "totalElements":1, "pageable": { "offset":1, "pageNumber":1, "pageSize":1 }}'; - when(httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=${args.helperGroup.minVersion}&pageSize=1'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=${args.helperGroup.minVersion}&pageSize=1'))) .thenAnswer((_) => Future.value(Response(versionPageJson, 200))); // mock save helper var expectedHelperResultJson = EntityAdapter.HelperEntityAdapter().toJson(expectedHelperResult..id = "JDLSKJDSD"); args.config.id = expectedHelperResult.id; - when(httpClientMock.put(Uri.parse('pal-business/editor/helpers/${args.config.id}'), body: anyNamed("body"))) + when(() => httpClientMock.put(Uri.parse('pal-business/editor/helpers/${args.config.id}'), body: any(named: "body"))) .thenAnswer((_) => Future.value(Response(expectedHelperResultJson, 200))); await updateCall(); // group exists here and should not been called - var capturedHelperCreation = verify(httpClientMock.put( + var capturedHelperCreation = verify(() => httpClientMock.put( Uri.parse('pal-business/editor/helpers/${args.config.id}'), - body: captureAnyNamed("body")) + body: captureAny(named: "body")) ).captured; expect(capturedHelperCreation[0], expectedHelperResultJson); - verifyNever(httpClientMock.post(Uri.parse('pal-business/editor/pages/${existingPage.id}/groups'), body: captureAnyNamed("body"))); + verifyNever(() => httpClientMock.post( + Uri.parse('pal-business/editor/pages/${existingPage.id}/groups'), + body: captureAny(named: "body")) + ); } group('[EditorHelperService] - save simpleHelper', () { diff --git a/test/services/editor/helper/simple_model_data.dart b/test/services/editor/helper/simple_model_data.dart index 9ddd7040..db9cdab6 100644 --- a/test/services/editor/helper/simple_model_data.dart +++ b/test/services/editor/helper/simple_model_data.dart @@ -4,7 +4,7 @@ import 'package:pal/src/database/entity/helper/helper_type.dart'; import 'package:pal/src/services/editor/helper/helper_editor_models.dart'; import 'package:pal/src/ui/shared/helper_shared_factory.dart'; -genSimpleHelperData({HelperGroupConfig groupConfig}) +genSimpleHelperData({HelperGroupConfig? groupConfig}) => CreateSimpleHelper( boxConfig: HelperBoxConfig(color: '#FFF'), titleText: HelperTextConfig( diff --git a/test/services/editor/helper/update_model_data.dart b/test/services/editor/helper/update_model_data.dart index 9814d681..ad9cc27c 100644 --- a/test/services/editor/helper/update_model_data.dart +++ b/test/services/editor/helper/update_model_data.dart @@ -4,7 +4,7 @@ import 'package:pal/src/database/entity/helper/helper_type.dart'; import 'package:pal/src/services/editor/helper/helper_editor_models.dart'; import 'package:pal/src/ui/shared/helper_shared_factory.dart'; -genUpdateModelData({HelperGroupConfig groupConfig}) +genUpdateModelData({HelperGroupConfig? groupConfig}) => CreateUpdateHelper( helperGroup: groupConfig ?? HelperGroupConfig( id: "3872983729JJF" @@ -51,11 +51,11 @@ genExpectedUpdateEntity(CreateUpdateHelper args) priority: 1, helperTexts: [ HelperTextEntity( - value: args.title.text, - fontColor: args.title.fontColor, - fontWeight: args.title.fontWeight, - fontSize: args.title.fontSize, - fontFamily: args.title.fontFamily, + value: args.title!.text, + fontColor: args.title!.fontColor, + fontWeight: args.title!.fontWeight, + fontSize: args.title!.fontSize, + fontFamily: args.title!.fontFamily, key: UpdatescreenHelperKeys.TITLE_KEY, ), HelperTextEntity( @@ -84,6 +84,6 @@ genExpectedUpdateEntity(CreateUpdateHelper args) helperBoxes: [ HelperBoxEntity( key: FullscreenHelperKeys.BACKGROUND_KEY, - backgroundColor: args.bodyBox.color, + backgroundColor: args.bodyBox!.color, ) ]); diff --git a/test/services/editor/versions/version_editor_service_test.dart b/test/services/editor/versions/version_editor_service_test.dart index 1a34507c..033b1e37 100644 --- a/test/services/editor/versions/version_editor_service_test.dart +++ b/test/services/editor/versions/version_editor_service_test.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/version_entity.dart'; import 'package:pal/src/database/repository/version_repository.dart'; import 'package:pal/src/services/package_version.dart'; @@ -63,8 +63,8 @@ void main() { "totalPages": 1 }; - when(packageVersionReaderMock.version).thenReturn(versionNumber); - when(httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=$versionNumber&pageSize=10'))) + when(() => packageVersionReaderMock.version).thenReturn(versionNumber); + when(() => httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=$versionNumber&pageSize=10'))) .thenAnswer((_) async => http.Response(jsonEncode(expectedModel), 200)); var currentVersionEntity = await versionEditorService.getCurrentVersion(); expect(currentVersionEntity, isNotNull); @@ -104,7 +104,7 @@ void main() { "totalElements": 3, "totalPages": 1 }; - when(httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=&pageSize=1000'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/versions?versionName=&pageSize=1000'))) .thenAnswer((_) async => http.Response(jsonEncode(expectedModel), 200)); List allVersions = await versionEditorService.getAll(); diff --git a/test/services/http_client/http_client_test.dart b/test/services/http_client/http_client_test.dart index d1f1896a..165f7aea 100644 --- a/test/services/http_client/http_client_test.dart +++ b/test/services/http_client/http_client_test.dart @@ -2,16 +2,20 @@ import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; -import 'package:mockito/mockito.dart'; +import 'package:http/http.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/services/http_client/base_client.dart'; +class MockClient extends Mock implements HttpClient {} -class MockHttpClient extends Mock implements http.Client {} +void main() { + setUpAll(() { + registerFallbackValue(Request("POST", Uri())); + }); -void main() { group('HttpClient tests with token', () { - var httpMockClient = new MockHttpClient(); + var httpMockClient = new MockClient(); var baseUrl = 'baseUrl'; HttpClient httpClient = new HttpClient.internal( @@ -26,14 +30,12 @@ void main() { testWidgets('GET, returning code 200 => sends request with token on correct url', (WidgetTester tester) async { await tester.runAsync(() async { - when(httpMockClient.send(any)).thenAnswer((_) => new Future( + when(() => httpMockClient.send(any())).thenAnswer((_) => new Future( () => new http.StreamedResponse(new Stream.fromFuture(Future>(() => [])), 200)) ); var res = await httpClient.get(Uri.parse('test')); - expect(true, res != null); expect(res.statusCode, 200); - - var capturedCall = verify(httpMockClient.send(captureAny)).captured; + var capturedCall = verify(() => httpMockClient.send(captureAny())).captured; expect(capturedCall[0].url.toString(), equals('$baseUrl/test')); expect(capturedCall[0].headers['Authorization'], equals('Bearer JLKJDLSJDLKSJDLSD')); }); @@ -41,14 +43,13 @@ void main() { testWidgets('POST, returning code 200 => sends request with token on correct url', (WidgetTester tester) async { await tester.runAsync(() async { - when(httpMockClient.send(any)).thenAnswer((_) => new Future( + when(() => httpMockClient.send(any())).thenAnswer((_) => new Future( () => new http.StreamedResponse(new Stream.fromFuture(Future>(() => [])), 200)) ); var res = await httpClient.post(Uri.parse('test')); - expect(true, res != null); expect(res.statusCode, 200); - - var capturedCall = verify(httpMockClient.send(captureAny)).captured; + + var capturedCall = verify(() => httpMockClient.send(captureAny())).captured; expect(capturedCall[0].url.toString(), equals('$baseUrl/test')); expect(capturedCall[0].headers['Authorization'], equals('Bearer JLKJDLSJDLKSJDLSD')); }); @@ -56,14 +57,13 @@ void main() { testWidgets('PUT, returning code 200 => sends request with token on correct url', (WidgetTester tester) async { await tester.runAsync(() async { - when(httpMockClient.send(any)).thenAnswer((_) => new Future( + when(() => httpMockClient.send(any())).thenAnswer((_) => new Future( () => new http.StreamedResponse(new Stream.fromFuture(Future>(() => [])), 200)) ); var res = await httpClient.put(Uri.parse('test')); - expect(true, res != null); expect(res.statusCode, 200); - var capturedCall = verify(httpMockClient.send(captureAny)).captured; + var capturedCall = verify(() => httpMockClient.send(captureAny())).captured; expect(capturedCall[0].url.toString(), equals('$baseUrl/test')); expect(capturedCall[0].headers['Authorization'], equals('Bearer JLKJDLSJDLKSJDLSD')); }); @@ -71,14 +71,13 @@ void main() { testWidgets('DELETE, returning code 200 => sends request with token on correct url', (WidgetTester tester) async { await tester.runAsync(() async { - when(httpMockClient.send(any)).thenAnswer((_) => new Future( + when(() => httpMockClient.send(any())).thenAnswer((_) => new Future( () => new http.StreamedResponse(new Stream.fromFuture(Future>(() => [])), 200)) ); var res = await httpClient.delete(Uri.parse('test')); - expect(true, res != null); expect(res.statusCode, 200); - var capturedCall = verify(httpMockClient.send(captureAny)).captured; + var capturedCall = verify(() => httpMockClient.send(captureAny())).captured; expect(capturedCall[0].url.toString(), equals('$baseUrl/test')); expect(capturedCall[0].headers['Authorization'], equals('Bearer JLKJDLSJDLKSJDLSD')); }); @@ -86,7 +85,7 @@ void main() { testWidgets('http 500 should throw InternalHttpError', (WidgetTester tester) async { await tester.runAsync(() async { - when(httpMockClient.send(any)).thenAnswer((_) => new Future( + when(() => httpMockClient.send(any())).thenAnswer((_) => new Future( () => new http.StreamedResponse(new Stream.fromFuture(Future>(() => [])), 500)) ); try { @@ -100,7 +99,7 @@ void main() { testWidgets('http 400 should throw UnreacheableHttpError', (WidgetTester tester) async { await tester.runAsync(() async { - when(httpMockClient.send(any)).thenAnswer((_) => new Future( + when(() => httpMockClient.send(any())).thenAnswer((_) => new Future( () => new http.StreamedResponse(new Stream.fromFuture(Future>(() => [])), 400)) ); try { diff --git a/test/ui/client/helper_mocks.dart b/test/ui/client/helper_mocks.dart index 3a2ef15d..bf743490 100644 --- a/test/ui/client/helper_mocks.dart +++ b/test/ui/client/helper_mocks.dart @@ -6,12 +6,12 @@ import 'package:pal/src/ui/shared/helper_shared_factory.dart'; abstract class MockHelperEntityBuilder { - HelperEntity create(String id, {String title}); + HelperEntity create(String id, {String? title}); } class MockFullscreenHelperEntityBuilder implements MockHelperEntityBuilder { @override - HelperEntity create(String id, {String title}) + HelperEntity create(String id, {String? title}) => HelperEntity( id: id, name: "helper name", diff --git a/test/ui/client/helper_orchestrator_test.dart b/test/ui/client/helper_orchestrator_test.dart index 53180388..e70daefe 100644 --- a/test/ui/client/helper_orchestrator_test.dart +++ b/test/ui/client/helper_orchestrator_test.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/helper/helper_entity.dart'; import 'package:pal/src/database/entity/helper/helper_group_entity.dart'; import 'package:pal/src/database/entity/in_app_user_entity.dart'; @@ -45,6 +45,12 @@ class SamplePage extends StatelessWidget { void main() { + + setUpAll(() { + registerFallbackValue(AppVersion.fromString("1.0.0")); + registerFallbackValue(HelperEntity()); + }); + group('HelperOrchestrator', () { var helperClientServiceMock = HelperClientServiceMock(); @@ -72,9 +78,10 @@ void main() { reset(inAppUserClientService); reset(helperClientServiceMock); reset(helperSynchronizer); - when(helperSynchronizer.sync(any, languageCode: anyNamed("languageCode"))).thenAnswer((_) => Future.value()); - when(packageVersionReader.version).thenReturn('1.0.0'); - when(packageVersionReader.appVersion).thenReturn(AppVersion.fromString('1.0.0')); + when(() => helperSynchronizer.sync(any(), languageCode: any(named: "languageCode"))) + .thenAnswer((_) => Future.value()); + when(() => packageVersionReader.version).thenReturn('1.0.0'); + when(() => packageVersionReader.appVersion).thenReturn(AppVersion.fromString('1.0.0')); }); testWidgets('should create properly and accessible from children', (WidgetTester tester) async { @@ -84,8 +91,9 @@ void main() { testWidgets('call helperService to get what needs to be shown on each route', (WidgetTester tester) async { final routeObserver = PalNavigatorObserver.instance(); - when(inAppUserClientService.getOrCreate()).thenAnswer((_) => Future.value(InAppUserEntity(id: "db6b01e1-b649-4a17-949a-9ab320601001", disabledHelpers: false, anonymous: true))); - when(helperClientServiceMock.getPageNextHelper(any, any, any)).thenAnswer((_) => Future.value()); + when(() => inAppUserClientService.getOrCreate()).thenAnswer((_) => Future.value(InAppUserEntity(id: "db6b01e1-b649-4a17-949a-9ab320601001", disabledHelpers: false, anonymous: true))); + when(() => helperClientServiceMock.getPageNextHelper(any(), any(), any())) + .thenAnswer((_) => Future.value()); var orchestrator = HelperOrchestrator.create( helperClientService: helperClientServiceMock, @@ -103,14 +111,14 @@ void main() { // navigatorKey.currentState.pushNamed("/test1"); // expect(find.text("New1"), findsOneWidget); await orchestrator.onChangePage("/test1"); - verify(helperClientServiceMock.getPageNextHelper("/test1", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))).called(1); - verify(helperSynchronizer.sync("db6b01e1-b649-4a17-949a-9ab320601001", languageCode: "en")).called(1); + verify(() => helperClientServiceMock.getPageNextHelper("/test1", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))).called(1); + verify(() => helperSynchronizer.sync("db6b01e1-b649-4a17-949a-9ab320601001", languageCode: "en")).called(1); await tester.pumpAndSettle(Duration(seconds: 1)); }); testWidgets('changing page will dismiss current helper, sync helpers schema is not call again', (WidgetTester tester) async { final routeObserver = PalNavigatorObserver.instance(); - when(inAppUserClientService.getOrCreate()).thenAnswer((_) => Future.value(InAppUserEntity(id: "db6b01e1-b649-4a17-949a-9ab320601001", disabledHelpers: false, anonymous: true))); + when(() => inAppUserClientService.getOrCreate()).thenAnswer((_) => Future.value(InAppUserEntity(id: "db6b01e1-b649-4a17-949a-9ab320601001", disabledHelpers: false, anonymous: true))); HelperEntity(id: "1", name: "test1"); var helperGroup = HelperGroupEntity( @@ -120,9 +128,9 @@ void main() { helpers: [HelperEntity(id: "1")] ); - when(helperClientServiceMock.getPageNextHelper("/test", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))) + when(() => helperClientServiceMock.getPageNextHelper("/test", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))) .thenAnswer((_) => Future.value(helperGroup)); - when(helperClientServiceMock.getPageNextHelper("/route2", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))) + when(() => helperClientServiceMock.getPageNextHelper("/route2", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))) .thenAnswer((_) => Future.value(null)); var orchestrator = HelperOrchestrator.create( helperClientService: helperClientServiceMock, @@ -138,7 +146,7 @@ void main() { expect(orchestrator.overlay, isNotNull); await orchestrator.onChangePage("/route2"); expect(orchestrator.overlay, isNull); - verify(helperSynchronizer.sync("db6b01e1-b649-4a17-949a-9ab320601001", languageCode: "en")).called(1); + verify(() => helperSynchronizer.sync("db6b01e1-b649-4a17-949a-9ab320601001", languageCode: "en")).called(1); }); testWidgets('only one overlay at a time', (WidgetTester tester) async { @@ -150,9 +158,9 @@ void main() { helpers: [HelperEntity(id: "1")] ); - when(inAppUserClientService.getOrCreate()) + when(() => inAppUserClientService.getOrCreate()) .thenAnswer((_) => Future.value(InAppUserEntity(id: "db6b01e1-b649-4a17-949a-9ab320601001", disabledHelpers: false, anonymous: true))); - when(helperClientServiceMock + when(() => helperClientServiceMock .getPageNextHelper("test", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))) .thenAnswer((_) => Future.value(helperGroup)); var orchestrator = HelperOrchestrator.create( @@ -184,11 +192,13 @@ void main() { mockHelperBuilder.create("3", title: "TITLEKEY_3"), ] ); - when(inAppUserClientService.getOrCreate()) + when(() => inAppUserClientService.getOrCreate()) .thenAnswer((_) => Future.value(InAppUserEntity(id: "db6b01e1-b649-4a17-949a-9ab320601001", disabledHelpers: false, anonymous: true))); - when(helperClientServiceMock + when(() => helperClientServiceMock .getPageNextHelper("/test1", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))) - .thenAnswer((_) => Future.value(helperGroup)); + .thenAnswer((_) async => helperGroup); + when(() => helperClientServiceMock.onHelperTrigger("p1", helperGroup, helperGroup.helpers!.first, "db6b01e1-b649-4a17-949a-9ab320601001", true, "1.0.0")) + .thenAnswer((_) async => null); var orchestrator = HelperOrchestrator.create( helperClientService: helperClientServiceMock, inAppUserClientService: inAppUserClientService, @@ -235,11 +245,13 @@ void main() { mockHelperBuilder.create("3", title: "TITLEKEY_3"), ] ); - when(inAppUserClientService.getOrCreate()) + when(() => inAppUserClientService.getOrCreate()) .thenAnswer((_) => Future.value(InAppUserEntity(id: "db6b01e1-b649-4a17-949a-9ab320601001", disabledHelpers: false, anonymous: true))); - when(helperClientServiceMock + when(() => helperClientServiceMock .getPageNextHelper("/test1", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))) .thenAnswer((_) => Future.value(helperGroup)); + when(() => helperClientServiceMock.onHelperTrigger("p1", helperGroup, helperGroup.helpers!.first, "db6b01e1-b649-4a17-949a-9ab320601001", false, "1.0.0")) + .thenAnswer((_) async => null); var orchestrator = HelperOrchestrator.create( helperClientService: helperClientServiceMock, inAppUserClientService: inAppUserClientService, @@ -286,11 +298,13 @@ void main() { mockHelperBuilder.create("3", title: "TITLEKEY_3"), ] ); - when(inAppUserClientService.getOrCreate()) + when(() => inAppUserClientService.getOrCreate()) .thenAnswer((_) => Future.value(InAppUserEntity(id: "db6b01e1-b649-4a17-949a-9ab320601001", disabledHelpers: false, anonymous: true))); - when(helperClientServiceMock + when(() => helperClientServiceMock .getPageNextHelper("/test1", "db6b01e1-b649-4a17-949a-9ab320601001", AppVersion.fromString('1.0.0'))) .thenAnswer((_) => Future.value(helperGroup)); + when(() => helperClientServiceMock.onHelperTrigger("p1", helperGroup, any(), "db6b01e1-b649-4a17-949a-9ab320601001", true, "1.0.0")) + .thenAnswer((_) async => null); var orchestrator = HelperOrchestrator.create( helperClientService: helperClientServiceMock, inAppUserClientService: inAppUserClientService, diff --git a/test/ui/client/helpers/anchored/client_anchored_helper_test.dart b/test/ui/client/helpers/anchored/client_anchored_helper_test.dart index e1f2a800..81c6c2ff 100644 --- a/test/ui/client/helpers/anchored/client_anchored_helper_test.dart +++ b/test/ui/client/helpers/anchored/client_anchored_helper_test.dart @@ -1,18 +1,26 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/helper/helper_entity.dart'; +import 'package:pal/src/database/hive_client.dart'; +import 'package:pal/src/extensions/color_extension.dart'; +import 'package:pal/src/injectors/editor_app/editor_app_context.dart'; +import 'package:pal/src/injectors/user_app/user_app_context.dart'; import 'package:pal/src/router.dart'; +import 'package:pal/src/services/http_client/base_client.dart'; import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/client/helpers/user_anchored_helper/anchored_helper_widget.dart'; import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_weight_picker/font_weight_picker_loader.dart'; import 'package:pal/src/ui/shared/helper_shared_factory.dart'; import 'package:pal/src/ui/shared/helper_shared_viewmodels.dart'; import 'package:pal/src/ui/shared/widgets/overlayed.dart'; -import '../../../../../lib/src/extensions/color_extension.dart'; + import '../../../../pal_test_utilities.dart'; import './data.dart'; void main() { + HiveClient(shouldInit: false)..initLocal(); + final _navigatorKey = GlobalKey(); Scaffold _myHomeTest = Scaffold( @@ -33,9 +41,13 @@ void main() { ); Future beforeEach(WidgetTester tester, HelperEntity helperEntity) async { - await initAppWithPal(tester, _myHomeTest, _navigatorKey, - editorModeEnabled: false); - await tester.pumpAndSettle(); + await initAppWithPal( + tester, + _myHomeTest, + _navigatorKey, + editorModeEnabled: false, + ); + await tester.pumpAndSettle(); showOverlayed( _navigatorKey, (context) => PalTheme( @@ -43,32 +55,32 @@ void main() { child: AnchoredHelper.fromEntity( titleLabel: HelperSharedFactory.parseTextLabel( AnchoredscreenHelperKeys.TITLE_KEY, - helperEntity.helperTexts, + helperEntity.helperTexts!, ), descriptionLabel: HelperSharedFactory.parseTextLabel( AnchoredscreenHelperKeys.DESCRIPTION_KEY, - helperEntity.helperTexts, + helperEntity.helperTexts!, ), helperBoxViewModel: HelperBoxViewModel( backgroundColor: HexColor.fromHex( - helperEntity.helperBoxes.first.backgroundColor), - id: helperEntity.helperBoxes.first.id, + helperEntity.helperBoxes!.first.backgroundColor!), + id: helperEntity.helperBoxes!.first.id, ), - anchorKey: helperEntity.helperBoxes.first.key, + anchorKey: helperEntity.helperBoxes!.first.key, positivButtonLabel: HelperSharedFactory.parseButtonLabel( AnchoredscreenHelperKeys.POSITIV_KEY, - helperEntity.helperTexts, + helperEntity.helperTexts!, ), negativButtonLabel: HelperSharedFactory.parseButtonLabel( AnchoredscreenHelperKeys.NEGATIV_KEY, - helperEntity.helperTexts, + helperEntity.helperTexts!, ), onError: () { var key = OverlayKeys.PAGE_OVERLAY_KEY; - Overlayed.of(_navigatorKey.currentState.context) - .entries[key] + Overlayed.of(_navigatorKey.currentState!.context)! + .entries[key]! .remove(); - Overlayed.of(_navigatorKey.currentState.context) + Overlayed.of(_navigatorKey.currentState!.context)! .entries .remove(key); }, @@ -83,16 +95,18 @@ void main() { 'valid anchored helper entity => show anchored helper as overlay', (WidgetTester tester) async { await beforeEach(tester, validAnchoredHelperEntity); + await tester.pump(); + await tester.pump(); expect(find.byType(AnchoredHelper), findsOneWidget); - validAnchoredHelperEntity.helperTexts.forEach((element) { + validAnchoredHelperEntity.helperTexts!.forEach((element) { var textWidget = - find.text(element.value).evaluate().first.widget as Text; + find.text(element.value!).evaluate().first.widget as Text; expect(textWidget, isNotNull); - expect(textWidget.style.color.toHex(), element.fontColor); - expect(textWidget.style.fontWeight, + expect(textWidget.style!.color!.toHex(), element.fontColor); + expect(textWidget.style!.fontWeight, FontWeightMapper.toFontWeight(element.fontWeight)); - expect(textWidget.style.fontFamily, contains(element.fontFamily)); - expect(textWidget.style.fontSize, element.fontSize); + expect(textWidget.style!.fontFamily, contains(element.fontFamily)); + expect(textWidget.style!.fontSize, element.fontSize); }); await tester.pump(); }); @@ -104,6 +118,7 @@ void main() { await tester.pump(); await tester.pump(); expect(find.byType(AnchoredHelper), findsNothing); + await tester.pump(); }); }); } diff --git a/test/ui/client/helpers/client_update_helper_test.dart b/test/ui/client/helpers/client_update_helper_test.dart index 549cfb08..b15cf69c 100644 --- a/test/ui/client/helpers/client_update_helper_test.dart +++ b/test/ui/client/helpers/client_update_helper_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/services/package_version.dart'; import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/client/helpers/user_update_helper/user_update_helper.dart'; @@ -12,8 +12,8 @@ void main() { group('[Client] Update helper widget', () { var packageVersionReaderService = PackageVersionReaderMock(); - when(packageVersionReaderService.init()).thenAnswer((_) => Future.value()); - when(packageVersionReaderService.version).thenReturn('0.0.1'); + when(() => packageVersionReaderService.init()).thenAnswer((_) => Future.value()); + when(() => packageVersionReaderService.version).thenReturn('0.0.1'); UserUpdateHelperPage userUpdateHelperWidget = UserUpdateHelperPage( onPositivButtonTap: () {}, @@ -63,7 +63,7 @@ void main() { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: userUpdateHelperWidget, ), ), @@ -110,8 +110,8 @@ void main() { expect(find.text('N.O.S au secours'), findsOneWidget); var titleLabel = (tester.firstWidget(find.text('N.O.S au secours')) as Text); - expect(titleLabel.style.color, Colors.red); - expect(titleLabel.style.fontSize, 27.0); + expect(titleLabel.style!.color, Colors.red); + expect(titleLabel.style!.fontSize, 27.0); }); testWidgets('should display correct thanks button', @@ -166,25 +166,25 @@ void main() { tester.element(richText3Finder).widget as RichText; // FIXME: Impossible to use children without using the deprecated one - final textSpan0 = ((richText0Widget.text as TextSpan).children.last as TextSpan); - final textSpan1 = ((richText1Widget.text as TextSpan).children.last as TextSpan); - final textSpan2 = ((richText2Widget.text as TextSpan).children.last as TextSpan); - final textSpan3 = ((richText3Widget.text as TextSpan).children.last as TextSpan); + final textSpan0 = ((richText0Widget.text as TextSpan).children!.last as TextSpan); + final textSpan1 = ((richText1Widget.text as TextSpan).children!.last as TextSpan); + final textSpan2 = ((richText2Widget.text as TextSpan).children!.last as TextSpan); + final textSpan3 = ((richText3Widget.text as TextSpan).children!.last as TextSpan); - expect(textSpan0.style.color, Colors.white); - expect(textSpan0.style.fontSize, 14.0); + expect(textSpan0.style!.color, Colors.white); + expect(textSpan0.style!.fontSize, 14.0); expect(textSpan0.text, 'My feature 1'); - expect(textSpan1.style.color, Colors.black); - expect(textSpan1.style.fontSize, 22.0); + expect(textSpan1.style!.color, Colors.black); + expect(textSpan1.style!.fontSize, 22.0); expect(textSpan1.text, 'My feature 2'); - expect(textSpan2.style.color, Colors.red); - expect(textSpan2.style.fontSize, 14.0); + expect(textSpan2.style!.color, Colors.red); + expect(textSpan2.style!.fontSize, 14.0); expect(textSpan2.text, 'My feature 3'); - expect(textSpan3.style.color, Colors.white); - expect(textSpan3.style.fontSize, 19.0); + expect(textSpan3.style!.color, Colors.white); + expect(textSpan3.style!.fontSize, 19.0); expect(textSpan3.text, 'My feature 4'); }); }); diff --git a/test/ui/client/helpers/simple_helper_widget_test.dart b/test/ui/client/helpers/simple_helper_widget_test.dart index d69b06b0..2c1233c1 100644 --- a/test/ui/client/helpers/simple_helper_widget_test.dart +++ b/test/ui/client/helpers/simple_helper_widget_test.dart @@ -30,7 +30,7 @@ void main() { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: component, ), ), diff --git a/test/ui/client/helpers/user_fullscreen_helper_test.dart b/test/ui/client/helpers/user_fullscreen_helper_test.dart index 8e514dd1..a1489b9c 100644 --- a/test/ui/client/helpers/user_fullscreen_helper_test.dart +++ b/test/ui/client/helpers/user_fullscreen_helper_test.dart @@ -49,7 +49,7 @@ void main() { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: userFullScreenHelperPage, ), ), @@ -60,63 +60,14 @@ void main() { await tester.pump(Duration(milliseconds: 700)); await tester.pump(Duration(milliseconds: 700)); - final presenterFinder = - find.byKey(ValueKey('pal_UserFullScreenHelperPage_Builder')); - final page = presenterFinder.evaluate().first.widget - as PresenterInherited; - presenter = page.presenter; - } - - testWidgets('should crash when no box was provided', - (WidgetTester tester) async { - bool hasThrow = false; - try { - UserFullScreenHelperPage helperWidget = - UserFullScreenHelperPage(); // ignore: missing_required_param - var app = new MediaQuery( - data: MediaQueryData(), child: MaterialApp(home: helperWidget)); - await tester.pumpWidget(app); - } catch (e) { - hasThrow = true; - expect( - e.toString().contains("'helperBoxViewModel != null': is not true"), - isTrue); - } - expect(hasThrow, isTrue); - }); + // final presenterFinder = + // find.byKey(ValueKey('pal_UserFullScreenHelperPage_Builder')); + // final page = presenterFinder.evaluate().first.widget + // as PresenterInherited; - testWidgets('should crash when no title label was provided', - (WidgetTester tester) async { - bool hasThrow = false; - try { - // ignore: missing_required_param - UserFullScreenHelperPage helperWidget = UserFullScreenHelperPage( - helperBoxViewModel: HelperBoxViewModel( - backgroundColor: Colors.black, - ), - positivLabel: HelperButtonViewModel( - text: 'test', - fontColor: Colors.white, - fontSize: 23.0, - ), - negativLabel: HelperButtonViewModel( - text: 'test', - fontColor: Colors.white, - fontSize: 23.0, - ), - onNegativButtonTap: () {}, - onPositivButtonTap: () {}, - ); - var app = new MediaQuery( - data: MediaQueryData(), child: MaterialApp(home: helperWidget)); - await tester.pumpWidget(app); - await tester.pumpAndSettle(Duration(seconds: 1)); - } catch (e) { - hasThrow = true; - } - expect(hasThrow, isTrue); - }); + presenter = userFullScreenHelperPage.presenter; + } testWidgets('should have valid UI', (WidgetTester tester) async { await _beforeEach(tester); diff --git a/test/ui/client/helpers_synchronizer_test.dart b/test/ui/client/helpers_synchronizer_test.dart index d312213b..84a9a476 100644 --- a/test/ui/client/helpers_synchronizer_test.dart +++ b/test/ui/client/helpers_synchronizer_test.dart @@ -1,6 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/helper/helper_entity.dart'; import 'package:pal/src/database/entity/helper/helper_group_entity.dart'; import 'package:pal/src/database/entity/helper/schema_entity.dart'; @@ -67,13 +67,15 @@ void main() { test('[sync] loads all helpers from server if has nothing in local database', () async { var currentSchema = _mockSchema(1); const appVersion = "1.0.0"; - when(schemaRemoteRepository.get(appVersion: appVersion)).thenAnswer((_) => Future.value(currentSchema)); - when(packageVersionReader.version).thenReturn(appVersion); - when(mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))).thenAnswer((_) => Future.value(Response('[]', 200))); + when(() => schemaRemoteRepository.get(appVersion: appVersion)) + .thenAnswer((_) => Future.value(currentSchema)); + when(() => packageVersionReader.version).thenReturn(appVersion); + when(() => mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))) + .thenAnswer((_) => Future.value(Response('[]', 200))); expect(await schemaLocalRepository.get(appVersion: appVersion), isNull); await synchronizer.sync(userId); - verify(schemaRemoteRepository.get(appVersion: appVersion)).called(1); + verify(() => schemaRemoteRepository.get(appVersion: appVersion)).called(1); var localSchema = await schemaLocalRepository.get(appVersion: appVersion); expect(localSchema, isNotNull); expect(localSchema, equals(currentSchema)); @@ -83,10 +85,13 @@ void main() { var currentSchema = _mockSchema(1); var lastRemoteSchema = _mockSchema(2); const appVersion = "1.0.0"; - when(packageVersionReader.version).thenReturn(appVersion); - when(schemaRemoteRepository.get(appVersion: appVersion)).thenAnswer((_) => Future.value(currentSchema)); - when(schemaRemoteRepository.get(schemaVersion: 1, appVersion: appVersion)).thenAnswer((_) => Future.value(lastRemoteSchema)); - when(mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))).thenAnswer((_) => Future.value(Response('[]', 200))); + when(() => packageVersionReader.version).thenReturn(appVersion); + when(() => schemaRemoteRepository.get(appVersion: appVersion)) + .thenAnswer((_) => Future.value(currentSchema)); + when(() => schemaRemoteRepository.get(schemaVersion: 1, appVersion: appVersion)) + .thenAnswer((_) => Future.value(lastRemoteSchema)); + when(() => mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))) + .thenAnswer((_) => Future.value(Response('[]', 200))); //first sync on null version await synchronizer.sync(userId); var localSchema = await schemaLocalRepository.get(); @@ -94,7 +99,7 @@ void main() { //second sync should send version 1 and get a new version await synchronizer.sync(userId); localSchema = await schemaLocalRepository.get(); - expect(localSchema.schemaVersion, equals(lastRemoteSchema.schemaVersion)); + expect(localSchema!.schemaVersion, equals(lastRemoteSchema.schemaVersion)); expect(localSchema, equals(lastRemoteSchema)); }); @@ -108,13 +113,16 @@ void main() { {"pageId":"390289032", "helperGroupId": "AN1782184", "time": "2020-10-01T06:00:00Z", "version":"1.0.0"}, {"pageId":"390289032", "helperGroupId": "AN1782183", "time": "2020-10-01T06:00:00Z", "version":"1.0.0"} ]'''; - when(schemaRemoteRepository.get(appVersion: appVersion)).thenAnswer((_) => Future.value(currentSchema)); - when(packageVersionReader.version).thenReturn(appVersion); - when(mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))).thenAnswer((_) => Future.value(Response(visitedUserGroupsJson, 200))); + when(() => schemaRemoteRepository.get(appVersion: appVersion)) + .thenAnswer((_) => Future.value(currentSchema)); + when(() => packageVersionReader.version).thenReturn(appVersion); + when(() => mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))) + .thenAnswer((_) => Future.value(Response(visitedUserGroupsJson, 200))); expect(await pageUserVisitLocalRepository.get(userId, appVersion), isEmpty); await synchronizer.sync(userId); - verify(mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))).called(1); + verify(() => mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))) + .called(1); var savedVisits = await pageUserVisitLocalRepository.get(userId, appVersion); expect(savedVisits, isNotEmpty); expect(savedVisits.length, equals(5)); @@ -124,15 +132,20 @@ void main() { var currentSchema = _mockSchema(1); const appVersion = "1.0.0"; var visitedUserGroupsJson = '''[]'''; - when(schemaRemoteRepository.get(appVersion: appVersion)).thenAnswer((_) => Future.value(currentSchema)); - when(packageVersionReader.version).thenReturn(appVersion); - when(mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))).thenAnswer((_) => Future.value(Response(visitedUserGroupsJson, 200))); + when(() => schemaRemoteRepository.get(appVersion: appVersion)) + .thenAnswer((_) => Future.value(currentSchema)); + when(() => packageVersionReader.version) + .thenReturn(appVersion); + when(() => mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))) + .thenAnswer((_) => Future.value(Response(visitedUserGroupsJson, 200))); await synchronizer.sync(userId); - when(schemaRemoteRepository.get(appVersion: appVersion)).thenAnswer((_) => Future.value(null)); + when(() => schemaRemoteRepository.get(appVersion: appVersion)) + .thenAnswer((_) => Future.value(null)); await synchronizer.sync(userId); // visits api is not called again because we gonne store them locally - verify(mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))).called(1); + verify(() => mockHttpClient.get(Uri.parse('pal-analytic/users/$userId/groups'))) + .called(1); }); }); diff --git a/test/ui/editor/font_editor/font_editor_test.dart b/test/ui/editor/font_editor/font_editor_test.dart index 2b1185c1..79ae2472 100644 --- a/test/ui/editor/font_editor/font_editor_test.dart +++ b/test/ui/editor/font_editor/font_editor_test.dart @@ -36,7 +36,7 @@ void main() { ); await tester.pumpWidget(app); showDialog( - context: testNavigatorKey.currentContext, + context: testNavigatorKey.currentContext!, builder: widgetBuilder ); } @@ -56,7 +56,7 @@ void main() { }); testWidgets('font size = 20, tap on middle of slider, validate => onFontModified returns a size = 45', (WidgetTester tester) async { - double selectedFontSize = 20; + double? selectedFontSize = 20; var widgetBuilder = (context) => FontEditorDialogPage( onCancelPicker: () => Navigator.of(context).pop(), onValidatePicker: () => Navigator.of(context).pop(), @@ -81,7 +81,7 @@ void main() { }); testWidgets('font size = 20, tap on middle of slider, cancel => selectedFontSize = 20', (WidgetTester tester) async { - double selectedFontSize = 20; + double? selectedFontSize = 20; var widgetBuilder = (context) => FontEditorDialogPage( onCancelPicker: () => Navigator.of(context).pop(), onValidatePicker: () => Navigator.of(context).pop(), diff --git a/test/ui/editor/pages/app_settings/app_settings_test.dart b/test/ui/editor/pages/app_settings/app_settings_test.dart index a8a8d7a0..51373091 100644 --- a/test/ui/editor/pages/app_settings/app_settings_test.dart +++ b/test/ui/editor/pages/app_settings/app_settings_test.dart @@ -2,7 +2,7 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/app_icon_entity.dart'; import 'package:pal/src/services/editor/project/app_icon_grabber_delegate.dart'; import 'package:pal/src/services/editor/project/project_editor_service.dart'; @@ -18,29 +18,34 @@ class AppIconGrabberDelegateMock extends Mock class ProjectEditorServiceMock extends Mock implements ProjectEditorService {} void main() { + + setUpAll(() { + registerFallbackValue(Uint8List(8)); + }); + group('App settings', () { Uint8List icon = Uint8List(32); AppIconEntity appIcon = AppIconEntity(id: "123", url: "url"); - ProjectEditorServiceMock _projectEditorService; + ProjectEditorServiceMock? _projectEditorService; Future _beforeEach(WidgetTester tester, - {ProjectEditorServiceMock projectEditorMock}) async { + {ProjectEditorServiceMock? projectEditorMock}) async { var packageVersionReaderService = PackageVersionReaderMock(); var appIconGrabberDelegate = AppIconGrabberDelegateMock(); _projectEditorService = projectEditorMock ?? ProjectEditorServiceMock(); - when(packageVersionReaderService.init()) + when(() => packageVersionReaderService.init()) .thenAnswer((_) => Future.value()); - when(packageVersionReaderService.version).thenReturn('1.0.0'); - when(packageVersionReaderService.appName).thenReturn('Pal example'); - when(appIconGrabberDelegate.getClientAppIcon()) + when(() => packageVersionReaderService.version).thenReturn('1.0.0'); + when(() => packageVersionReaderService.appName).thenReturn('Pal example'); + when(() => appIconGrabberDelegate.getClientAppIcon()) .thenAnswer((_) => Future.value(icon)); if (projectEditorMock == null) { - when(_projectEditorService.sendAppIcon(any, any)) + when(() => _projectEditorService!.sendAppIcon(any(), any())) .thenAnswer((_) => Future.value(appIcon)); - when(_projectEditorService.updateAppIcon(any, any, any)).thenAnswer( + when(() => _projectEditorService!.updateAppIcon(any(), any(), any())).thenAnswer( (_) => Future.value(AppIconEntity(id: appIcon.id, url: "newUrl"))); - when(_projectEditorService.getAppIcon()) + when(() => _projectEditorService!.getAppIcon()) .thenAnswer((_) => Future.value(appIcon)); } @@ -51,7 +56,7 @@ void main() { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: AppSettingsPage( packageVersionReader: packageVersionReaderService, appIconGrabberDelegate: appIconGrabberDelegate, @@ -95,21 +100,18 @@ void main() { await tester.pumpAndSettle(); expect(find.byType(SnackBar), findsOneWidget); - verify(_projectEditorService.updateAppIcon(appIcon.id, icon, "png")) + verify(() => _projectEditorService!.updateAppIcon(appIcon.id, icon, "png")) .called(1); }); testWidgets('should create app icon if there is no app icon configured', (WidgetTester tester) async { ProjectEditorServiceMock mock = ProjectEditorServiceMock(); - when(mock.sendAppIcon(any, any)).thenAnswer((_) => Future.value(appIcon)); - when(mock.updateAppIcon(any, any, any)).thenAnswer( + when(() => mock.sendAppIcon(any(), any())).thenAnswer((_) => Future.value(appIcon)); + when(() => mock.updateAppIcon(any(), any(), any())).thenAnswer( (_) => Future.value(AppIconEntity(id: appIcon.id, url: "newUrl"))); - when(mock.getAppIcon()).thenAnswer((_) => Future.value(AppIconEntity( - id: null, - url: null, - ))); - + when(() => mock.getAppIcon()).thenAnswer( + (_) => Future.value(AppIconEntity(id: null, url: null))); await _beforeEach(tester, projectEditorMock: mock); var updateAppIconButton = find @@ -118,7 +120,7 @@ void main() { await tester.pumpAndSettle(); expect(find.byType(SnackBar), findsOneWidget); - verify(mock.sendAppIcon(icon, "png")).called(1); + verify(() => mock.sendAppIcon(icon, "png")).called(1); }); }); } diff --git a/test/ui/editor/pages/create_helper/create_helper_test.dart b/test/ui/editor/pages/create_helper/create_helper_test.dart index 210140c8..7e18596a 100644 --- a/test/ui/editor/pages/create_helper/create_helper_test.dart +++ b/test/ui/editor/pages/create_helper/create_helper_test.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; import 'package:pal/src/database/repository/editor/helper_editor_repository.dart'; import 'package:pal/src/database/repository/editor/helper_group_repository.dart'; @@ -41,7 +41,7 @@ void main() { ProjectEditorService projectEditorService; - CreateHelperPresenter presenter; + CreateHelperPresenter? presenter; getPresenter() { var presenterFinder = find.byKey(ValueKey("createHelperPresenter")); @@ -61,7 +61,7 @@ void main() { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: CreateHelperPage( projectEditorService: projectEditorService, routeObserver: routeObserverMock, @@ -81,9 +81,9 @@ void main() { setUp(() { reset(httpClientMock); reset(packageVersionReader); - when(packageVersionReader.init()).thenAnswer((realInvocation) => Future.value()); - when(packageVersionReader.appName).thenReturn('test'); - when(packageVersionReader.version).thenReturn('1.0.0'); + when(() => packageVersionReader.init()).thenAnswer((realInvocation) => Future.value()); + when(() => packageVersionReader.appName).thenReturn('test'); + when(() => packageVersionReader.version).thenReturn('1.0.0'); }); testWidgets('should create page correctly', (WidgetTester tester) async { @@ -105,7 +105,7 @@ void main() { {"id":"jdlqsjdlq132","name":"test_intro2", "priority": 1, "type": "ANCHORED_OVERLAYED_HELPER", "helpers":[{"name":"test_intro2"}]} ] '''; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))).thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))).thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); await _before(tester); await tester.pump(); await tester.pump(Duration(seconds: 1)); @@ -120,7 +120,7 @@ void main() { await tester.tap(find.text("Next")); await tester.pump(); // current step is 1 - expect(presenter.viewModel.step.value, 1); + expect(presenter!.viewModel.step!.value, 1); }); testWidgets('[step 1] 2 groups are available on page, click on first, click on second => second only is selected', (WidgetTester tester) async { @@ -129,7 +129,7 @@ void main() { {"id":"jdlqsjdlq132","name":"test_intro2", "priority": 1, "type": "ANCHORED_OVERLAYED_HELPER", "helpers":[{"name":"test_intro2"}]} ] '''; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))).thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))).thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); await _before(tester); await tester.pump(); await tester.pump(Duration(seconds: 1)); @@ -147,7 +147,7 @@ void main() { expect(find.byType(HelperGroupItemLine), findsNWidgets(2)); var lineWidget1 = find.byType(HelperGroupItemLine).evaluate().first.widget as HelperGroupItemLine; var lineWidget2 = find.byType(HelperGroupItemLine).evaluate().elementAt(1).widget as HelperGroupItemLine; - expect(presenter.viewModel.selectedHelperGroup.groupId, "jdlqsjdlq12"); + expect(presenter!.viewModel.selectedHelperGroup!.groupId, "jdlqsjdlq12"); expect(lineWidget1.model.selected, isTrue); expect(lineWidget2.model.selected, isFalse); }); @@ -158,7 +158,7 @@ void main() { {"id":"jdlqsjdlq132","name":"test_intro2", "priority": 1, "type": "ANCHORED_OVERLAYED_HELPER", "helpers":[{"name":"test_intro2"}]} ] '''; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) .thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); await _before(tester); await tester.pump(); @@ -178,7 +178,7 @@ void main() { testWidgets('[step 1] no groups available on page => click on create new group and create a group', (WidgetTester tester) async { var helperGroupListJson = '''[]'''; var myNewHelperGroupName = 'My Helper Group Name'; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) .thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); await _before(tester); await tester.pump(Duration(seconds: 1)); @@ -191,27 +191,27 @@ void main() { // create a group expect(find.byType(CreateHelperGroup), findsOneWidget); await tester.enterText(find.byKey(ValueKey('pal_CreateHelperGroup_TextField_Name')), myNewHelperGroupName); - expect(presenter.viewModel.selectedHelperGroup.title, equals(myNewHelperGroupName)); - expect(presenter.viewModel.minVersion, equals("1.0.0")); + expect(presenter!.viewModel.selectedHelperGroup!.title, equals(myNewHelperGroupName)); + expect(presenter!.viewModel.minVersion, equals("1.0.0")); expect(find.text("1.0.0"), findsOneWidget); await tester.enterText(find.byKey(ValueKey('pal_CreateHelper_TextField_MinimumVersion')), "1.1.0"); await tester.enterText(find.byKey(ValueKey('pal_CreateHelper_TextField_MaximumVersion')), "1.2.0"); - expect(presenter.viewModel.minVersion, equals("1.1.0")); - expect(presenter.viewModel.maxVersion, equals("1.2.0")); + expect(presenter!.viewModel.minVersion, equals("1.1.0")); + expect(presenter!.viewModel.maxVersion, equals("1.2.0")); // go next step await tester.pump(); expect(tester.widget(find.byKey(ValueKey('palCreateHelperNextButton'))).enabled, isTrue); await tester.tap(find.text("Next")); await tester.pump(); // current step is 1 - expect(presenter.viewModel.step.value, 1); + expect(presenter!.viewModel.step!.value, 1); expect(tester.widget(find.byKey(ValueKey('palCreateHelperNextButton'))).enabled, isFalse); }); testWidgets('[step 1] create a group with invalid min version, max version can be null => next button is disabled', (WidgetTester tester) async { var helperGroupListJson = '''[]'''; var myNewHelperGroupName = 'My Helper Group Name'; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) .thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); await _before(tester); await tester.pump(Duration(seconds: 1)); @@ -231,7 +231,7 @@ void main() { expect(tester.widget(find.byKey(ValueKey('palCreateHelperNextButton'))).enabled, isFalse); // enter 0.0.0-test min version => invalid await tester.enterText(find.byKey(ValueKey('pal_CreateHelper_TextField_MinimumVersion')), "0.0.0-test"); - expect(presenter.viewModel.minVersion, equals("0.0.0-test")); + expect(presenter!.viewModel.minVersion, equals("0.0.0-test")); await tester.pump(); await tester.pump(Duration(seconds: 1)); expect(tester.widget(find.byKey(ValueKey('palCreateHelperNextButton'))).enabled, isFalse); @@ -240,7 +240,7 @@ void main() { testWidgets('[step 1] create a group with valid min version max version is null => next button is enabled', (WidgetTester tester) async { var helperGroupListJson = '''[]'''; var myNewHelperGroupName = 'My Helper Group Name'; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) .thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); await _before(tester); await tester.pump(Duration(seconds: 1)); @@ -255,7 +255,7 @@ void main() { await tester.enterText(find.byKey(ValueKey('pal_CreateHelperGroup_TextField_Name')), myNewHelperGroupName); // enter 1.0.0 min version => valid await tester.enterText(find.byKey(ValueKey('pal_CreateHelper_TextField_MinimumVersion')), "1.0.0"); - expect(presenter.viewModel.minVersion, equals("1.0.0")); + expect(presenter!.viewModel.minVersion, equals("1.0.0")); await tester.pump(); await tester.pump(Duration(seconds: 1)); expect(tester.widget(find.byKey(ValueKey('palCreateHelperNextButton'))).enabled, isTrue); @@ -271,7 +271,7 @@ void main() { {"id":"jdlqsjdlq132","name":"test_intro2", "priority": 1, "type": "ANCHORED_OVERLAYED_HELPER", "helpers":[{"name":"test_intro2"}]} ] '''; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testPageId/groups'))) .thenAnswer((_) => Future.value(Response(helperGroupListJson, 200))); await _before(tester); await tester.pump(); @@ -283,7 +283,7 @@ void main() { await tester.tap(find.text("Next")); await tester.pump(); // current step is 1 - expect(presenter.viewModel.step.value, 1); + expect(presenter!.viewModel.step!.value, 1); } testWidgets('[step 2] an existing group is selected, click on helper position => show group helpers list, by default our helper is last', (WidgetTester tester) async { @@ -294,13 +294,13 @@ void main() { {"id":"8290832095", "name":"my helper 3", "priority": 3}, {"id":"8290832096", "name":"my helper 4", "priority": 4} ]'''; - when(httpClientMock.get(Uri.parse('pal-business/editor/groups/$selectedGroupId/helpers'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/groups/$selectedGroupId/helpers'))) .thenAnswer((_) => Future.value(Response(groupHelperListJson, 200))); await _initStep1(tester); await tester.pump(Duration(seconds: 1)); await tester.pump(Duration(seconds: 1)); // current step is 1 - expect(presenter.viewModel.step.value, 1); + expect(presenter!.viewModel.step!.value, 1); expect(find.byKey(ValueKey("pal_CreateHelper_TextField_Name")), findsOneWidget); expect(find.byKey(ValueKey("palHelperPositionNextButton")), findsOneWidget); await tester.enterText(find.byKey(ValueKey('pal_CreateHelper_TextField_Name')), 'my helper test'); diff --git a/test/ui/editor/pages/create_helper/steps/create_helper_infos_step_test.dart b/test/ui/editor/pages/create_helper/steps/create_helper_infos_step_test.dart index 8e3c9bda..bb3aa4d9 100644 --- a/test/ui/editor/pages/create_helper/steps/create_helper_infos_step_test.dart +++ b/test/ui/editor/pages/create_helper/steps/create_helper_infos_step_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/services/package_version.dart'; import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/editor/pages/create_helper/create_helper_presenter.dart'; @@ -19,13 +19,13 @@ var mockedPresenter = _CreateHelperPresenterMock(); var mockedModel = _CreateHelperModelMock(); Future _before(WidgetTester tester) async { - when(mockedPresenter.checkValidStep()).thenAnswer((_) => Future.value([])); - when(mockedModel.helperNameController).thenReturn(TextEditingController()); - when(mockedModel.isAppVersionLoading).thenReturn(false); - when(mockedModel.infosForm).thenReturn(GlobalKey()); - when(mockedModel.appVersion).thenReturn('1.0.0'); - when(mockedModel.isFormValid).thenReturn(ValueNotifier(false)); - when(mockedPresenter.readAppVersion()) + when(() => mockedPresenter.checkValidStep()).thenAnswer((_) => Future.value([])); + when(() => mockedModel.helperNameController).thenReturn(TextEditingController()); + when(() => mockedModel.isAppVersionLoading).thenReturn(false); + when(() => mockedModel.infosForm).thenReturn(GlobalKey()); + when(() => mockedModel.appVersion).thenReturn('1.0.0'); + when(() => mockedModel.isFormValid).thenReturn(ValueNotifier(false)); + when(() => mockedPresenter.readAppVersion()) .thenAnswer((realInvocation) => Future.value()); final app = MediaQuery( @@ -34,7 +34,7 @@ Future _before(WidgetTester tester) async { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: Material( child: CreateHelperInfosStep( presenter: mockedPresenter, diff --git a/test/ui/editor/pages/create_helper/steps/create_helper_theme_step_test.dart b/test/ui/editor/pages/create_helper/steps/create_helper_theme_step_test.dart index 82ece261..bb5c7b90 100644 --- a/test/ui/editor/pages/create_helper/steps/create_helper_theme_step_test.dart +++ b/test/ui/editor/pages/create_helper/steps/create_helper_theme_step_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/helper/helper_type.dart'; import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/editor/pages/create_helper/create_helper_presenter.dart'; @@ -20,11 +20,11 @@ Future _before(WidgetTester tester) async { final mockedPresenter = CreateHelperPresenterMock(); final mockedModel = CreateHelperModelMock(); - when(mockedPresenter.checkValidStep()).thenAnswer((_) => Future.value([])); - when(mockedModel.selectedHelperType).thenReturn(HelperType.HELPER_FULL_SCREEN); + when(() => mockedPresenter.checkValidStep()).thenAnswer((_) => Future.value([])); + when(() => mockedModel.selectedHelperType).thenReturn(HelperType.HELPER_FULL_SCREEN); // Clean static data - for (PreviewThemeCard card in CreateHelperThemeStepModel.cards[mockedModel.selectedHelperType]) { + for (PreviewThemeCard card in CreateHelperThemeStepModel.cards[mockedModel.selectedHelperType!]!) { card.isSelected = false; } @@ -34,7 +34,7 @@ Future _before(WidgetTester tester) async { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: CreateHelperThemeStep( presenter: mockedPresenter, model: mockedModel, diff --git a/test/ui/editor/pages/create_helper/steps/create_helper_type_step_test.dart b/test/ui/editor/pages/create_helper/steps/create_helper_type_step_test.dart index cb46a923..b51ca5e6 100644 --- a/test/ui/editor/pages/create_helper/steps/create_helper_type_step_test.dart +++ b/test/ui/editor/pages/create_helper/steps/create_helper_type_step_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/editor/pages/create_helper/create_helper_presenter.dart'; import 'package:pal/src/ui/editor/pages/create_helper/create_helper_viewmodel.dart'; @@ -16,8 +16,8 @@ Future _before(WidgetTester tester) async { final mockedPresenter = CreateHelperPresenterMock(); final mockedModel = CreateHelperModelMock(); - when(mockedPresenter.checkValidStep()).thenAnswer((_) => Future.value([])); - when(mockedModel.selectedHelperType).thenReturn(null); + when(() => mockedPresenter.checkValidStep()).thenAnswer((_) => Future.value([])); + when(() => mockedModel.selectedHelperType).thenReturn(null); // Clean static data for (PreviewTypeCard card in CreateHelperTypesStepModel.cards) { @@ -30,7 +30,7 @@ Future _before(WidgetTester tester) async { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: CreateHelperTypeStep( presenter: mockedPresenter, model: mockedModel, diff --git a/test/ui/editor/pages/group_details/group_details_test.dart b/test/ui/editor/pages/group_details/group_details_test.dart index d2945706..920cb8b5 100644 --- a/test/ui/editor/pages/group_details/group_details_test.dart +++ b/test/ui/editor/pages/group_details/group_details_test.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; import 'package:pal/src/injectors/editor_app/editor_app_context.dart'; import 'package:pal/src/services/http_client/base_client.dart'; @@ -53,7 +53,7 @@ var navKey = GlobalKey(); main() { HttpClientMock httpMock = HttpClientMock(); - GroupDetailsPage component; + late GroupDetailsPage component; group('Group Details Tests', () { Future _before(WidgetTester tester) async { EditorAppContext editorAppContext = @@ -64,7 +64,7 @@ main() { await tester.pumpAndSettle(); Navigator.push( - navKey.currentContext, + navKey.currentContext!, MaterialPageRoute( builder: (context) => GroupDetailsPage( groupId: 'testId', @@ -89,25 +89,23 @@ main() { setUp(() { reset(httpMock); // GROUP DETAILS MOCK - when(httpMock.get(Uri.parse('pal-business/editor/groups/testId'))) + when(() => httpMock.get(Uri.parse('pal-business/editor/groups/testId'))) .thenAnswer((_) => Future.value(Response(mockGroup, 200))); - when(httpMock.get(Uri.parse('pal-business/editor/groups/testId/helpers'))) + when(() => httpMock.get(Uri.parse('pal-business/editor/groups/testId/helpers'))) .thenAnswer((_) => Future.value(Response(mockHelpersList, 200))); // GROUP DETAILS MOCK - when(httpMock.put(Uri.parse('pal-business/editor/groups/testId'), - body: anyNamed('body'))) + when(() => httpMock.put(Uri.parse('pal-business/editor/groups/testId'), body: any(named: 'body'))) .thenAnswer((_) => Future.delayed( - Duration(seconds: 2), () => Response(mockGroup, 200))); + Duration(seconds: 2), () => Response(mockGroup, 200)) + ); // VERSIONS MOCKS - when(httpMock - .get(Uri.parse('pal-business/editor/versions?versionName=1.0.2&pageSize=1'))) + when(() => httpMock.get(Uri.parse('pal-business/editor/versions?versionName=1.0.2&pageSize=1'))) .thenAnswer((_) => Future.value(Response(minVersionEntity, 200))); - when(httpMock - .get(Uri.parse('pal-business/editor/versions?versionName=1.0.3&pageSize=1'))) + when(() => httpMock.get(Uri.parse('pal-business/editor/versions?versionName=1.0.3&pageSize=1'))) .thenAnswer((_) => Future.value(Response(maxVersionEntity, 200))); // VERSIONS MOCKS }); @@ -117,10 +115,10 @@ main() { await _before(tester); expect(find.byType(GroupDetailsPage), findsOneWidget); - expect(groupName(tester).controller.text, equals('group 06')); + expect(groupName(tester).controller!.text, equals('group 06')); expect(helperTriggerTypeToString(triggerType(tester).initialValue), equals('ON_SCREEN_VISIT')); - expect(minVer(tester).controller.text, equals('1.0.1')); - expect(maxVer(tester).controller.text, equals('1.0.2')); + expect(minVer(tester).controller!.text, equals('1.0.1')); + expect(maxVer(tester).controller!.text, equals('1.0.2')); }); testWidgets( @@ -129,11 +127,11 @@ main() { await _before(tester); expect(find.byType(GroupDetailsPage), findsOneWidget); - groupName(tester).controller.text = 'newTest'; + groupName(tester).controller!.text = 'newTest'; component.getPageBuilder.presenter .onNewTrigger(HelperTriggerType.ON_NEW_UPDATE); - minVer(tester).controller.text = '1.0.2'; - maxVer(tester).controller.text = '1.0.3'; + minVer(tester).controller!.text = '1.0.2'; + maxVer(tester).controller!.text = '1.0.3'; await tester.pump(); await tester.tap(find.byKey(ValueKey("saveButton"))); @@ -144,32 +142,29 @@ main() { await tester.pump(Duration(seconds: 2)); expect( - verify(httpMock.put( + verify(() => httpMock.put( Uri.parse('pal-business/editor/groups/testId'), - body: captureAnyNamed('body'), + body: captureAny(named: 'body'), )).captured.first, - equals( - '{"versionMinId":666,"versionMaxId":42,"triggerType":"ON_NEW_UPDATE","name":"newTest"}'), + equals('{"versionMinId":666,"versionMaxId":42,"triggerType":"ON_NEW_UPDATE","name":"newTest"}'), ); await tester.pumpAndSettle(); - expect( - component.getPageBuilder.presenter.viewModel.loading, equals(false)); + expect(component.getPageBuilder.presenter.viewModel.loading, equals(false)); }); testWidgets( 'On save button click (error) => should make server \'save\' request', (tester) async { - when(httpMock.put(Uri.parse('pal-business/editor/groups/testId'), - body: anyNamed('body'))) + when(() => httpMock.put(Uri.parse('pal-business/editor/groups/testId'), body: any(named: 'body'))) .thenThrow(InternalHttpError); await _before(tester); - groupName(tester).controller.text = 'newTest'; + groupName(tester).controller!.text = 'newTest'; component.getPageBuilder.presenter .onNewTrigger(HelperTriggerType.ON_NEW_UPDATE); - minVer(tester).controller.text = '1.0.2'; - maxVer(tester).controller.text = '1.0.3'; + minVer(tester).controller!.text = '1.0.2'; + maxVer(tester).controller!.text = '1.0.3'; await tester.pump(); await tester.tap(find.byKey(ValueKey("saveButton"))); @@ -193,9 +188,8 @@ main() { testWidgets('On helpers list click => Should fetch helper list and show', (tester) async { - when(httpMock.put(Uri.parse('pal-business/groups/testId/helpers'))).thenAnswer((_) => - Future.delayed( - Duration(seconds: 2), () => Response(mockHelpersList, 200))); + when(() => httpMock.put(Uri.parse('pal-business/groups/testId/helpers'))) + .thenAnswer((_) => Future.delayed(Duration(seconds: 2), () => Response(mockHelpersList, 200))); await _before(tester); await _goToHelpersList(tester); @@ -207,12 +201,13 @@ main() { testWidgets( 'On Helper delete click (sucess) => Should make server request and delete helper from list', (tester) async { - when(httpMock.put(Uri.parse('pal-business/groups/testId/helpers'))).thenAnswer((_) => - Future.delayed( - Duration(seconds: 2), () => Response(mockHelpersList, 200))); + when(() => httpMock.put(Uri.parse('pal-business/groups/testId/helpers'))) + .thenAnswer((_) => Future.delayed(Duration(seconds: 2), () => Response(mockHelpersList, 200))); + when(() => httpMock.delete(Uri.parse('pal-business/editor/helpers/id1'))) + .thenAnswer((_) async => Response('''''', 200)); - when(httpMock.delete(Uri.parse('pal-business/groups/testId/helpers/id1'))) - .thenAnswer((_) => Future.value(Response(mockHelpersList, 200))); + when(() => httpMock.delete(Uri.parse('pal-business/groups/testId/helpers/id1'))) + .thenAnswer((_) => Future.value(Response(mockHelpersList, 200))); await _before(tester); await _goToHelpersList(tester); @@ -222,25 +217,25 @@ main() { await tester.pump(); Finder deleteButton = find.byKey(ValueKey('DeleteHelperButtonid1')); - await tester.tap(deleteButton); + expect(deleteButton, findsOneWidget); + var deleteButtonAction = deleteButton.evaluate().first.widget as ActionWidget; + deleteButtonAction.onTap!(); await tester.pump(); - verify(httpMock.delete(Uri.parse('pal-business/editor/helpers/id1'))).called(1); + verify(() => httpMock.delete(Uri.parse('pal-business/editor/helpers/id1'))).called(1); await tester.pumpAndSettle(); Finder helpers = find.byType(GroupDetailsHelperTile); expect(helpers.evaluate().length, equals(2)); }); - testWidgets( - 'On Helper delete click (error) => Should make server request and show error message', - (tester) async { - when(httpMock.put(Uri.parse('pal-business/groups/testId/helpers'))).thenAnswer((_) => - Future.delayed( - Duration(seconds: 2), () => Response(mockHelpersList, 200))); + testWidgets('On Helper delete click (error) => Should make server request and show error message', + (tester) + async { + when(() => httpMock.put(Uri.parse('pal-business/groups/testId/helpers'))) + .thenAnswer((_) => Future.delayed(Duration(seconds: 2), () => Response(mockHelpersList, 200))); - when(httpMock.delete(Uri.parse('pal-business/editor/helpers/id1'))) - .thenThrow(InternalHttpError); + when(() => httpMock.delete(Uri.parse('pal-business/editor/helpers/id1'))).thenThrow(InternalHttpError); await _before(tester); await _goToHelpersList(tester); @@ -253,7 +248,7 @@ main() { await tester.tap(deleteButton); await tester.pump(); - verify(httpMock.delete(Uri.parse('pal-business/editor/helpers/id1'))).called(1); + verify(() => httpMock.delete(Uri.parse('pal-business/editor/helpers/id1'))).called(1); await tester.pumpAndSettle(Duration(milliseconds: 200)); SnackBar snackBar = tester.widget(find.byType(SnackBar)); @@ -265,7 +260,7 @@ main() { testWidgets( 'On Group menu click (sucess) => Should show delete button and delete the group', (tester) async { - when(httpMock.delete(Uri.parse('pal-business/editor/groups/testId'))) + when(() => httpMock.delete(Uri.parse('pal-business/editor/groups/testId'))) .thenAnswer((_) => Future.value(Response('true', 200))); await _before(tester); expect(find.byType(GroupDetailsPage), findsOneWidget); @@ -278,13 +273,17 @@ main() { await tester.tap(deleteGroup); await tester.pump(Duration(milliseconds: 250)); - verify(httpMock.delete(Uri.parse('pal-business/editor/groups/testId'))).called(1); + Finder deleteConfirmation = find.byKey(ValueKey('DeleteGroupConfirmationYesButton')); + await tester.tap(deleteConfirmation); + await tester.pump(Duration(milliseconds: 250)); + + verify(() => httpMock.delete(Uri.parse('pal-business/editor/groups/testId'))).called(1); }); testWidgets( 'On Group menu click (error) => Should show delete button and show error message', (tester) async { - when(httpMock.delete(Uri.parse('pal-business/editor/groups/testId'))) + when(() => httpMock.delete(Uri.parse('pal-business/editor/groups/testId'))) .thenThrow(InternalHttpError); await _before(tester); expect(find.byType(GroupDetailsPage), findsOneWidget); @@ -297,6 +296,10 @@ main() { await tester.tap(deleteGroup); await tester.pump(Duration(milliseconds: 250)); + Finder deleteConfirmation = find.byKey(ValueKey('DeleteGroupConfirmationYesButton')); + await tester.tap(deleteConfirmation); + await tester.pump(Duration(milliseconds: 250)); + SnackBar snackBar = tester.widget(find.byType(SnackBar)); expect(snackBar, isNotNull); expect(snackBar.backgroundColor, equals(Colors.redAccent)); diff --git a/test/ui/editor/pages/group_list/page_group_list_test.dart b/test/ui/editor/pages/group_list/page_group_list_test.dart index 4526f324..ef28f84e 100644 --- a/test/ui/editor/pages/group_list/page_group_list_test.dart +++ b/test/ui/editor/pages/group_list/page_group_list_test.dart @@ -1,13 +1,16 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/injectors/editor_app/editor_app_context.dart'; import 'package:pal/src/services/http_client/base_client.dart'; import 'package:pal/src/ui/editor/pages/create_helper/create_helper.dart'; import 'package:pal/src/ui/editor/pages/group_details/group_details.dart'; import 'package:pal/src/ui/editor/pages/page_groups/page_group_list.dart'; import 'package:pal/src/ui/editor/pages/page_groups/widgets/create_helper_button.dart'; +import 'package:pal/src/ui/editor/pages/page_groups/widgets/page_group_list_item.dart'; import 'package:pal/src/ui/editor/widgets/bubble_overlay.dart'; import '../../../../pal_test_utilities.dart'; @@ -48,15 +51,19 @@ void main() { editorAppContext: editorAppContext); var bubble = find.byType(BubbleOverlayButton); var bubbleWidget = bubble.evaluate().first.widget as BubbleOverlayButton; - bubbleWidget.onTapCallback(); + bubbleWidget.onTapCallback!(); } testWidgets('should create page correctly', (WidgetTester tester) async { - var helpersListJson = '''[ - - ]'''; - when(httpClientMock.get(Uri.parse('pal-business/editor/groups?routeName=myPage'))) - .thenAnswer((_) => Future.value(Response(helpersListJson, 200))); + var helpersListJson = '''[]'''; + var pageJson = '''{"id":"testId","route":"myPage"}'''; + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages?route=myPage&pageSize=1'))) + .thenAnswer((_) async => Response('''''', 200)); + when(() => httpClientMock.post(Uri.parse('pal-business/editor/pages'), body: jsonEncode({'route': 'myPage'}))) + .thenAnswer((_) async => Response(pageJson, 200)); + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) + .thenAnswer((_) async => Response(helpersListJson, 200)); + await _before(tester); await tester.pump(Duration(seconds: 2)); await tester.pump(Duration(seconds: 2)); @@ -73,23 +80,25 @@ void main() { {"id":"JKLSDJDLS27", "priority":5, "name":"group 05", "triggerType":"ON_SCREEN_VISIT", "creationDate":"2020-01-23T18:25:43.511Z", "minVersion":"1.0.1", "maxVersion": "1.0.2"}, {"id":"JKLSDJDLS28", "priority":6, "name":"group 06", "triggerType":"ON_SCREEN_VISIT", "creationDate":"2020-12-23T18:25:43.511Z", "minVersion":"1.0.1", "maxVersion": "1.0.2"} ]'''; - when(httpClientMock - .get(Uri.parse('pal-business/editor/pages?route=myPage&pageSize=1'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages?route=myPage&pageSize=1'))) .thenAnswer((_) => Future.value(Response(pageEntity, 200))); - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) .thenAnswer((_) => Future.value(Response(helpersListJson, 200))); await _before(tester); await tester.pump(Duration(seconds: 2)); expect(find.byType(PageGroupsListPage), findsOneWidget); - verify(httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) + verify(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) .called(1); // expect(find.byType(PageGroupsListItem), findsNWidgets(6)); }); testWidgets('loading with error => shut silently with a message', (WidgetTester tester) async { - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) - .thenThrow(Response('', 500)); + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages?route=myPage&pageSize=1'))) + .thenAnswer((_) async => Response(pageEntity, 200)); + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) + .thenThrow((_) => new UnknownHttpError("NETWORK ERROR e")); + await _before(tester); await tester.pump(Duration(seconds: 2)); await tester.pump(); @@ -103,7 +112,7 @@ void main() { var helpersListJson = '''[ {"id":"JKLSDJDLS23", "priority":1, "name":"group 01", "triggerType":"ON_SCREEN_VISIT", "creationDate":"2020-04-23T18:25:43.511Z", "minVersion":"1.0.1", "maxVersion": null} ]'''; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) .thenAnswer((_) => Future.value(Response(helpersListJson, 200))); await _before(tester); await tester.pump(Duration(seconds: 2)); @@ -117,7 +126,7 @@ void main() { var helpersListJson = '''[ {"id":"JKLSDJDLS23", "priority":1, "name":"group 01", "triggerType":"ON_SCREEN_VISIT", "creationDate":"2020-04-23T18:25:43.511Z", "minVersion":"1.0.1", "maxVersion": null} ]'''; - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) .thenAnswer((_) => Future.value(Response(helpersListJson, 200))); await _before(tester); await tester.pump(Duration(seconds: 2)); @@ -127,7 +136,7 @@ void main() { .evaluate() .first .widget as CreateHelperButton; - await createHelperButton.onTap(); + await createHelperButton.onTap!(); await tester.pump(Duration(seconds: 2)); await tester.pump(); expect(find.byType(CreateHelperPage), findsOneWidget); @@ -139,20 +148,20 @@ void main() { {"id":"JKLSDJDLS23", "priority":1, "name":"group 01", "triggerType":"ON_SCREEN_VISIT", "creationDate":"2020-04-23T18:25:43.511Z", "minVersion":"1.0.1", "maxVersion": null} ]'''; var groupHelpers = '''[]'''; - var groupDetails = '''{"id":"JKLSDJDLS23"}'''; - when(httpClientMock + var groupDetails = '''{"id":"JKLSDJDLS23","priority":1, "helpers":[], "name":"test", "triggerType":"ON_SCREEN_VISIT", "creationDate":"2020-04-23T18:25:43.511Z", "minVersion":"1.0.1", "maxVersion": null}'''; + when(() => httpClientMock .get(Uri.parse('pal-business/editor/pages?route=myPage&pageSize=1'))) .thenAnswer((_) => Future.value(Response(pageEntity, 200))); - when(httpClientMock.get(Uri.parse('pal-business/editor/groups/JKLSDJDLS23'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/groups/JKLSDJDLS23'))) .thenAnswer((_) => Future.value(Response(groupDetails, 200))); - when(httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/pages/testId/groups'))) .thenAnswer((_) => Future.value(Response(helpersListJson, 200))); - when(httpClientMock.get(Uri.parse('pal-business/editor/groups/JKLSDJDLS23/helpers'))) + when(() => httpClientMock.get(Uri.parse('pal-business/editor/groups/JKLSDJDLS23/helpers'))) .thenAnswer((_) => Future.value(Response(groupHelpers, 200))); await _before(tester); await tester.pumpAndSettle(Duration(seconds: 2)); - Finder listHelperItem = find.byKey(ValueKey('JKLSDJDLS23')); - await tester.tap(listHelperItem); + expect(find.byType(PageGroupsListItem), findsNWidgets(1)); + await tester.tap(find.byType(PageGroupsListItem).first); await tester.pump(Duration(seconds: 2)); await tester.pump(); expect(find.byType(GroupDetailsPage), findsOneWidget); diff --git a/test/ui/editor/pages/helper_editor/font_editor/font_editor_test.dart b/test/ui/editor/pages/helper_editor/font_editor/font_editor_test.dart index 12b51b35..3c2ae2a2 100644 --- a/test/ui/editor/pages/helper_editor/font_editor/font_editor_test.dart +++ b/test/ui/editor/pages/helper_editor/font_editor/font_editor_test.dart @@ -72,7 +72,7 @@ Future _beforeEach( theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: component, routes: { '/editor/new/font-family': (context) => Scaffold( diff --git a/test/ui/editor/pages/helper_editor/font_editor/pickers/font_family_picker_test.dart b/test/ui/editor/pages/helper_editor/font_editor/pickers/font_family_picker_test.dart index f4ced266..95554fd1 100644 --- a/test/ui/editor/pages/helper_editor/font_editor/pickers/font_family_picker_test.dart +++ b/test/ui/editor/pages/helper_editor/font_editor/pickers/font_family_picker_test.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker.dart'; import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_loader.dart'; import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/pickers/font_editor/pickers/font_family_picker/font_family_picker_viewmodel.dart'; -class FontFamilyPickerLoaderMock extends Mock - implements FontFamilyPickerLoader {} +class FontFamilyPickerLoaderMock extends Mock implements FontFamilyPickerLoader {} void main() { group('Font family picker', () { @@ -85,7 +84,7 @@ Future _beforeEach( fonts: fonts, originalFonts: List.from(fonts), ); - when(loader.load()).thenAnswer((realInvocation) => Future.value(viewModel)); + when(() => loader.load()).thenAnswer((realInvocation) => Future.value(viewModel)); final component = FontFamilyPickerPage( loader: loader, @@ -101,7 +100,7 @@ Future _beforeEach( theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: component, ), ), diff --git a/test/ui/editor/pages/helper_editor/font_editor/pickers/font_weight_picker_test.dart b/test/ui/editor/pages/helper_editor/font_editor/pickers/font_weight_picker_test.dart index 46e70795..adcbba78 100644 --- a/test/ui/editor/pages/helper_editor/font_editor/pickers/font_weight_picker_test.dart +++ b/test/ui/editor/pages/helper_editor/font_editor/pickers/font_weight_picker_test.dart @@ -54,7 +54,7 @@ Future _beforeEach( theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: component, ), ), diff --git a/test/ui/editor/pages/helper_editor/helpers/editor_anchored_helper_test.dart b/test/ui/editor/pages/helper_editor/helpers/editor_anchored_helper_test.dart index 096ef6ac..8c25d97c 100644 --- a/test/ui/editor/pages/helper_editor/helpers/editor_anchored_helper_test.dart +++ b/test/ui/editor/pages/helper_editor/helpers/editor_anchored_helper_test.dart @@ -3,7 +3,8 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; -import 'package:mockito/mockito.dart'; +// import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; import 'package:pal/src/database/entity/helper/helper_entity.dart'; import 'package:pal/src/database/entity/helper/helper_theme.dart'; @@ -40,6 +41,11 @@ class PalEditModeStateServiceMock extends Mock class HttpClientMock extends Mock implements HttpClient {} void main() { + + setUpAll(() { + registerFallbackValue(CreateAnchoredHelper.empty()); + }); + _getAnchorFullscreenPainter() => find.byType(AnimatedAnchoredFullscreenCircle).evaluate().first.widget as AnimatedAnchoredFullscreenCircle; @@ -47,7 +53,7 @@ void main() { group('[Editor] save Anchored helper', () { final _navigatorKey = GlobalKey(); - EditorAnchoredFullscreenPresenter presenter; + late EditorAnchoredFullscreenPresenter presenter; HelperEditorServiceMock helperEditorServiceMock = HelperEditorServiceMock(); @@ -71,6 +77,11 @@ void main() { // init pal + go to editor Future beforeEach(WidgetTester tester) async { + var httpClientMock = HttpClientMock(); + when(() => httpClientMock + .get(Uri.parse('pal-business/editor/pages/null/groups'))) + .thenAnswer((_) => Future.value(Response('[]', 200))); + EditorAppContext editorAppContext = HttpEditorAppContext.private(httpClient: httpClientMock); var routeFactory = (settings) { switch (settings.name) { case '/': @@ -78,7 +89,7 @@ void main() { builder: (context) => _myHomeTest, ); case '/editor/preview': - EditorPreviewArguments args = settings.arguments; + EditorPreviewArguments? args = settings.arguments; return MaterialPageRoute( builder: (context) => EditorPreviewPage( args: args, @@ -87,7 +98,9 @@ void main() { } }; await initAppWithPal(tester, null, _navigatorKey, - routeFactory: routeFactory); + routeFactory: routeFactory, + editorAppContext: editorAppContext + ); await pumpHelperWidget( tester, _navigatorKey, @@ -111,7 +124,7 @@ void main() { await tester.pump(Duration(seconds: 2)); var btn = find.byKey(ValueKey("tutorialBtnDiss")).evaluate().first.widget as OutlineButton; - btn.onPressed(); + btn.onPressed!(); await tester.pump(); } @@ -121,7 +134,7 @@ void main() { // tap on first element var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(); await tester.pump(); // validate this anchor @@ -198,7 +211,7 @@ void main() { find.byKey(ValueKey('editableActionBarPreviewButton')); final previewButton = previewButtonFinder.evaluate().first.widget as EditorActionItem; - previewButton.onTap(); + previewButton.onTap!(); // await tester.pumpAndSettle(); await tester.pump(Duration(seconds: 1)); await tester.pump(Duration(seconds: 2)); @@ -232,7 +245,7 @@ void main() { findsOneWidget); (tester.widget(find.byKey(ValueKey("positiveFeedback"))) as OutlinedButton) - .onPressed(); + .onPressed!(); await tester.pump(Duration(milliseconds: 1000)); await tester.pump(Duration(milliseconds: 2000)); @@ -257,7 +270,7 @@ void main() { find.byKey(ValueKey('editableActionBarPreviewButton')); final previewButton = previewButtonFinder.evaluate().first.widget as EditorActionItem; - previewButton.onTap(); + previewButton.onTap!(); // await tester.pumpAndSettle(); await tester.pump(Duration(seconds: 1)); await tester.pump(Duration(seconds: 2)); @@ -288,7 +301,7 @@ void main() { expect(positivText.data, equals('positiv edit')); (tester.widget(find.byKey(ValueKey("negativeFeedback"))) as OutlinedButton) - .onPressed(); + .onPressed!(); await tester.pump(Duration(milliseconds: 1000)); await tester.pump(Duration(milliseconds: 2000)); @@ -326,13 +339,13 @@ void main() { var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; var element2 = elementsFinder.evaluate().elementAt(2).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(); await tester.pump(); // expect first element to be selected expect(presenter.viewModel.selectedAnchorKey, contains("[<\'text1\'>]")); // expect second element to be selected - element2.onTap(); + element2.onTap!(); await tester.pump(Duration(milliseconds: 100)); expect(presenter.viewModel.selectedAnchorKey, contains("[<\'text2\'>]")); }); @@ -347,7 +360,7 @@ void main() { // tap on first element var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(); await tester.pump(); expect(find.byKey(ValueKey("validateSelectionBtn")), findsOneWidget); @@ -372,7 +385,7 @@ void main() { // tap on first element var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(Duration(milliseconds: 100)); await tester.pump(Duration(milliseconds: 100)); // validate this anchor @@ -385,7 +398,7 @@ void main() { expect(find.byType(EditorActionBar), findsOneWidget); // expect(_getActionBar().animation.value, equals(0)); expect(find.byKey(ValueKey("validateSelectionBtn")), findsNothing); - expect(presenter.viewModel.backgroundBox.backgroundColor.opacity, 1); + expect(presenter.viewModel.backgroundBox.backgroundColor!.opacity, 1); expect(find.text("My helper title"), findsOneWidget); expect(find.text("Describe your element here"), findsOneWidget); expect(find.text("Ok, thanks!"), findsOneWidget, @@ -405,13 +418,13 @@ void main() { var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; var element2 = elementsFinder.evaluate().elementAt(2).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(Duration(milliseconds: 100)); await tester.pump(Duration(milliseconds: 100)); // validate this anchor await tester.tap(find.byKey(ValueKey("validateSelectionBtn"))); await tester.pump(Duration(milliseconds: 100)); - element2.onTap(); + element2.onTap!(); expect(presenter.viewModel.selectedAnchorKey, contains("[<\'text1\'>]")); }); @@ -425,7 +438,7 @@ void main() { // tap on first element var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(); await tester.pump(); // validate this anchor @@ -457,7 +470,7 @@ void main() { // tap on first element var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(); await tester.pump(); // validate this anchor @@ -497,7 +510,7 @@ void main() { // tap on first element var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(); await tester.pump(); // validate this anchor @@ -519,7 +532,7 @@ void main() { validateFinder.evaluate().first.widget as CircleIconButton; expect(validateButton.onTapCallback, isNotNull); await tester.pump(Duration(seconds: 1)); - validateButton.onTapCallback(); + validateButton.onTapCallback!(); var args = CreateAnchoredHelper( helperGroup: HelperGroupConfig( id: "8209839023", minVersion: "1.0.0", maxVersion: "1.0.0"), @@ -564,9 +577,7 @@ void main() { )); await tester.pump(Duration(seconds: 2)); await tester.pump(Duration(milliseconds: 100)); - var capturedCall = - verify(helperEditorServiceMock.saveAnchoredWidget(captureAny)) - .captured; + var capturedCall = verify(() => helperEditorServiceMock.saveAnchoredWidget(captureAny())).captured; expect(jsonEncode(capturedCall.first), equals(jsonEncode(args))); await tester.pumpAndSettle(Duration(seconds: 1)); }); @@ -579,7 +590,7 @@ void main() { // tap on first element var elementsFinder = find.byKey(ValueKey("elementContainer")); var element1 = elementsFinder.evaluate().elementAt(1).widget as InkWell; - element1.onTap(); + element1.onTap!(); await tester.pump(); await tester.pump(); // validate this anchor @@ -597,7 +608,7 @@ void main() { group('[Editor] update Anchored helper', () { final _navigatorKey = GlobalKey(); - EditorAnchoredFullscreenPresenter presenter; + late EditorAnchoredFullscreenPresenter presenter; final HttpClientMock httpClientMock = HttpClientMock(); @@ -715,9 +726,12 @@ void main() { // init pal + go to editor Future beforeEach(WidgetTester tester, HelperEntity helperEntity) async { - when(httpClientMock.get(Uri.parse('pal-business/editor/helpers/myhelperid'))) - .thenAnswer( - (_) => Future.value(Response(jsonEncode(helperEntity), 200))); + when(() => httpClientMock + .get(Uri.parse('pal-business/editor/helpers/myhelperid'))) + .thenAnswer((_) => Future.value(Response(jsonEncode(helperEntity), 200))); + when(() => httpClientMock + .get(Uri.parse('pal-business/editor/pages/myPage/groups'))) + .thenAnswer((_) => Future.value(Response(jsonEncode('[]'), 200))); EditorAppContext editorAppContext = HttpEditorAppContext.private(httpClient: httpClientMock); await initAppWithPal(tester, _myHomeTest, _navigatorKey, @@ -773,14 +787,13 @@ void main() { await beforeEach(tester, helperEntity); await tester.pump(); await tester.pump(); - helperEntity.helperTexts.forEach((element) { - dynamic textWidget = find.text(element.value).evaluate().first.widget; + helperEntity.helperTexts!.forEach((element) { + dynamic textWidget = find.text(element.value!).evaluate().first.widget; expect(textWidget, isNotNull); var textColor = textWidget.style.color as Color; expect(textColor.toHex(), element.fontColor); - expect(textWidget.style.fontWeight, - FontWeightMapper.toFontWeight(element.fontWeight)); - expect(textWidget.style.fontFamily, contains(element.fontFamily)); + expect(textWidget.style.fontWeight, FontWeightMapper.toFontWeight(element.fontWeight)); + //expect(textWidget.style.fontFamily, contains(element.fontFamily)); expect(textWidget.style.fontSize, element.fontSize); }); expect(presenter.viewModel.backgroundBox.backgroundColor, diff --git a/test/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper_test.dart b/test/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper_test.dart index 1a0d7e67..81539595 100644 --- a/test/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper_test.dart +++ b/test/ui/editor/pages/helper_editor/helpers/editor_fullscreen_helper_test.dart @@ -5,6 +5,7 @@ import 'package:pal/src/database/entity/helper/helper_entity.dart'; import 'package:pal/src/database/entity/helper/helper_theme.dart'; import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; import 'package:pal/src/database/entity/helper/helper_type.dart'; +import 'package:pal/src/services/editor/helper/helper_editor_models.dart'; import 'package:pal/src/services/editor/helper/helper_editor_service.dart'; import 'package:pal/src/services/pal/pal_state_service.dart'; import 'package:pal/src/theme.dart'; @@ -20,7 +21,8 @@ import 'package:pal/src/ui/shared/helper_shared_factory.dart'; import 'package:pal/src/ui/shared/widgets/circle_button.dart'; import 'package:pal/src/ui/shared/widgets/overlayed.dart'; import '../../../../../pal_test_utilities.dart'; -import 'package:mockito/mockito.dart'; +// import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; class HelperEditorServiceMock extends Mock implements EditorHelperService {} @@ -28,8 +30,13 @@ class PalEditModeStateServiceMock extends Mock implements PalEditModeStateService {} void main() { + + setUpAll(() { + registerFallbackValue(CreateFullScreenHelper.empty()); + }); + group('[Editor] Fullscreen helper - creation mode', () { - EditorFullScreenHelperPresenter presenter; + EditorFullScreenHelperPresenter? presenter; final _navigatorKey = GlobalKey(); @@ -64,7 +71,7 @@ void main() { builder: (context) => _overlayedApplicationPage, ); case '/editor/preview': - EditorPreviewArguments args = settings.arguments; + EditorPreviewArguments? args = settings.arguments; return MaterialPageRoute( builder: (context) => EditorPreviewPage( args: args, @@ -98,7 +105,7 @@ void main() { await _beforeEach(tester); expect(find.byType(EditorFullScreenHelperPage), findsOneWidget); expect(presenter, isNotNull); - expect(presenter.editorHelperService, isNotNull); + expect(presenter!.editorHelperService, isNotNull); }); testWidgets('on text press => button is disabled', @@ -129,11 +136,11 @@ void main() { final String thirdField = 'negativ edit'; EditorFullScreenHelperPage page = tester.widget(find.byType(EditorFullScreenHelperPage)); - EditorFullScreenHelperPresenter presenter = page.builder.presenter; + EditorFullScreenHelperPresenter presenter = page.builder.presenter as EditorFullScreenHelperPresenter; - presenter.viewModel.titleTextForm.text = firstField; - presenter.viewModel.positivButtonForm.text = secondField; - presenter.viewModel.negativButtonForm.text = thirdField; + presenter.viewModel.titleTextForm!.text = firstField; + presenter.viewModel.positivButtonForm!.text = secondField; + presenter.viewModel.negativButtonForm!.text = thirdField; // await _fillFields(tester, firstField, secondField, thirdField); @@ -141,7 +148,7 @@ void main() { find.byKey(ValueKey('editableActionBarPreviewButton')); final previewButton = previewButtonFinder.evaluate().first.widget as EditorActionItem; - previewButton.onTap(); + previewButton.onTap!(); await tester.pump(Duration(milliseconds: 1100)); await tester.pump(Duration(milliseconds: 700)); @@ -170,7 +177,7 @@ void main() { (tester.widget(find.byKey(ValueKey( 'pal_UserFullScreenHelperPage_Feedback_PositivButton'))) as RaisedButton) - .onPressed(); + .onPressed!(); await tester.pump(Duration(milliseconds: 700)); await tester.pump(Duration(milliseconds: 700)); @@ -190,17 +197,17 @@ void main() { final String thirdField = 'negativ edit'; EditorFullScreenHelperPage page = tester.widget(find.byType(EditorFullScreenHelperPage)); - EditorFullScreenHelperPresenter presenter = page.builder.presenter; + EditorFullScreenHelperPresenter presenter = page.builder.presenter as EditorFullScreenHelperPresenter; - presenter.viewModel.titleTextForm.text = firstField; - presenter.viewModel.positivButtonForm.text = secondField; - presenter.viewModel.negativButtonForm.text = thirdField; + presenter.viewModel.titleTextForm!.text = firstField; + presenter.viewModel.positivButtonForm!.text = secondField; + presenter.viewModel.negativButtonForm!.text = thirdField; final previewButtonFinder = find.byKey(ValueKey('editableActionBarPreviewButton')); final previewButton = previewButtonFinder.evaluate().first.widget as EditorActionItem; - previewButton.onTap(); + previewButton.onTap!(); await tester.pump(Duration(milliseconds: 1100)); await tester.pump(Duration(milliseconds: 700)); @@ -229,7 +236,7 @@ void main() { (tester.widget(find.byKey(ValueKey( 'pal_UserFullScreenHelperPage_Feedback_NegativButton'))) as RaisedButton) - .onPressed(); + .onPressed!(); await tester.pump(Duration(milliseconds: 700)); await tester.pump(Duration(milliseconds: 700)); @@ -244,31 +251,26 @@ void main() { '=> save call helperService.saveFullscreen', (WidgetTester tester) async { await _beforeEach(tester); - var validateFinder = - find.byKey(ValueKey('editableActionBarValidateButton')); - var validateButton = - validateFinder.evaluate().first.widget as CircleIconButton; + var validateFinder = find.byKey(ValueKey('editableActionBarValidateButton')); + var validateButton = validateFinder.evaluate().first.widget as CircleIconButton; expect(validateButton.onTapCallback, isNull); - await enterTextInTextForm( - tester, 0, 'test title'); - await enterTextInTextForm( - tester, 1, 'test description'); + await enterTextInTextForm(tester, 0, 'test title'); + await enterTextInTextForm(tester, 1, 'test description'); - validateButton = - validateFinder.evaluate().first.widget as CircleIconButton; + validateButton = validateFinder.evaluate().first.widget as CircleIconButton; await tester.pumpAndSettle(); - expect(presenter.viewModel.titleTextForm.text, equals('test title')); - expect(presenter.viewModel.descriptionTextForm.text, + expect(presenter!.viewModel.titleTextForm!.text, equals('test title')); + expect(presenter!.viewModel.descriptionTextForm!.text, equals('test description')); expect( - presenter.viewModel.positivButtonForm.text, equals('Ok, thanks !')); - expect(presenter.viewModel.negativButtonForm.text, + presenter!.viewModel.positivButtonForm!.text, equals('Ok, thanks !')); + expect(presenter!.viewModel.negativButtonForm!.text, equals('This is not helping')); expect(validateButton.onTapCallback, isNotNull); - validateButton.onTapCallback(); + validateButton.onTapCallback!(); await tester.pump(Duration(seconds: 1)); - verify(helperEditorServiceMock.saveFullScreenHelper(any)).called(1); + verify(() => helperEditorServiceMock.saveFullScreenHelper(any())).called(1); await tester.pump(Duration(seconds: 2)); await tester.pump(Duration(milliseconds: 100)); }); @@ -277,7 +279,7 @@ void main() { 'save call helperService.saveFullscreen with error => shows error overlay', (WidgetTester tester) async { await _beforeEach(tester); - when(helperEditorServiceMock.saveFullScreenHelper(any)) + when(() => helperEditorServiceMock.saveFullScreenHelper(any())) .thenThrow(ArgumentError()); var validateFinder = find.byKey(ValueKey('editableActionBarValidateButton')); @@ -290,10 +292,9 @@ void main() { var validateButton = validateFinder.evaluate().first.widget as CircleIconButton; expect(validateButton.onTapCallback, isNotNull); - validateButton.onTapCallback(); + validateButton.onTapCallback!(); await tester.pump(Duration(seconds: 1)); - expect( - find.text('Error occured, please try again later'), findsOneWidget); + expect(find.text('Error occured, please try again later'), findsOneWidget); await tester.pump(Duration(seconds: 2)); await tester.pump(Duration(milliseconds: 100)); }); @@ -303,7 +304,7 @@ void main() { (WidgetTester tester) async { await _beforeEach(tester); expect( - presenter.viewModel.backgroundBoxForm.backgroundColor, + presenter!.viewModel.backgroundBoxForm!.backgroundColor, Colors.blueAccent, ); var colorPickerButton = find.byKey( @@ -322,7 +323,7 @@ void main() { await tester.tap(validateColorButton); await tester.pumpAndSettle(); expect( - presenter.viewModel.backgroundBoxForm.backgroundColor, + presenter!.viewModel.backgroundBoxForm!.backgroundColor, Color(0xFFFFFFFF), ); }); @@ -344,9 +345,9 @@ void main() { FullscreenHelperViewModel.fromHelperViewModel(helperViewModel); expect(helper.id, helperViewModel.id); expect(helper.name, helperViewModel.name); - expect(helper.helperGroup.minVersionCode, helperViewModel.helperGroup.minVersionCode); - expect(helper.helperGroup.maxVersionCode, helperViewModel.helperGroup.maxVersionCode); - expect(helper.helperGroup.triggerType, HelperTriggerType.ON_SCREEN_VISIT); + expect(helper.helperGroup!.minVersionCode, helperViewModel.helperGroup!.minVersionCode); + expect(helper.helperGroup!.maxVersionCode, helperViewModel.helperGroup!.maxVersionCode); + expect(helper.helperGroup!.triggerType, HelperTriggerType.ON_SCREEN_VISIT); expect(helper.helperTheme, HelperTheme.BLACK); }); }); @@ -395,7 +396,7 @@ void main() { Future _beforeEach(WidgetTester tester, HelperEntity helperEntity) async { reset(helperEditorServiceMock); - when(helperEditorServiceMock.getHelper(any)).thenAnswer((_) => Future.value(helperEntity)); + when(() => helperEditorServiceMock.getHelper(any())).thenAnswer((_) => Future.value(helperEntity)); EditorFullScreenHelperPage editor = EditorFullScreenHelperPage.edit( palEditModeStateService: PalEditModeStateServiceMock(), helperId: helperEntity.id, @@ -414,8 +415,8 @@ void main() { (WidgetTester tester) async { var entity = validFullscreenHelperEntity(); await _beforeEach(tester, entity); - entity.helperTexts.forEach( - (element) => expect(find.text(element.value), findsOneWidget)); + entity.helperTexts!.forEach( + (element) => expect(find.text(element.value!), findsOneWidget)); }); }); } diff --git a/test/ui/editor/pages/helper_editor/helpers/editor_simple_helper_test.dart b/test/ui/editor/pages/helper_editor/helpers/editor_simple_helper_test.dart index 6a0823bd..75075352 100644 --- a/test/ui/editor/pages/helper_editor/helpers/editor_simple_helper_test.dart +++ b/test/ui/editor/pages/helper_editor/helpers/editor_simple_helper_test.dart @@ -1,10 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +// import 'package:mockito/annotations.dart'; +// import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; import 'package:pal/src/database/entity/helper/helper_theme.dart'; import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; import 'package:pal/src/database/entity/helper/helper_type.dart'; +import 'package:pal/src/services/editor/helper/helper_editor_models.dart'; import 'package:pal/src/services/editor/helper/helper_editor_service.dart'; import 'package:pal/src/services/pal/pal_state_service.dart'; import 'package:pal/src/ui/editor/pages/helper_editor/editor_preview/editor_preview.dart'; @@ -19,16 +22,21 @@ import '../../../../../pal_test_utilities.dart'; class HelperEditorServiceMock extends Mock implements EditorHelperService {} -class PalEditModeStateServiceMock extends Mock - implements PalEditModeStateService {} +class PalEditModeStateServiceMock extends Mock implements PalEditModeStateService {} void main() { + + setUpAll(() { + registerFallbackValue(CreateSimpleHelper.empty()); + }); + group('[Editor] Simple helper', () { final _navigatorKey = GlobalKey(); - EditorSimpleHelperPresenter presenter; + EditorSimpleHelperPresenter? presenter; - HelperEditorServiceMock helperEditorServiceMock = HelperEditorServiceMock(); + EditorHelperService helperEditorServiceMock = HelperEditorServiceMock(); + PalEditModeStateService palEditModeStateService = PalEditModeStateServiceMock(); Scaffold _myHomeTest = Scaffold( body: Column( @@ -60,7 +68,7 @@ void main() { builder: (context) => _myHomeTest, ); case '/editor/preview': - EditorPreviewArguments args = settings.arguments; + EditorPreviewArguments? args = settings.arguments; return MaterialPageRoute( maintainState: true, builder: (context) => EditorPreviewPage( @@ -78,7 +86,7 @@ void main() { HelperType.SIMPLE_HELPER, HelperTheme.BLACK, editorHelperService: helperEditorServiceMock, - palEditModeStateService: new PalEditModeStateServiceMock()); + palEditModeStateService: palEditModeStateService); await tester.pumpAndSettle(Duration(milliseconds: 1000)); var presenterFinder = @@ -99,8 +107,8 @@ void main() { expect(find.text('Edit me!'), findsOneWidget); }); - testWidgets('close editor => page is removed', - (WidgetTester tester) async { + testWidgets('close editor => page is removed', (WidgetTester tester) async { + when(() => palEditModeStateService.showHelpersList(any())).thenReturn(null); await _beforeEach(tester); expect(find.byType(EditorSimpleHelperPage), findsOneWidget); var cancelFinder = find.byKey(ValueKey('editableActionBarCancelButton')); @@ -109,8 +117,7 @@ void main() { expect(find.byType(EditorSimpleHelperPage), findsNothing); }); - testWidgets('on text press => button is disabled', - (WidgetTester tester) async { + testWidgets('on text press => button is disabled', (WidgetTester tester) async { await _beforeEach(tester); expect(find.byType(EditorSimpleHelperPage), findsOneWidget); var textMode = find.byKey(ValueKey('editableActionBarTextButton')); @@ -148,7 +155,7 @@ void main() { await enterTextInTextForm(tester, 0, ''); await tester.pumpAndSettle(); - expect(presenter.viewModel.contentTextForm.text, equals('')); + expect(presenter!.viewModel.contentTextForm!.text, equals('')); var cancelFinder = find.byKey(ValueKey('editableActionBarCancelButton')); var validateFinder = @@ -184,7 +191,7 @@ void main() { final previewButton = previewButtonFinder.evaluate().first.widget as EditorActionItem; await tester.runAsync(() async { - previewButton.onTap(); + previewButton.onTap!(); await tester.pump(Duration(milliseconds: 1100)); await tester.pump(Duration(milliseconds: 500)); await tester.pump(Duration(milliseconds: 500)); @@ -199,7 +206,7 @@ void main() { expect(toastFinder, findsOneWidget); Dismissible dis = tester.widget(toastFinder); - dis.onDismissed(DismissDirection.endToStart); + dis.onDismissed!(DismissDirection.endToStart); await tester.pump(Duration(milliseconds: 500)); await tester.pump(Duration(milliseconds: 500)); await tester.pump(Duration(milliseconds: 500)); @@ -226,7 +233,7 @@ void main() { final previewButton = previewButtonFinder.evaluate().first.widget as EditorActionItem; await tester.runAsync(() async { - previewButton.onTap(); + previewButton.onTap!(); await tester.pump(Duration(milliseconds: 1300)); await tester.pump(Duration(milliseconds: 1100)); @@ -244,7 +251,7 @@ void main() { expect(toastFinder, findsOneWidget); Dismissible dis = tester.widget(toastFinder); - dis.onDismissed(DismissDirection.startToEnd); + dis.onDismissed!(DismissDirection.startToEnd); await tester.pump(Duration(milliseconds: 500)); await tester.pump(Duration(milliseconds: 1100)); @@ -263,18 +270,16 @@ void main() { await _beforeEach(tester); await enterTextInTextForm(tester, 0, 'my helper tips lorem'); await tester.pump(); - var validateFinder = - find.byKey(ValueKey('editableActionBarValidateButton')); - var validateButton = - validateFinder.evaluate().first.widget as CircleIconButton; + var validateFinder = find.byKey(ValueKey('editableActionBarValidateButton')); + var validateButton = validateFinder.evaluate().first.widget as CircleIconButton; expect(validateButton.onTapCallback, isNotNull); - validateButton.onTapCallback(); + validateButton.onTapCallback!(); await tester.pump(Duration(seconds: 1)); await tester.pump(Duration(seconds: 2)); await tester.pump(Duration(milliseconds: 100)); // await tester.pump(Duration(seconds: 1)); - verify(helperEditorServiceMock.saveSimpleHelper(any)).called(1); + verify(() => helperEditorServiceMock.saveSimpleHelper(any())).called(1); await tester.pumpAndSettle(Duration(milliseconds: 2000)); // await tester.pump(Duration(seconds: 2)); @@ -285,18 +290,17 @@ void main() { 'save call helperService.saveSimpleHelper with error => an error is shown then fades', (WidgetTester tester) async { await _beforeEach(tester); - when(helperEditorServiceMock.saveSimpleHelper(any)) - .thenThrow(new ArgumentError()); + when(() => helperEditorServiceMock.saveSimpleHelper(any())).thenThrow(new ArgumentError()); await _fillFields(tester, 'my helper tips lorem'); await tester.pumpAndSettle(); - print(presenter.viewModel.contentTextForm.text); + print(presenter!.viewModel.contentTextForm!.text); var validateFinder = find.byKey(ValueKey('editableActionBarValidateButton')); var validateButton = validateFinder.evaluate().first.widget as CircleIconButton; expect(validateButton.onTapCallback, isNotNull); - validateButton.onTapCallback(); + validateButton.onTapCallback!(); await tester.pump(Duration(seconds: 1)); expect( find.text('Error occured, please try again later'), findsOneWidget); @@ -325,11 +329,11 @@ void main() { SimpleHelperViewModel.fromHelperViewModel(helperViewModel); expect(simpleHelper.id, helperViewModel.id); expect(simpleHelper.name, helperViewModel.name); - expect(simpleHelper.helperGroup.minVersionCode, - helperViewModel.helperGroup.minVersionCode); - expect(simpleHelper.helperGroup.maxVersionCode, - helperViewModel.helperGroup.maxVersionCode); - expect(simpleHelper.helperGroup.triggerType, + expect(simpleHelper.helperGroup!.minVersionCode, + helperViewModel.helperGroup!.minVersionCode); + expect(simpleHelper.helperGroup!.maxVersionCode, + helperViewModel.helperGroup!.maxVersionCode); + expect(simpleHelper.helperGroup!.triggerType, HelperTriggerType.ON_SCREEN_VISIT); expect(simpleHelper.helperTheme, HelperTheme.BLACK); }); diff --git a/test/ui/editor/pages/helper_editor/helpers/editor_update_helper_test.dart b/test/ui/editor/pages/helper_editor/helpers/editor_update_helper_test.dart index ab35c026..8742065b 100644 --- a/test/ui/editor/pages/helper_editor/helpers/editor_update_helper_test.dart +++ b/test/ui/editor/pages/helper_editor/helpers/editor_update_helper_test.dart @@ -1,11 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:mvvm_builder/mvvm_builder.dart'; import 'package:pal/src/database/entity/helper/helper_entity.dart'; import 'package:pal/src/database/entity/helper/helper_theme.dart'; import 'package:pal/src/database/entity/helper/helper_trigger_type.dart'; import 'package:pal/src/database/entity/helper/helper_type.dart'; +import 'package:pal/src/services/editor/helper/helper_editor_models.dart'; import 'package:pal/src/services/editor/helper/helper_editor_service.dart'; import 'package:pal/src/services/package_version.dart'; import 'package:pal/src/services/pal/pal_state_service.dart'; @@ -30,15 +31,20 @@ class PalEditModeStateServiceMock extends Mock class PackageVersionReaderMock extends Mock implements PackageVersionReader {} void main() { + + setUpAll(() { + registerFallbackValue(CreateUpdateHelper.empty()); + }); + group('[Editor] create - Update helper', () { var packageVersionReaderService = PackageVersionReaderMock(); - when(packageVersionReaderService.init()).thenAnswer((_) => Future.value()); - when(packageVersionReaderService.version).thenReturn('0.0.1'); + when(() => packageVersionReaderService.init()).thenAnswer((_) => Future.value()); + when(() => packageVersionReaderService.version).thenReturn('0.0.1'); final _navigatorKey = GlobalKey(); - EditorUpdateHelperPresenter presenter; + late EditorUpdateHelperPresenter presenter; EditorHelperService helperEditorServiceMock = HelperEditorServiceMock(); @@ -68,7 +74,7 @@ void main() { builder: (context) => _myHomeTest, ); case '/editor/preview': - EditorPreviewArguments args = settings.arguments; + EditorPreviewArguments? args = settings.arguments; return MaterialPageRoute( builder: (context) => EditorPreviewPage( args: args, @@ -134,7 +140,7 @@ void main() { (tester.widget( find.byKey(ValueKey('pal_EditorUpdateHelperWidget_AddNote'))) as CircleIconButton) - .onTapCallback(); + .onTapCallback!(); // await tester.tap(addChangelogButtonFinder); await tester.pumpAndSettle(Duration(milliseconds: 500)); await enterTextInTextForm(tester, 1, thirdField); @@ -155,7 +161,7 @@ void main() { find.byKey(ValueKey('editableActionBarPreviewButton')); final previewButton = previewButtonFinder.evaluate().first.widget as EditorActionItem; - previewButton.onTap(); + previewButton.onTap!(); await tester.pump(Duration(milliseconds: 700)); await tester.pump(Duration(milliseconds: 700)); @@ -179,13 +185,13 @@ void main() { .byKey(ValueKey('pal_UserUpdateHelperWidget_ReleaseNotes_List_0')); expect(changelogFinder, findsOneWidget); RichText changeLogText = tester.widget(changelogFinder); - expect(((changeLogText.text as TextSpan).children.last as TextSpan).text, + expect(((changeLogText.text as TextSpan).children!.last as TextSpan).text, equals('test changelog edited')); (tester.widget(find.byKey( ValueKey('pal_UserUpdateHelperWidget_ThanksButton_Raised'))) as RaisedButton) - .onPressed(); + .onPressed!(); await tester.pump(Duration(milliseconds: 700)); await tester.pump(Duration(milliseconds: 700)); @@ -238,8 +244,8 @@ void main() { var validateButton = validateFinder.evaluate().first.widget as CircleIconButton; expect(validateButton.onTapCallback, isNotNull); - expect(presenter.viewModel.titleTextForm.text, 'Lorem ipsum'); - expect(presenter.viewModel.changelogsTextsForm['0'].text, + expect(presenter.viewModel.titleTextForm!.text, 'Lorem ipsum'); + expect(presenter.viewModel.changelogsTextsForm!['0']!.text, 'Lorem ipsum changelog'); await tester.pump(Duration(milliseconds: 100)); }); @@ -274,9 +280,9 @@ void main() { find.byKey(ValueKey('editableActionBarValidateButton')); var validateButton = validateFinder.evaluate().first.widget as CircleIconButton; - validateButton.onTapCallback(); + validateButton.onTapCallback!(); await tester.pump(Duration(seconds: 1)); - verify(helperEditorServiceMock.saveUpdateHelper(any)).called(1); + verify(() => helperEditorServiceMock.saveUpdateHelper(any())).called(1); await tester.pump(Duration(seconds: 2)); await tester.pump(Duration(milliseconds: 100)); }); @@ -285,7 +291,7 @@ void main() { (WidgetTester tester) async { await beforeEach(tester); expect( - presenter.viewModel.backgroundBoxForm.backgroundColor, + presenter.viewModel.backgroundBoxForm!.backgroundColor, Colors.blueAccent, ); @@ -305,7 +311,7 @@ void main() { await tester.tap(validateColorButton); await tester.pumpAndSettle(); - expect(presenter.viewModel.backgroundBoxForm.backgroundColor, + expect(presenter.viewModel.backgroundBoxForm!.backgroundColor, Color(0xFFFFFFFF)); }); @@ -336,11 +342,11 @@ void main() { var helper = UpdateHelperViewModel.fromHelperViewModel(helperViewModel); expect(helper.id, helperViewModel.id); expect(helper.name, helperViewModel.name); - expect(helper.helperGroup.minVersionCode, - helperViewModel.helperGroup.minVersionCode); - expect(helper.helperGroup.maxVersionCode, - helperViewModel.helperGroup.maxVersionCode); - expect(helper.helperGroup.triggerType, HelperTriggerType.ON_SCREEN_VISIT); + expect(helper.helperGroup!.minVersionCode, + helperViewModel.helperGroup!.minVersionCode); + expect(helper.helperGroup!.maxVersionCode, + helperViewModel.helperGroup!.maxVersionCode); + expect(helper.helperGroup!.triggerType, HelperTriggerType.ON_SCREEN_VISIT); expect(helper.helperTheme, HelperTheme.BLACK); }); }); @@ -348,7 +354,7 @@ void main() { group('[Editor] update - Update helper', () { final _navigatorKey = GlobalKey(); - EditorUpdateHelperPresenter presenter; + late EditorUpdateHelperPresenter presenter; EditorHelperService helperEditorServiceMock = HelperEditorServiceMock(); @@ -372,7 +378,7 @@ void main() { // init pal + go to editor Future beforeEach(WidgetTester tester, HelperEntity helperEntity) async { reset(helperEditorServiceMock); - when(helperEditorServiceMock.getHelper(any)) + when(() => helperEditorServiceMock.getHelper(any())) .thenAnswer((_) => Future.value(helperEntity)); await initAppWithPal(tester, _myHomeTest, _navigatorKey); await pumpHelperWidget( @@ -441,10 +447,10 @@ void main() { var entity = validUpdateHelperEntity(); await beforeEach(tester, entity); expect(find.byType(EditorUpdateHelperPage), findsOneWidget); - expect(presenter.viewModel.changelogsTextsForm.length, 2); + expect(presenter.viewModel.changelogsTextsForm!.length, 2); await tester.pump(Duration(milliseconds: 500)); - entity.helperTexts.forEach( - (element) => expect(find.text(element.value), findsOneWidget)); + entity.helperTexts!.forEach( + (element) => expect(find.text(element.value!), findsOneWidget)); }); }); } diff --git a/test/ui/editor/pages/helper_editor/widgets/editor_sending_overlay_test.dart b/test/ui/editor/pages/helper_editor/widgets/editor_sending_overlay_test.dart index 6720a262..923c15aa 100644 --- a/test/ui/editor/pages/helper_editor/widgets/editor_sending_overlay_test.dart +++ b/test/ui/editor/pages/helper_editor/widgets/editor_sending_overlay_test.dart @@ -6,7 +6,7 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_sending_ove void main() { group('EditorSendingOverlay', () { - var appContext; + late var appContext; Widget myApp = PalTheme( theme: PalThemeData.light(), diff --git a/test/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_test.dart b/test/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_test.dart index b14f5471..5d3690b7 100644 --- a/test/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_test.dart +++ b/test/ui/editor/pages/helper_editor/widgets/editor_toolbox/editor_toolbox_test.dart @@ -19,7 +19,7 @@ main() { } void _onFontPickerDone(EditedFontModel font) { - expect(font?.size, closeTo(40.0, 50.0)); + expect(font.size, closeTo(40.0, 50.0)); } void _onMediaPickerDone(GraphicEntity graphicEntity) {} @@ -29,7 +29,7 @@ main() { } group('Editor Toolbox tests', () { - ValueNotifier currentEditableItemNotifier = + ValueNotifier currentEditableItemNotifier = ValueNotifier(null); Future _beforeEach(WidgetTester tester) async { diff --git a/test/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_tool_bar_test.dart b/test/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_tool_bar_test.dart index fa11796f..60395de5 100644 --- a/test/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_tool_bar_test.dart +++ b/test/ui/editor/pages/helper_editor/widgets/editor_toolbox/widgets/editor_tool_bar_test.dart @@ -8,7 +8,7 @@ import 'package:pal/src/ui/editor/pages/helper_editor/widgets/editor_toolbox/wid main() { group('Editor ToolBar tests', () { - ValueNotifier currentEditableItemNotifier = + ValueNotifier currentEditableItemNotifier = ValueNotifier(null); Future _beforeEach(WidgetTester tester) async { diff --git a/test/ui/editor/pages/media_gallery/media_gallery_test.dart b/test/ui/editor/pages/media_gallery/media_gallery_test.dart index 37802096..02dcc817 100644 --- a/test/ui/editor/pages/media_gallery/media_gallery_test.dart +++ b/test/ui/editor/pages/media_gallery/media_gallery_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:pal/src/database/entity/graphic_entity.dart'; import 'package:pal/src/theme.dart'; import 'package:pal/src/ui/editor/pages/media_gallery/media_gallery.dart'; @@ -8,26 +8,62 @@ import 'package:pal/src/ui/editor/pages/media_gallery/media_gallery_loader.dart' import 'package:pal/src/ui/editor/pages/media_gallery/media_gallery_viewmodel.dart'; import 'package:pal/src/ui/editor/pages/media_gallery/widgets/media_cell_widget.dart'; -class _MediaGalleryLoaderMock extends Mock implements MediaGalleryLoader {} +class MediaGalleryLoaderMock extends Mock implements MediaGalleryLoader {} void main() { + group('Media gallery', () { + + final mediasData = MediaGalleryModel( + medias: List.generate(6, (i) => GraphicEntity( + id: '${20 + i}', + url: 'https://picsum.photos/id/${20 + i}/200', + uploadedDate: DateTime.now(), + ) + ) + ); + + final mediaGalleryLoader = MediaGalleryLoaderMock(); + + Future _beforeEach(WidgetTester tester) async { + var app = MediaQuery( + data: MediaQueryData(), + child: PalTheme( + theme: PalThemeData.light(), + child: Builder( + builder: (context) => MaterialApp( + theme: PalTheme.of(context)!.buildTheme(), + home: MediaGalleryPage( + loader: mediaGalleryLoader, + mediaId: '21', + ), + ), + ), + ), + ); + await tester.pumpWidget(app); + await tester.pump(); + } + + tearDown(() { + reset(mediaGalleryLoader); + }); + testWidgets('should valid ui', (WidgetTester tester) async { + when(() => mediaGalleryLoader.loadMore()).thenAnswer((_) async => List.empty()); + when(() => mediaGalleryLoader.load()).thenAnswer((_) async => mediasData); await _beforeEach(tester); - expect( - find.byKey(ValueKey('pal_MediaGalleryPage_Header')), findsOneWidget); - expect(find.byKey(ValueKey('pal_MediaGalleryPage_Header_NoteText')), - findsOneWidget); - expect(find.byKey(ValueKey('pal_MediaGalleryPage_SelectButton')), - findsOneWidget); - expect( - find.text( - 'You can upload new image to your app gallery using web Pal admin.'), + expect(find.byKey(ValueKey('pal_MediaGalleryPage_Header')), findsOneWidget); + expect(find.byKey(ValueKey('pal_MediaGalleryPage_Header_NoteText')), findsOneWidget); + expect(find.byKey(ValueKey('pal_MediaGalleryPage_SelectButton')), findsOneWidget); + expect(find.text('You can upload new image to your app gallery using web Pal admin.'), findsOneWidget); }); testWidgets('should display media cells', (WidgetTester tester) async { + when(() => mediaGalleryLoader.loadMore()).thenAnswer((_) async => List.empty()); + when(() => mediaGalleryLoader.load()).thenAnswer((_) async => mediasData); await _beforeEach(tester); await tester.pump(Duration.zero); @@ -35,6 +71,8 @@ void main() { }); testWidgets('should select second cell', (WidgetTester tester) async { + when(() => mediaGalleryLoader.loadMore()).thenAnswer((_) async => List.empty()); + when(() => mediaGalleryLoader.load()).thenAnswer((_) async => mediasData); await _beforeEach(tester); await tester.pump(Duration.zero); @@ -43,65 +81,4 @@ void main() { }); } -Future _beforeEach( - WidgetTester tester, -) async { - final mediaGalleryLoader = _MediaGalleryLoaderMock(); - when(mediaGalleryLoader.load()).thenAnswer( - (realInvocation) => Future.value( - MediaGalleryModel( - medias: [ - GraphicEntity( - id: '20', - url: 'https://picsum.photos/id/20/200', - uploadedDate: DateTime.now(), - ), - GraphicEntity( - id: '21', - url: 'https://picsum.photos/id/21/200', - uploadedDate: DateTime.now(), - ), - GraphicEntity( - id: '22', - url: 'https://picsum.photos/id/22/200', - uploadedDate: DateTime.now(), - ), - GraphicEntity( - id: '23', - url: 'https://picsum.photos/id/23/200', - uploadedDate: DateTime.now(), - ), - GraphicEntity( - id: '24', - url: 'https://picsum.photos/id/24/200', - uploadedDate: DateTime.now(), - ), - GraphicEntity( - id: '25', - url: 'https://picsum.photos/id/25/200', - uploadedDate: DateTime.now(), - ), - ], - ), - ), - ); - when(mediaGalleryLoader.loadMore()).thenAnswer((realInvocation) => null); - var app = MediaQuery( - data: MediaQueryData(), - child: PalTheme( - theme: PalThemeData.light(), - child: Builder( - builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), - home: MediaGalleryPage( - loader: mediaGalleryLoader, - mediaId: '21', - ), - ), - ), - ), - ); - await tester.pumpWidget(app); - await tester.pump(); -} diff --git a/test/ui/editor/widgets/alert_dialogs/color_picker_test.dart b/test/ui/editor/widgets/alert_dialogs/color_picker_test.dart index 134cd163..9eb6ac15 100644 --- a/test/ui/editor/widgets/alert_dialogs/color_picker_test.dart +++ b/test/ui/editor/widgets/alert_dialogs/color_picker_test.dart @@ -14,7 +14,7 @@ void main() { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: colorPickerDialog, ), ), diff --git a/test/ui/editor/widgets/edit_helper_toolbar_test.dart b/test/ui/editor/widgets/edit_helper_toolbar_test.dart index 1668af17..c05c43b1 100644 --- a/test/ui/editor/widgets/edit_helper_toolbar_test.dart +++ b/test/ui/editor/widgets/edit_helper_toolbar_test.dart @@ -14,7 +14,7 @@ void main() { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: editHelperToolbar, ), ), diff --git a/test/ui/editor/widgets/progress_bar_test.dart b/test/ui/editor/widgets/progress_bar_test.dart index 05394d11..f12d7e6e 100644 --- a/test/ui/editor/widgets/progress_bar_test.dart +++ b/test/ui/editor/widgets/progress_bar_test.dart @@ -6,8 +6,8 @@ import 'package:pal/src/ui/editor/widgets/progress_widget/pulsing_circle.dart'; void main() { group('Progress Bar', () { - ValueNotifier notifier; - ProgressBarWidget widget; + ValueNotifier? notifier; + ProgressBarWidget? widget; _setup(WidgetTester tester) async { notifier = ValueNotifier(2); @@ -19,7 +19,7 @@ void main() { theme: PalThemeData.light(), child: Builder( builder: (context) => MaterialApp( - theme: PalTheme.of(context).buildTheme(), + theme: PalTheme.of(context)!.buildTheme(), home: widget, ), ), @@ -61,11 +61,11 @@ void main() { PulsingCircleWidget circle = tester.widget(circles.at(2)); expect(circle.active, isTrue); - notifier.value++; + notifier!.value++; await tester.pump(Duration(seconds: 2)); circle = tester.widget(circles.at(2)); - expect(widget.step.value,equals(3)); + expect(widget!.step!.value,equals(3)); expect(circle.active,isFalse); expect(circle.done,isTrue); @@ -81,12 +81,12 @@ void main() { expect(circle.active, isTrue); - notifier.value--; + notifier!.value--; await tester.pump(Duration(seconds: 2)); circle = tester.widget(circles.at(2)); - expect(widget.step.value,equals(1)); + expect(widget!.step!.value,equals(1)); expect(circle.active,isFalse); expect(circle.done,isFalse); diff --git a/test/ui/screen_tester_utilities.dart b/test/ui/screen_tester_utilities.dart index 99175756..375dc082 100644 --- a/test/ui/screen_tester_utilities.dart +++ b/test/ui/screen_tester_utilities.dart @@ -16,7 +16,7 @@ class ScreenSize { } -List devicesScreenConfigs; +List? devicesScreenConfigs; extension ScreenSizeManager on WidgetTester { diff --git a/test/ui/shared/utilities/element_finder_test.dart b/test/ui/shared/utilities/element_finder_test.dart index 744cd715..275530f4 100644 --- a/test/ui/shared/utilities/element_finder_test.dart +++ b/test/ui/shared/utilities/element_finder_test.dart @@ -16,7 +16,7 @@ void main() { ); testWidgets('search a widget by key and find location + size', (WidgetTester tester) async { - BuildContext _context; + BuildContext? _context; var app = new MediaQuery(data: MediaQueryData(), child: MaterialApp(home: Builder( builder: (context) { @@ -27,13 +27,13 @@ void main() { ); await tester.pumpWidget(app); ElementFinder finder = ElementFinder(_context); - var result = finder.searchChildElement("container"); + var result = finder.searchChildElement("container")!; expect(result, isNotNull); - expect(result.bounds.size, equals(Size(150, 50))); + expect(result.bounds!.size, equals(Size(150, 50))); }); testWidgets('scan widgets finds all with their rect', (WidgetTester tester) async { - BuildContext _context; + BuildContext? _context; var app = new MediaQuery(data: MediaQueryData(), child: MaterialApp(home: Builder( builder: (context) {