From 1e65e421154a49a390fcdbd02b58ecbe35efc030 Mon Sep 17 00:00:00 2001 From: Dan Cojocaru Date: Mon, 20 Jun 2022 12:35:46 +0300 Subject: [PATCH] Implemented simulation For now just the code, without UI that shows the simulation. However, the code works. Also added ground work for visual designer. --- lib/dialogs/unsatisfied_dependencies.dart | 75 +++ lib/main.dart | 15 +- lib/models.dart | 4 + lib/models/component.dart | 26 + lib/models/component.freezed.dart | 380 +++++++++++++ lib/models/component.g.dart | 51 ++ lib/models/project.dart | 23 +- lib/models/project.freezed.dart | 365 ------------- lib/models/project.g.dart | 44 -- lib/models/wiring.dart | 35 ++ lib/models/wiring.freezed.dart | 497 ++++++++++++++++++ lib/models/wiring.g.dart | 47 ++ lib/pages/design_component.dart | 69 +++ lib/pages/edit_component.dart | 66 ++- lib/pages/project.dart | 2 +- lib/pages/projects.dart | 4 +- lib/pages_arguments/design_component.dart | 11 + .../design_component.freezed.dart | 150 ++++++ lib/pages_arguments/edit_component.dart | 2 +- lib/state/component.dart | 135 +++++ lib/state/project.dart | 7 +- lib/state/projects.dart | 2 +- lib/utils/simulation.dart | 127 +++++ lib/utils/stack_canvas_controller_hook.dart | 62 +++ pubspec.lock | 21 + pubspec.yaml | 2 + 26 files changed, 1770 insertions(+), 452 deletions(-) create mode 100644 lib/dialogs/unsatisfied_dependencies.dart create mode 100644 lib/models.dart create mode 100644 lib/models/component.dart create mode 100644 lib/models/component.freezed.dart create mode 100644 lib/models/component.g.dart create mode 100644 lib/models/wiring.dart create mode 100644 lib/models/wiring.freezed.dart create mode 100644 lib/models/wiring.g.dart create mode 100644 lib/pages/design_component.dart create mode 100644 lib/pages_arguments/design_component.dart create mode 100644 lib/pages_arguments/design_component.freezed.dart create mode 100644 lib/state/component.dart create mode 100644 lib/utils/simulation.dart create mode 100644 lib/utils/stack_canvas_controller_hook.dart diff --git a/lib/dialogs/unsatisfied_dependencies.dart b/lib/dialogs/unsatisfied_dependencies.dart new file mode 100644 index 0000000..5baa2e8 --- /dev/null +++ b/lib/dialogs/unsatisfied_dependencies.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; + +class UnsatisfiedDependenciesDialog extends StatelessWidget { + final List dependencies; + + const UnsatisfiedDependenciesDialog({required this.dependencies, super.key}); + + List get projectIds { + return dependencies + .map((dep) => dep.split('/')[0]) + .toSet() + .toList(); + } + + List componentIds(String projectId) { + return dependencies + .map((dep) => dep.split('/')) + .where((dep) => dep[0] == projectId) + .map((dep) => dep[1]) + .toSet() + .toList(); + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('Unsatisfied Dependencies'), + content: IntrinsicWidth( + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.all(8.0), + child: Text('The component you are trying to design has the following dependencies that are not available.'), + ), + const Padding( + padding: EdgeInsets.all(8.0), + child: Text('Consider importing the required projects or checking that they are up to date with the required components.'), + ), + ...projectIds.map( + (pId) => Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(2.0), + child: Text('Project $pId:'), + ), + ...componentIds(pId).map( + (cId) => Padding( + padding: const EdgeInsets.fromLTRB(16.0 + 2.0, 2.0, 2.0, 2.0), + child: Text('- Component $cId'), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('OK'), + ), + ], + ); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index ec5d860..383d355 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,14 @@ import 'package:flutter/material.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl_standalone.dart'; +import 'package:logic_circuits_simulator/pages/design_component.dart'; import 'package:logic_circuits_simulator/pages/edit_component.dart'; import 'package:logic_circuits_simulator/pages/project.dart'; import 'package:logic_circuits_simulator/pages/projects.dart'; import 'package:logic_circuits_simulator/pages/settings.dart'; +import 'package:logic_circuits_simulator/pages_arguments/design_component.dart'; import 'package:logic_circuits_simulator/pages_arguments/edit_component.dart'; +import 'package:logic_circuits_simulator/state/component.dart'; import 'package:logic_circuits_simulator/state/project.dart'; import 'package:logic_circuits_simulator/state/projects.dart'; import 'package:provider/provider.dart'; @@ -29,6 +32,7 @@ class MyApp extends StatelessWidget { providers: [ ChangeNotifierProvider(create: (_) => ProjectsState()), ChangeNotifierProvider(create: (_) => ProjectState()), + ChangeNotifierProvider(create: (_) => ComponentState()), ], child: MaterialApp( title: 'Logic Circuits Simulator', @@ -53,11 +57,12 @@ class MyApp extends StatelessWidget { return const ProjectPage(); }, EditComponentPage.routeName: (context) { - final arguments = ModalRoute.of(context)!.settings.arguments as EditComponentPageArguments; - return EditComponentPage( - component: arguments.component, - newComponent: arguments.newComponent, - ); + final args = ModalRoute.of(context)!.settings.arguments as EditComponentPageArguments; + return EditComponentPage.fromArguments(args); + }, + DesignComponentPage.routeName: (context) { + final args = ModalRoute.of(context)!.settings.arguments as DesignComponentPageArguments; + return DesignComponentPage.fromArguments(args); }, }, initialRoute: MainPage.routeName, diff --git a/lib/models.dart b/lib/models.dart new file mode 100644 index 0000000..577d79b --- /dev/null +++ b/lib/models.dart @@ -0,0 +1,4 @@ +export 'package:logic_circuits_simulator/models/projects.dart'; +export 'package:logic_circuits_simulator/models/project.dart'; +export 'package:logic_circuits_simulator/models/component.dart'; +export 'package:logic_circuits_simulator/models/wiring.dart'; diff --git a/lib/models/component.dart b/lib/models/component.dart new file mode 100644 index 0000000..1dbb290 --- /dev/null +++ b/lib/models/component.dart @@ -0,0 +1,26 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'component.freezed.dart'; +part 'component.g.dart'; + +@freezed +class ComponentEntry with _$ComponentEntry { + const factory ComponentEntry({ + required String componentId, + required String componentName, + @JsonKey(includeIfNull: false) + String? componentDescription, + required List inputs, + required List outputs, + @JsonKey(includeIfNull: false) + List? truthTable, + @JsonKey(includeIfNull: false) + List? logicExpression, + @JsonKey(defaultValue: false) + required bool visualDesigned, + @JsonKey(defaultValue: []) + required List dependencies, + }) = _ComponentEntry; + + factory ComponentEntry.fromJson(Map json) => _$ComponentEntryFromJson(json); +} diff --git a/lib/models/component.freezed.dart b/lib/models/component.freezed.dart new file mode 100644 index 0000000..5a71c57 --- /dev/null +++ b/lib/models/component.freezed.dart @@ -0,0 +1,380 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target + +part of 'component.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +ComponentEntry _$ComponentEntryFromJson(Map json) { + return _ComponentEntry.fromJson(json); +} + +/// @nodoc +mixin _$ComponentEntry { + String get componentId => throw _privateConstructorUsedError; + String get componentName => throw _privateConstructorUsedError; + @JsonKey(includeIfNull: false) + String? get componentDescription => throw _privateConstructorUsedError; + List get inputs => throw _privateConstructorUsedError; + List get outputs => throw _privateConstructorUsedError; + @JsonKey(includeIfNull: false) + List? get truthTable => throw _privateConstructorUsedError; + @JsonKey(includeIfNull: false) + List? get logicExpression => throw _privateConstructorUsedError; + @JsonKey(defaultValue: false) + bool get visualDesigned => throw _privateConstructorUsedError; + @JsonKey(defaultValue: []) + List get dependencies => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ComponentEntryCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ComponentEntryCopyWith<$Res> { + factory $ComponentEntryCopyWith( + ComponentEntry value, $Res Function(ComponentEntry) then) = + _$ComponentEntryCopyWithImpl<$Res>; + $Res call( + {String componentId, + String componentName, + @JsonKey(includeIfNull: false) String? componentDescription, + List inputs, + List outputs, + @JsonKey(includeIfNull: false) List? truthTable, + @JsonKey(includeIfNull: false) List? logicExpression, + @JsonKey(defaultValue: false) bool visualDesigned, + @JsonKey(defaultValue: []) List dependencies}); +} + +/// @nodoc +class _$ComponentEntryCopyWithImpl<$Res> + implements $ComponentEntryCopyWith<$Res> { + _$ComponentEntryCopyWithImpl(this._value, this._then); + + final ComponentEntry _value; + // ignore: unused_field + final $Res Function(ComponentEntry) _then; + + @override + $Res call({ + Object? componentId = freezed, + Object? componentName = freezed, + Object? componentDescription = freezed, + Object? inputs = freezed, + Object? outputs = freezed, + Object? truthTable = freezed, + Object? logicExpression = freezed, + Object? visualDesigned = freezed, + Object? dependencies = freezed, + }) { + return _then(_value.copyWith( + componentId: componentId == freezed + ? _value.componentId + : componentId // ignore: cast_nullable_to_non_nullable + as String, + componentName: componentName == freezed + ? _value.componentName + : componentName // ignore: cast_nullable_to_non_nullable + as String, + componentDescription: componentDescription == freezed + ? _value.componentDescription + : componentDescription // ignore: cast_nullable_to_non_nullable + as String?, + inputs: inputs == freezed + ? _value.inputs + : inputs // ignore: cast_nullable_to_non_nullable + as List, + outputs: outputs == freezed + ? _value.outputs + : outputs // ignore: cast_nullable_to_non_nullable + as List, + truthTable: truthTable == freezed + ? _value.truthTable + : truthTable // ignore: cast_nullable_to_non_nullable + as List?, + logicExpression: logicExpression == freezed + ? _value.logicExpression + : logicExpression // ignore: cast_nullable_to_non_nullable + as List?, + visualDesigned: visualDesigned == freezed + ? _value.visualDesigned + : visualDesigned // ignore: cast_nullable_to_non_nullable + as bool, + dependencies: dependencies == freezed + ? _value.dependencies + : dependencies // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +abstract class _$$_ComponentEntryCopyWith<$Res> + implements $ComponentEntryCopyWith<$Res> { + factory _$$_ComponentEntryCopyWith( + _$_ComponentEntry value, $Res Function(_$_ComponentEntry) then) = + __$$_ComponentEntryCopyWithImpl<$Res>; + @override + $Res call( + {String componentId, + String componentName, + @JsonKey(includeIfNull: false) String? componentDescription, + List inputs, + List outputs, + @JsonKey(includeIfNull: false) List? truthTable, + @JsonKey(includeIfNull: false) List? logicExpression, + @JsonKey(defaultValue: false) bool visualDesigned, + @JsonKey(defaultValue: []) List dependencies}); +} + +/// @nodoc +class __$$_ComponentEntryCopyWithImpl<$Res> + extends _$ComponentEntryCopyWithImpl<$Res> + implements _$$_ComponentEntryCopyWith<$Res> { + __$$_ComponentEntryCopyWithImpl( + _$_ComponentEntry _value, $Res Function(_$_ComponentEntry) _then) + : super(_value, (v) => _then(v as _$_ComponentEntry)); + + @override + _$_ComponentEntry get _value => super._value as _$_ComponentEntry; + + @override + $Res call({ + Object? componentId = freezed, + Object? componentName = freezed, + Object? componentDescription = freezed, + Object? inputs = freezed, + Object? outputs = freezed, + Object? truthTable = freezed, + Object? logicExpression = freezed, + Object? visualDesigned = freezed, + Object? dependencies = freezed, + }) { + return _then(_$_ComponentEntry( + componentId: componentId == freezed + ? _value.componentId + : componentId // ignore: cast_nullable_to_non_nullable + as String, + componentName: componentName == freezed + ? _value.componentName + : componentName // ignore: cast_nullable_to_non_nullable + as String, + componentDescription: componentDescription == freezed + ? _value.componentDescription + : componentDescription // ignore: cast_nullable_to_non_nullable + as String?, + inputs: inputs == freezed + ? _value._inputs + : inputs // ignore: cast_nullable_to_non_nullable + as List, + outputs: outputs == freezed + ? _value._outputs + : outputs // ignore: cast_nullable_to_non_nullable + as List, + truthTable: truthTable == freezed + ? _value._truthTable + : truthTable // ignore: cast_nullable_to_non_nullable + as List?, + logicExpression: logicExpression == freezed + ? _value._logicExpression + : logicExpression // ignore: cast_nullable_to_non_nullable + as List?, + visualDesigned: visualDesigned == freezed + ? _value.visualDesigned + : visualDesigned // ignore: cast_nullable_to_non_nullable + as bool, + dependencies: dependencies == freezed + ? _value._dependencies + : dependencies // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_ComponentEntry implements _ComponentEntry { + const _$_ComponentEntry( + {required this.componentId, + required this.componentName, + @JsonKey(includeIfNull: false) this.componentDescription, + required final List inputs, + required final List outputs, + @JsonKey(includeIfNull: false) final List? truthTable, + @JsonKey(includeIfNull: false) final List? logicExpression, + @JsonKey(defaultValue: false) required this.visualDesigned, + @JsonKey(defaultValue: []) required final List dependencies}) + : _inputs = inputs, + _outputs = outputs, + _truthTable = truthTable, + _logicExpression = logicExpression, + _dependencies = dependencies; + + factory _$_ComponentEntry.fromJson(Map json) => + _$$_ComponentEntryFromJson(json); + + @override + final String componentId; + @override + final String componentName; + @override + @JsonKey(includeIfNull: false) + final String? componentDescription; + final List _inputs; + @override + List get inputs { + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_inputs); + } + + final List _outputs; + @override + List get outputs { + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_outputs); + } + + final List? _truthTable; + @override + @JsonKey(includeIfNull: false) + List? get truthTable { + final value = _truthTable; + if (value == null) return null; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _logicExpression; + @override + @JsonKey(includeIfNull: false) + List? get logicExpression { + final value = _logicExpression; + if (value == null) return null; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + @JsonKey(defaultValue: false) + final bool visualDesigned; + final List _dependencies; + @override + @JsonKey(defaultValue: []) + List get dependencies { + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_dependencies); + } + + @override + String toString() { + return 'ComponentEntry(componentId: $componentId, componentName: $componentName, componentDescription: $componentDescription, inputs: $inputs, outputs: $outputs, truthTable: $truthTable, logicExpression: $logicExpression, visualDesigned: $visualDesigned, dependencies: $dependencies)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_ComponentEntry && + const DeepCollectionEquality() + .equals(other.componentId, componentId) && + const DeepCollectionEquality() + .equals(other.componentName, componentName) && + const DeepCollectionEquality() + .equals(other.componentDescription, componentDescription) && + const DeepCollectionEquality().equals(other._inputs, _inputs) && + const DeepCollectionEquality().equals(other._outputs, _outputs) && + const DeepCollectionEquality() + .equals(other._truthTable, _truthTable) && + const DeepCollectionEquality() + .equals(other._logicExpression, _logicExpression) && + const DeepCollectionEquality() + .equals(other.visualDesigned, visualDesigned) && + const DeepCollectionEquality() + .equals(other._dependencies, _dependencies)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(componentId), + const DeepCollectionEquality().hash(componentName), + const DeepCollectionEquality().hash(componentDescription), + const DeepCollectionEquality().hash(_inputs), + const DeepCollectionEquality().hash(_outputs), + const DeepCollectionEquality().hash(_truthTable), + const DeepCollectionEquality().hash(_logicExpression), + const DeepCollectionEquality().hash(visualDesigned), + const DeepCollectionEquality().hash(_dependencies)); + + @JsonKey(ignore: true) + @override + _$$_ComponentEntryCopyWith<_$_ComponentEntry> get copyWith => + __$$_ComponentEntryCopyWithImpl<_$_ComponentEntry>(this, _$identity); + + @override + Map toJson() { + return _$$_ComponentEntryToJson(this); + } +} + +abstract class _ComponentEntry implements ComponentEntry { + const factory _ComponentEntry( + {required final String componentId, + required final String componentName, + @JsonKey(includeIfNull: false) + final String? componentDescription, + required final List inputs, + required final List outputs, + @JsonKey(includeIfNull: false) + final List? truthTable, + @JsonKey(includeIfNull: false) + final List? logicExpression, + @JsonKey(defaultValue: false) + required final bool visualDesigned, + @JsonKey(defaultValue: []) + required final List dependencies}) = _$_ComponentEntry; + + factory _ComponentEntry.fromJson(Map json) = + _$_ComponentEntry.fromJson; + + @override + String get componentId => throw _privateConstructorUsedError; + @override + String get componentName => throw _privateConstructorUsedError; + @override + @JsonKey(includeIfNull: false) + String? get componentDescription => throw _privateConstructorUsedError; + @override + List get inputs => throw _privateConstructorUsedError; + @override + List get outputs => throw _privateConstructorUsedError; + @override + @JsonKey(includeIfNull: false) + List? get truthTable => throw _privateConstructorUsedError; + @override + @JsonKey(includeIfNull: false) + List? get logicExpression => throw _privateConstructorUsedError; + @override + @JsonKey(defaultValue: false) + bool get visualDesigned => throw _privateConstructorUsedError; + @override + @JsonKey(defaultValue: []) + List get dependencies => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$$_ComponentEntryCopyWith<_$_ComponentEntry> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/component.g.dart b/lib/models/component.g.dart new file mode 100644 index 0000000..8a81526 --- /dev/null +++ b/lib/models/component.g.dart @@ -0,0 +1,51 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'component.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_ComponentEntry _$$_ComponentEntryFromJson(Map json) => + _$_ComponentEntry( + componentId: json['componentId'] as String, + componentName: json['componentName'] as String, + componentDescription: json['componentDescription'] as String?, + inputs: + (json['inputs'] as List).map((e) => e as String).toList(), + outputs: + (json['outputs'] as List).map((e) => e as String).toList(), + truthTable: (json['truthTable'] as List?) + ?.map((e) => e as String) + .toList(), + logicExpression: (json['logicExpression'] as List?) + ?.map((e) => e as String) + .toList(), + visualDesigned: json['visualDesigned'] as bool? ?? false, + dependencies: (json['dependencies'] as List?) + ?.map((e) => e as String) + .toList() ?? + [], + ); + +Map _$$_ComponentEntryToJson(_$_ComponentEntry instance) { + final val = { + 'componentId': instance.componentId, + 'componentName': instance.componentName, + }; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('componentDescription', instance.componentDescription); + val['inputs'] = instance.inputs; + val['outputs'] = instance.outputs; + writeNotNull('truthTable', instance.truthTable); + writeNotNull('logicExpression', instance.logicExpression); + val['visualDesigned'] = instance.visualDesigned; + val['dependencies'] = instance.dependencies; + return val; +} diff --git a/lib/models/project.dart b/lib/models/project.dart index 6b80539..9b30814 100644 --- a/lib/models/project.dart +++ b/lib/models/project.dart @@ -1,4 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:logic_circuits_simulator/models.dart'; part 'project.freezed.dart'; part 'project.g.dart'; @@ -11,25 +12,3 @@ class ProjectIndex with _$ProjectIndex { factory ProjectIndex.fromJson(Map json) => _$ProjectIndexFromJson(json); } - -@freezed -class ComponentEntry with _$ComponentEntry { - const factory ComponentEntry({ - required String componentId, - required String componentName, - @JsonKey(includeIfNull: false) - String? componentDescription, - required List inputs, - required List outputs, - @JsonKey(includeIfNull: false) - List? truthTable, - @JsonKey(includeIfNull: false) - List? logicExpression, - @JsonKey(defaultValue: false) - required bool visualDesigned, - @JsonKey(defaultValue: []) - required List dependencies, - }) = _ComponentEntry; - - factory ComponentEntry.fromJson(Map json) => _$ComponentEntryFromJson(json); -} diff --git a/lib/models/project.freezed.dart b/lib/models/project.freezed.dart index 0c2cb28..0cca7c5 100644 --- a/lib/models/project.freezed.dart +++ b/lib/models/project.freezed.dart @@ -151,368 +151,3 @@ abstract class _ProjectIndex implements ProjectIndex { _$$_ProjectIndexCopyWith<_$_ProjectIndex> get copyWith => throw _privateConstructorUsedError; } - -ComponentEntry _$ComponentEntryFromJson(Map json) { - return _ComponentEntry.fromJson(json); -} - -/// @nodoc -mixin _$ComponentEntry { - String get componentId => throw _privateConstructorUsedError; - String get componentName => throw _privateConstructorUsedError; - @JsonKey(includeIfNull: false) - String? get componentDescription => throw _privateConstructorUsedError; - List get inputs => throw _privateConstructorUsedError; - List get outputs => throw _privateConstructorUsedError; - @JsonKey(includeIfNull: false) - List? get truthTable => throw _privateConstructorUsedError; - @JsonKey(includeIfNull: false) - List? get logicExpression => throw _privateConstructorUsedError; - @JsonKey(defaultValue: false) - bool get visualDesigned => throw _privateConstructorUsedError; - @JsonKey(defaultValue: []) - List get dependencies => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $ComponentEntryCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ComponentEntryCopyWith<$Res> { - factory $ComponentEntryCopyWith( - ComponentEntry value, $Res Function(ComponentEntry) then) = - _$ComponentEntryCopyWithImpl<$Res>; - $Res call( - {String componentId, - String componentName, - @JsonKey(includeIfNull: false) String? componentDescription, - List inputs, - List outputs, - @JsonKey(includeIfNull: false) List? truthTable, - @JsonKey(includeIfNull: false) List? logicExpression, - @JsonKey(defaultValue: false) bool visualDesigned, - @JsonKey(defaultValue: []) List dependencies}); -} - -/// @nodoc -class _$ComponentEntryCopyWithImpl<$Res> - implements $ComponentEntryCopyWith<$Res> { - _$ComponentEntryCopyWithImpl(this._value, this._then); - - final ComponentEntry _value; - // ignore: unused_field - final $Res Function(ComponentEntry) _then; - - @override - $Res call({ - Object? componentId = freezed, - Object? componentName = freezed, - Object? componentDescription = freezed, - Object? inputs = freezed, - Object? outputs = freezed, - Object? truthTable = freezed, - Object? logicExpression = freezed, - Object? visualDesigned = freezed, - Object? dependencies = freezed, - }) { - return _then(_value.copyWith( - componentId: componentId == freezed - ? _value.componentId - : componentId // ignore: cast_nullable_to_non_nullable - as String, - componentName: componentName == freezed - ? _value.componentName - : componentName // ignore: cast_nullable_to_non_nullable - as String, - componentDescription: componentDescription == freezed - ? _value.componentDescription - : componentDescription // ignore: cast_nullable_to_non_nullable - as String?, - inputs: inputs == freezed - ? _value.inputs - : inputs // ignore: cast_nullable_to_non_nullable - as List, - outputs: outputs == freezed - ? _value.outputs - : outputs // ignore: cast_nullable_to_non_nullable - as List, - truthTable: truthTable == freezed - ? _value.truthTable - : truthTable // ignore: cast_nullable_to_non_nullable - as List?, - logicExpression: logicExpression == freezed - ? _value.logicExpression - : logicExpression // ignore: cast_nullable_to_non_nullable - as List?, - visualDesigned: visualDesigned == freezed - ? _value.visualDesigned - : visualDesigned // ignore: cast_nullable_to_non_nullable - as bool, - dependencies: dependencies == freezed - ? _value.dependencies - : dependencies // ignore: cast_nullable_to_non_nullable - as List, - )); - } -} - -/// @nodoc -abstract class _$$_ComponentEntryCopyWith<$Res> - implements $ComponentEntryCopyWith<$Res> { - factory _$$_ComponentEntryCopyWith( - _$_ComponentEntry value, $Res Function(_$_ComponentEntry) then) = - __$$_ComponentEntryCopyWithImpl<$Res>; - @override - $Res call( - {String componentId, - String componentName, - @JsonKey(includeIfNull: false) String? componentDescription, - List inputs, - List outputs, - @JsonKey(includeIfNull: false) List? truthTable, - @JsonKey(includeIfNull: false) List? logicExpression, - @JsonKey(defaultValue: false) bool visualDesigned, - @JsonKey(defaultValue: []) List dependencies}); -} - -/// @nodoc -class __$$_ComponentEntryCopyWithImpl<$Res> - extends _$ComponentEntryCopyWithImpl<$Res> - implements _$$_ComponentEntryCopyWith<$Res> { - __$$_ComponentEntryCopyWithImpl( - _$_ComponentEntry _value, $Res Function(_$_ComponentEntry) _then) - : super(_value, (v) => _then(v as _$_ComponentEntry)); - - @override - _$_ComponentEntry get _value => super._value as _$_ComponentEntry; - - @override - $Res call({ - Object? componentId = freezed, - Object? componentName = freezed, - Object? componentDescription = freezed, - Object? inputs = freezed, - Object? outputs = freezed, - Object? truthTable = freezed, - Object? logicExpression = freezed, - Object? visualDesigned = freezed, - Object? dependencies = freezed, - }) { - return _then(_$_ComponentEntry( - componentId: componentId == freezed - ? _value.componentId - : componentId // ignore: cast_nullable_to_non_nullable - as String, - componentName: componentName == freezed - ? _value.componentName - : componentName // ignore: cast_nullable_to_non_nullable - as String, - componentDescription: componentDescription == freezed - ? _value.componentDescription - : componentDescription // ignore: cast_nullable_to_non_nullable - as String?, - inputs: inputs == freezed - ? _value._inputs - : inputs // ignore: cast_nullable_to_non_nullable - as List, - outputs: outputs == freezed - ? _value._outputs - : outputs // ignore: cast_nullable_to_non_nullable - as List, - truthTable: truthTable == freezed - ? _value._truthTable - : truthTable // ignore: cast_nullable_to_non_nullable - as List?, - logicExpression: logicExpression == freezed - ? _value._logicExpression - : logicExpression // ignore: cast_nullable_to_non_nullable - as List?, - visualDesigned: visualDesigned == freezed - ? _value.visualDesigned - : visualDesigned // ignore: cast_nullable_to_non_nullable - as bool, - dependencies: dependencies == freezed - ? _value._dependencies - : dependencies // ignore: cast_nullable_to_non_nullable - as List, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$_ComponentEntry implements _ComponentEntry { - const _$_ComponentEntry( - {required this.componentId, - required this.componentName, - @JsonKey(includeIfNull: false) this.componentDescription, - required final List inputs, - required final List outputs, - @JsonKey(includeIfNull: false) final List? truthTable, - @JsonKey(includeIfNull: false) final List? logicExpression, - @JsonKey(defaultValue: false) required this.visualDesigned, - @JsonKey(defaultValue: []) required final List dependencies}) - : _inputs = inputs, - _outputs = outputs, - _truthTable = truthTable, - _logicExpression = logicExpression, - _dependencies = dependencies; - - factory _$_ComponentEntry.fromJson(Map json) => - _$$_ComponentEntryFromJson(json); - - @override - final String componentId; - @override - final String componentName; - @override - @JsonKey(includeIfNull: false) - final String? componentDescription; - final List _inputs; - @override - List get inputs { - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_inputs); - } - - final List _outputs; - @override - List get outputs { - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_outputs); - } - - final List? _truthTable; - @override - @JsonKey(includeIfNull: false) - List? get truthTable { - final value = _truthTable; - if (value == null) return null; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(value); - } - - final List? _logicExpression; - @override - @JsonKey(includeIfNull: false) - List? get logicExpression { - final value = _logicExpression; - if (value == null) return null; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(value); - } - - @override - @JsonKey(defaultValue: false) - final bool visualDesigned; - final List _dependencies; - @override - @JsonKey(defaultValue: []) - List get dependencies { - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_dependencies); - } - - @override - String toString() { - return 'ComponentEntry(componentId: $componentId, componentName: $componentName, componentDescription: $componentDescription, inputs: $inputs, outputs: $outputs, truthTable: $truthTable, logicExpression: $logicExpression, visualDesigned: $visualDesigned, dependencies: $dependencies)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$_ComponentEntry && - const DeepCollectionEquality() - .equals(other.componentId, componentId) && - const DeepCollectionEquality() - .equals(other.componentName, componentName) && - const DeepCollectionEquality() - .equals(other.componentDescription, componentDescription) && - const DeepCollectionEquality().equals(other._inputs, _inputs) && - const DeepCollectionEquality().equals(other._outputs, _outputs) && - const DeepCollectionEquality() - .equals(other._truthTable, _truthTable) && - const DeepCollectionEquality() - .equals(other._logicExpression, _logicExpression) && - const DeepCollectionEquality() - .equals(other.visualDesigned, visualDesigned) && - const DeepCollectionEquality() - .equals(other._dependencies, _dependencies)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(componentId), - const DeepCollectionEquality().hash(componentName), - const DeepCollectionEquality().hash(componentDescription), - const DeepCollectionEquality().hash(_inputs), - const DeepCollectionEquality().hash(_outputs), - const DeepCollectionEquality().hash(_truthTable), - const DeepCollectionEquality().hash(_logicExpression), - const DeepCollectionEquality().hash(visualDesigned), - const DeepCollectionEquality().hash(_dependencies)); - - @JsonKey(ignore: true) - @override - _$$_ComponentEntryCopyWith<_$_ComponentEntry> get copyWith => - __$$_ComponentEntryCopyWithImpl<_$_ComponentEntry>(this, _$identity); - - @override - Map toJson() { - return _$$_ComponentEntryToJson(this); - } -} - -abstract class _ComponentEntry implements ComponentEntry { - const factory _ComponentEntry( - {required final String componentId, - required final String componentName, - @JsonKey(includeIfNull: false) - final String? componentDescription, - required final List inputs, - required final List outputs, - @JsonKey(includeIfNull: false) - final List? truthTable, - @JsonKey(includeIfNull: false) - final List? logicExpression, - @JsonKey(defaultValue: false) - required final bool visualDesigned, - @JsonKey(defaultValue: []) - required final List dependencies}) = _$_ComponentEntry; - - factory _ComponentEntry.fromJson(Map json) = - _$_ComponentEntry.fromJson; - - @override - String get componentId => throw _privateConstructorUsedError; - @override - String get componentName => throw _privateConstructorUsedError; - @override - @JsonKey(includeIfNull: false) - String? get componentDescription => throw _privateConstructorUsedError; - @override - List get inputs => throw _privateConstructorUsedError; - @override - List get outputs => throw _privateConstructorUsedError; - @override - @JsonKey(includeIfNull: false) - List? get truthTable => throw _privateConstructorUsedError; - @override - @JsonKey(includeIfNull: false) - List? get logicExpression => throw _privateConstructorUsedError; - @override - @JsonKey(defaultValue: false) - bool get visualDesigned => throw _privateConstructorUsedError; - @override - @JsonKey(defaultValue: []) - List get dependencies => throw _privateConstructorUsedError; - @override - @JsonKey(ignore: true) - _$$_ComponentEntryCopyWith<_$_ComponentEntry> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/project.g.dart b/lib/models/project.g.dart index 7152826..382eba5 100644 --- a/lib/models/project.g.dart +++ b/lib/models/project.g.dart @@ -17,47 +17,3 @@ Map _$$_ProjectIndexToJson(_$_ProjectIndex instance) => { 'components': instance.components, }; - -_$_ComponentEntry _$$_ComponentEntryFromJson(Map json) => - _$_ComponentEntry( - componentId: json['componentId'] as String, - componentName: json['componentName'] as String, - componentDescription: json['componentDescription'] as String?, - inputs: - (json['inputs'] as List).map((e) => e as String).toList(), - outputs: - (json['outputs'] as List).map((e) => e as String).toList(), - truthTable: (json['truthTable'] as List?) - ?.map((e) => e as String) - .toList(), - logicExpression: (json['logicExpression'] as List?) - ?.map((e) => e as String) - .toList(), - visualDesigned: json['visualDesigned'] as bool? ?? false, - dependencies: (json['dependencies'] as List?) - ?.map((e) => e as String) - .toList() ?? - [], - ); - -Map _$$_ComponentEntryToJson(_$_ComponentEntry instance) { - final val = { - 'componentId': instance.componentId, - 'componentName': instance.componentName, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('componentDescription', instance.componentDescription); - val['inputs'] = instance.inputs; - val['outputs'] = instance.outputs; - writeNotNull('truthTable', instance.truthTable); - writeNotNull('logicExpression', instance.logicExpression); - val['visualDesigned'] = instance.visualDesigned; - val['dependencies'] = instance.dependencies; - return val; -} diff --git a/lib/models/wiring.dart b/lib/models/wiring.dart new file mode 100644 index 0000000..4856ea3 --- /dev/null +++ b/lib/models/wiring.dart @@ -0,0 +1,35 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'wiring.freezed.dart'; +part 'wiring.g.dart'; + +@freezed +class Wiring with _$Wiring { + const factory Wiring({ + required List instances, + required List wires, + }) = _Wiring; + + factory Wiring.fromJson(Map json) => _$WiringFromJson(json); +} + +@freezed +class WiringInstance with _$WiringInstance { + const factory WiringInstance({ + required String instanceId, + required String componentId, + }) = _WiringInstance; + + factory WiringInstance.fromJson(Map json) => _$WiringInstanceFromJson(json); +} + +@freezed +class WiringWire with _$WiringWire { + const factory WiringWire({ + required String wireId, + required String output, + required String input, + }) = _WiringWire; + + factory WiringWire.fromJson(Map json) => _$WiringWireFromJson(json); +} diff --git a/lib/models/wiring.freezed.dart b/lib/models/wiring.freezed.dart new file mode 100644 index 0000000..4bab8f6 --- /dev/null +++ b/lib/models/wiring.freezed.dart @@ -0,0 +1,497 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target + +part of 'wiring.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +Wiring _$WiringFromJson(Map json) { + return _Wiring.fromJson(json); +} + +/// @nodoc +mixin _$Wiring { + List get instances => throw _privateConstructorUsedError; + List get wires => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $WiringCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WiringCopyWith<$Res> { + factory $WiringCopyWith(Wiring value, $Res Function(Wiring) then) = + _$WiringCopyWithImpl<$Res>; + $Res call({List instances, List wires}); +} + +/// @nodoc +class _$WiringCopyWithImpl<$Res> implements $WiringCopyWith<$Res> { + _$WiringCopyWithImpl(this._value, this._then); + + final Wiring _value; + // ignore: unused_field + final $Res Function(Wiring) _then; + + @override + $Res call({ + Object? instances = freezed, + Object? wires = freezed, + }) { + return _then(_value.copyWith( + instances: instances == freezed + ? _value.instances + : instances // ignore: cast_nullable_to_non_nullable + as List, + wires: wires == freezed + ? _value.wires + : wires // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +abstract class _$$_WiringCopyWith<$Res> implements $WiringCopyWith<$Res> { + factory _$$_WiringCopyWith(_$_Wiring value, $Res Function(_$_Wiring) then) = + __$$_WiringCopyWithImpl<$Res>; + @override + $Res call({List instances, List wires}); +} + +/// @nodoc +class __$$_WiringCopyWithImpl<$Res> extends _$WiringCopyWithImpl<$Res> + implements _$$_WiringCopyWith<$Res> { + __$$_WiringCopyWithImpl(_$_Wiring _value, $Res Function(_$_Wiring) _then) + : super(_value, (v) => _then(v as _$_Wiring)); + + @override + _$_Wiring get _value => super._value as _$_Wiring; + + @override + $Res call({ + Object? instances = freezed, + Object? wires = freezed, + }) { + return _then(_$_Wiring( + instances: instances == freezed + ? _value._instances + : instances // ignore: cast_nullable_to_non_nullable + as List, + wires: wires == freezed + ? _value._wires + : wires // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_Wiring implements _Wiring { + const _$_Wiring( + {required final List instances, + required final List wires}) + : _instances = instances, + _wires = wires; + + factory _$_Wiring.fromJson(Map json) => + _$$_WiringFromJson(json); + + final List _instances; + @override + List get instances { + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_instances); + } + + final List _wires; + @override + List get wires { + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_wires); + } + + @override + String toString() { + return 'Wiring(instances: $instances, wires: $wires)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Wiring && + const DeepCollectionEquality() + .equals(other._instances, _instances) && + const DeepCollectionEquality().equals(other._wires, _wires)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_instances), + const DeepCollectionEquality().hash(_wires)); + + @JsonKey(ignore: true) + @override + _$$_WiringCopyWith<_$_Wiring> get copyWith => + __$$_WiringCopyWithImpl<_$_Wiring>(this, _$identity); + + @override + Map toJson() { + return _$$_WiringToJson(this); + } +} + +abstract class _Wiring implements Wiring { + const factory _Wiring( + {required final List instances, + required final List wires}) = _$_Wiring; + + factory _Wiring.fromJson(Map json) = _$_Wiring.fromJson; + + @override + List get instances => throw _privateConstructorUsedError; + @override + List get wires => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$$_WiringCopyWith<_$_Wiring> get copyWith => + throw _privateConstructorUsedError; +} + +WiringInstance _$WiringInstanceFromJson(Map json) { + return _WiringInstance.fromJson(json); +} + +/// @nodoc +mixin _$WiringInstance { + String get instanceId => throw _privateConstructorUsedError; + String get componentId => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $WiringInstanceCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WiringInstanceCopyWith<$Res> { + factory $WiringInstanceCopyWith( + WiringInstance value, $Res Function(WiringInstance) then) = + _$WiringInstanceCopyWithImpl<$Res>; + $Res call({String instanceId, String componentId}); +} + +/// @nodoc +class _$WiringInstanceCopyWithImpl<$Res> + implements $WiringInstanceCopyWith<$Res> { + _$WiringInstanceCopyWithImpl(this._value, this._then); + + final WiringInstance _value; + // ignore: unused_field + final $Res Function(WiringInstance) _then; + + @override + $Res call({ + Object? instanceId = freezed, + Object? componentId = freezed, + }) { + return _then(_value.copyWith( + instanceId: instanceId == freezed + ? _value.instanceId + : instanceId // ignore: cast_nullable_to_non_nullable + as String, + componentId: componentId == freezed + ? _value.componentId + : componentId // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +abstract class _$$_WiringInstanceCopyWith<$Res> + implements $WiringInstanceCopyWith<$Res> { + factory _$$_WiringInstanceCopyWith( + _$_WiringInstance value, $Res Function(_$_WiringInstance) then) = + __$$_WiringInstanceCopyWithImpl<$Res>; + @override + $Res call({String instanceId, String componentId}); +} + +/// @nodoc +class __$$_WiringInstanceCopyWithImpl<$Res> + extends _$WiringInstanceCopyWithImpl<$Res> + implements _$$_WiringInstanceCopyWith<$Res> { + __$$_WiringInstanceCopyWithImpl( + _$_WiringInstance _value, $Res Function(_$_WiringInstance) _then) + : super(_value, (v) => _then(v as _$_WiringInstance)); + + @override + _$_WiringInstance get _value => super._value as _$_WiringInstance; + + @override + $Res call({ + Object? instanceId = freezed, + Object? componentId = freezed, + }) { + return _then(_$_WiringInstance( + instanceId: instanceId == freezed + ? _value.instanceId + : instanceId // ignore: cast_nullable_to_non_nullable + as String, + componentId: componentId == freezed + ? _value.componentId + : componentId // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_WiringInstance implements _WiringInstance { + const _$_WiringInstance( + {required this.instanceId, required this.componentId}); + + factory _$_WiringInstance.fromJson(Map json) => + _$$_WiringInstanceFromJson(json); + + @override + final String instanceId; + @override + final String componentId; + + @override + String toString() { + return 'WiringInstance(instanceId: $instanceId, componentId: $componentId)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_WiringInstance && + const DeepCollectionEquality() + .equals(other.instanceId, instanceId) && + const DeepCollectionEquality() + .equals(other.componentId, componentId)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(instanceId), + const DeepCollectionEquality().hash(componentId)); + + @JsonKey(ignore: true) + @override + _$$_WiringInstanceCopyWith<_$_WiringInstance> get copyWith => + __$$_WiringInstanceCopyWithImpl<_$_WiringInstance>(this, _$identity); + + @override + Map toJson() { + return _$$_WiringInstanceToJson(this); + } +} + +abstract class _WiringInstance implements WiringInstance { + const factory _WiringInstance( + {required final String instanceId, + required final String componentId}) = _$_WiringInstance; + + factory _WiringInstance.fromJson(Map json) = + _$_WiringInstance.fromJson; + + @override + String get instanceId => throw _privateConstructorUsedError; + @override + String get componentId => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$$_WiringInstanceCopyWith<_$_WiringInstance> get copyWith => + throw _privateConstructorUsedError; +} + +WiringWire _$WiringWireFromJson(Map json) { + return _WiringWire.fromJson(json); +} + +/// @nodoc +mixin _$WiringWire { + String get wireId => throw _privateConstructorUsedError; + String get output => throw _privateConstructorUsedError; + String get input => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $WiringWireCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $WiringWireCopyWith<$Res> { + factory $WiringWireCopyWith( + WiringWire value, $Res Function(WiringWire) then) = + _$WiringWireCopyWithImpl<$Res>; + $Res call({String wireId, String output, String input}); +} + +/// @nodoc +class _$WiringWireCopyWithImpl<$Res> implements $WiringWireCopyWith<$Res> { + _$WiringWireCopyWithImpl(this._value, this._then); + + final WiringWire _value; + // ignore: unused_field + final $Res Function(WiringWire) _then; + + @override + $Res call({ + Object? wireId = freezed, + Object? output = freezed, + Object? input = freezed, + }) { + return _then(_value.copyWith( + wireId: wireId == freezed + ? _value.wireId + : wireId // ignore: cast_nullable_to_non_nullable + as String, + output: output == freezed + ? _value.output + : output // ignore: cast_nullable_to_non_nullable + as String, + input: input == freezed + ? _value.input + : input // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +abstract class _$$_WiringWireCopyWith<$Res> + implements $WiringWireCopyWith<$Res> { + factory _$$_WiringWireCopyWith( + _$_WiringWire value, $Res Function(_$_WiringWire) then) = + __$$_WiringWireCopyWithImpl<$Res>; + @override + $Res call({String wireId, String output, String input}); +} + +/// @nodoc +class __$$_WiringWireCopyWithImpl<$Res> extends _$WiringWireCopyWithImpl<$Res> + implements _$$_WiringWireCopyWith<$Res> { + __$$_WiringWireCopyWithImpl( + _$_WiringWire _value, $Res Function(_$_WiringWire) _then) + : super(_value, (v) => _then(v as _$_WiringWire)); + + @override + _$_WiringWire get _value => super._value as _$_WiringWire; + + @override + $Res call({ + Object? wireId = freezed, + Object? output = freezed, + Object? input = freezed, + }) { + return _then(_$_WiringWire( + wireId: wireId == freezed + ? _value.wireId + : wireId // ignore: cast_nullable_to_non_nullable + as String, + output: output == freezed + ? _value.output + : output // ignore: cast_nullable_to_non_nullable + as String, + input: input == freezed + ? _value.input + : input // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_WiringWire implements _WiringWire { + const _$_WiringWire( + {required this.wireId, required this.output, required this.input}); + + factory _$_WiringWire.fromJson(Map json) => + _$$_WiringWireFromJson(json); + + @override + final String wireId; + @override + final String output; + @override + final String input; + + @override + String toString() { + return 'WiringWire(wireId: $wireId, output: $output, input: $input)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_WiringWire && + const DeepCollectionEquality().equals(other.wireId, wireId) && + const DeepCollectionEquality().equals(other.output, output) && + const DeepCollectionEquality().equals(other.input, input)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(wireId), + const DeepCollectionEquality().hash(output), + const DeepCollectionEquality().hash(input)); + + @JsonKey(ignore: true) + @override + _$$_WiringWireCopyWith<_$_WiringWire> get copyWith => + __$$_WiringWireCopyWithImpl<_$_WiringWire>(this, _$identity); + + @override + Map toJson() { + return _$$_WiringWireToJson(this); + } +} + +abstract class _WiringWire implements WiringWire { + const factory _WiringWire( + {required final String wireId, + required final String output, + required final String input}) = _$_WiringWire; + + factory _WiringWire.fromJson(Map json) = + _$_WiringWire.fromJson; + + @override + String get wireId => throw _privateConstructorUsedError; + @override + String get output => throw _privateConstructorUsedError; + @override + String get input => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$$_WiringWireCopyWith<_$_WiringWire> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/wiring.g.dart b/lib/models/wiring.g.dart new file mode 100644 index 0000000..6d1ee03 --- /dev/null +++ b/lib/models/wiring.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'wiring.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_Wiring _$$_WiringFromJson(Map json) => _$_Wiring( + instances: (json['instances'] as List) + .map((e) => WiringInstance.fromJson(e as Map)) + .toList(), + wires: (json['wires'] as List) + .map((e) => WiringWire.fromJson(e as Map)) + .toList(), + ); + +Map _$$_WiringToJson(_$_Wiring instance) => { + 'instances': instance.instances, + 'wires': instance.wires, + }; + +_$_WiringInstance _$$_WiringInstanceFromJson(Map json) => + _$_WiringInstance( + instanceId: json['instanceId'] as String, + componentId: json['componentId'] as String, + ); + +Map _$$_WiringInstanceToJson(_$_WiringInstance instance) => + { + 'instanceId': instance.instanceId, + 'componentId': instance.componentId, + }; + +_$_WiringWire _$$_WiringWireFromJson(Map json) => + _$_WiringWire( + wireId: json['wireId'] as String, + output: json['output'] as String, + input: json['input'] as String, + ); + +Map _$$_WiringWireToJson(_$_WiringWire instance) => + { + 'wireId': instance.wireId, + 'output': instance.output, + 'input': instance.input, + }; diff --git a/lib/pages/design_component.dart b/lib/pages/design_component.dart new file mode 100644 index 0000000..cc4a841 --- /dev/null +++ b/lib/pages/design_component.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:logic_circuits_simulator/models.dart'; +import 'package:logic_circuits_simulator/pages_arguments/design_component.dart'; +import 'package:logic_circuits_simulator/state/component.dart'; +import 'package:logic_circuits_simulator/utils/provider_hook.dart'; +import 'package:logic_circuits_simulator/utils/stack_canvas_controller_hook.dart'; +import 'package:stack_canvas/stack_canvas.dart'; + +class DesignComponentPage extends HookWidget { + final ComponentEntry component; + + const DesignComponentPage({required this.component, super.key}); + DesignComponentPage.fromArguments(DesignComponentPageArguments args, {super.key}) + : component = args.component; + + static const String routeName = '/project/component/design'; + + @override + Widget build(BuildContext context) { + final componentState = useProvider(); + final canvasController = useStackCanvasController(); + final widgets = useState(>[]); + useEffect(() { + canvasController.addCanvasObjects(widgets.value); + + return () { + // Cleanup + canvasController.clearCanvas(); + }; + }, [widgets]); + + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text('Design - ${component.componentName}'), + ), + body: OrientationBuilder( + builder: (context, orientation) { + if (orientation == Orientation.portrait) { + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: StackCanvas( + canvasController: canvasController, + backgroundColor: Theme.of(context).colorScheme.background, + ), + ), + ], + ); + } + else { + return Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: StackCanvas( + canvasController: canvasController, + ), + ), + ], + ); + } + } + ), + ); + } +} diff --git a/lib/pages/edit_component.dart b/lib/pages/edit_component.dart index ec3d113..a471176 100644 --- a/lib/pages/edit_component.dart +++ b/lib/pages/edit_component.dart @@ -6,18 +6,28 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:logic_circuits_simulator/components/logic_expression_field.dart'; import 'package:logic_circuits_simulator/components/truth_table.dart'; import 'package:logic_circuits_simulator/dialogs/new_ask_for_name.dart'; -import 'package:logic_circuits_simulator/models/project.dart'; +import 'package:logic_circuits_simulator/dialogs/unsatisfied_dependencies.dart'; +import 'package:logic_circuits_simulator/models.dart'; +import 'package:logic_circuits_simulator/pages/design_component.dart'; +import 'package:logic_circuits_simulator/pages_arguments/design_component.dart'; +import 'package:logic_circuits_simulator/pages_arguments/edit_component.dart'; +import 'package:logic_circuits_simulator/state/component.dart'; import 'package:logic_circuits_simulator/state/project.dart'; +import 'package:logic_circuits_simulator/state/projects.dart'; import 'package:logic_circuits_simulator/utils/iterable_extension.dart'; import 'package:logic_circuits_simulator/utils/logic_expressions.dart'; import 'package:logic_circuits_simulator/utils/logic_operators.dart'; import 'package:logic_circuits_simulator/utils/provider_hook.dart'; +import 'package:provider/provider.dart'; +import 'package:tuple/tuple.dart'; class EditComponentPage extends HookWidget { final bool newComponent; final ComponentEntry component; - const EditComponentPage({Key? key, this.newComponent = false, required this.component}) : super(key: key); + const EditComponentPage({super.key, this.newComponent = false, required this.component}); + EditComponentPage.fromArguments(EditComponentPageArguments args, {super.key}) + : component = args.component, newComponent = args.newComponent; static const String routeName = '/project/component/edit'; @@ -63,7 +73,7 @@ class EditComponentPage extends HookWidget { return false; } - if (componentNameEditingController.text != ce().componentName) { + if (componentNameEditingController.text.trim() != ce().componentName.trim()) { return true; } if (!le.equals(inputs.value, ce().inputs)) { @@ -456,7 +466,7 @@ class EditComponentPage extends HookWidget { padding: EdgeInsets.all(8.0), child: OutlinedButton( onPressed: null, - child: const Text('Script'), + child: Text('Script'), ), ), ], @@ -563,9 +573,51 @@ class EditComponentPage extends HookWidget { ) else Padding( padding: const EdgeInsets.all(8.0), child: ElevatedButton( - // TODO: Implement visual designer - onPressed: null, - child: Text('Open Designer'), + onPressed: () async { + final nav = Navigator.of(context); + final projectsState = Provider.of(context, listen: false); + try { + await Provider.of(context, listen: false).setCurrentComponent( + project: projectState.currentProject!, + component: component, + onDependencyNeeded: (String projectId, String componentId) async { + if (projectId == 'self') { + final maybeComponent = projectState.index.components.where((c) => c.componentId == componentId).firstOrNull; + return maybeComponent == null ? null : Tuple2(projectState.currentProject!, maybeComponent); + } + else { + final maybeProject = projectsState.projects.where((p) => p.projectId == projectId).firstOrNull; + if (maybeProject == null) { + return null; + } + final projectState = ProjectState(); + await projectState.setCurrentProject(maybeProject); + final maybeComponent = projectState.index.components.where((c) => c.componentId == componentId).firstOrNull; + if (maybeComponent == null) { + return null; + } + return Tuple2(maybeProject, maybeComponent); + } + }, + ); + nav.pushNamed( + DesignComponentPage.routeName, + arguments: DesignComponentPageArguments( + component: component, + ), + ); + } on DependenciesNotSatisfiedException catch (e) { + showDialog( + context: context, + builder: (context) { + return UnsatisfiedDependenciesDialog( + dependencies: e.dependencies, + ); + } + ); + } + }, + child: const Text('Open Designer'), ), ), ], diff --git a/lib/pages/project.dart b/lib/pages/project.dart index c920e3c..78a77a4 100644 --- a/lib/pages/project.dart +++ b/lib/pages/project.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:logic_circuits_simulator/models/project.dart'; +import 'package:logic_circuits_simulator/models.dart'; import 'package:logic_circuits_simulator/pages/edit_component.dart'; import 'package:logic_circuits_simulator/pages_arguments/edit_component.dart'; import 'package:logic_circuits_simulator/state/project.dart'; diff --git a/lib/pages/projects.dart b/lib/pages/projects.dart index b5a3ab0..b261b20 100644 --- a/lib/pages/projects.dart +++ b/lib/pages/projects.dart @@ -5,7 +5,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:logic_circuits_simulator/dialogs/new_project.dart'; -import 'package:logic_circuits_simulator/models/projects.dart'; +import 'package:logic_circuits_simulator/models.dart'; import 'package:logic_circuits_simulator/pages/project.dart'; import 'package:logic_circuits_simulator/state/project.dart'; import 'package:logic_circuits_simulator/state/projects.dart'; @@ -58,7 +58,7 @@ class ProjectsPage extends StatelessWidget { } void onProjectSelect(BuildContext context, ProjectEntry p) { - Provider.of(context, listen: false).currentProject = p; + Provider.of(context, listen: false).setCurrentProject(p); Provider.of(context, listen: false).registerSaveHandler((p) async { await Provider.of(context, listen: false).updateProject(p); }); diff --git a/lib/pages_arguments/design_component.dart b/lib/pages_arguments/design_component.dart new file mode 100644 index 0000000..e6d610e --- /dev/null +++ b/lib/pages_arguments/design_component.dart @@ -0,0 +1,11 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:logic_circuits_simulator/models.dart'; + +part 'design_component.freezed.dart'; + +@freezed +class DesignComponentPageArguments with _$DesignComponentPageArguments { + const factory DesignComponentPageArguments({ + required ComponentEntry component, + }) = _DesignComponentPageArguments; +} diff --git a/lib/pages_arguments/design_component.freezed.dart b/lib/pages_arguments/design_component.freezed.dart new file mode 100644 index 0000000..49c05b1 --- /dev/null +++ b/lib/pages_arguments/design_component.freezed.dart @@ -0,0 +1,150 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target + +part of 'design_component.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$DesignComponentPageArguments { + ComponentEntry get component => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $DesignComponentPageArgumentsCopyWith + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DesignComponentPageArgumentsCopyWith<$Res> { + factory $DesignComponentPageArgumentsCopyWith( + DesignComponentPageArguments value, + $Res Function(DesignComponentPageArguments) then) = + _$DesignComponentPageArgumentsCopyWithImpl<$Res>; + $Res call({ComponentEntry component}); + + $ComponentEntryCopyWith<$Res> get component; +} + +/// @nodoc +class _$DesignComponentPageArgumentsCopyWithImpl<$Res> + implements $DesignComponentPageArgumentsCopyWith<$Res> { + _$DesignComponentPageArgumentsCopyWithImpl(this._value, this._then); + + final DesignComponentPageArguments _value; + // ignore: unused_field + final $Res Function(DesignComponentPageArguments) _then; + + @override + $Res call({ + Object? component = freezed, + }) { + return _then(_value.copyWith( + component: component == freezed + ? _value.component + : component // ignore: cast_nullable_to_non_nullable + as ComponentEntry, + )); + } + + @override + $ComponentEntryCopyWith<$Res> get component { + return $ComponentEntryCopyWith<$Res>(_value.component, (value) { + return _then(_value.copyWith(component: value)); + }); + } +} + +/// @nodoc +abstract class _$$_DesignComponentPageArgumentsCopyWith<$Res> + implements $DesignComponentPageArgumentsCopyWith<$Res> { + factory _$$_DesignComponentPageArgumentsCopyWith( + _$_DesignComponentPageArguments value, + $Res Function(_$_DesignComponentPageArguments) then) = + __$$_DesignComponentPageArgumentsCopyWithImpl<$Res>; + @override + $Res call({ComponentEntry component}); + + @override + $ComponentEntryCopyWith<$Res> get component; +} + +/// @nodoc +class __$$_DesignComponentPageArgumentsCopyWithImpl<$Res> + extends _$DesignComponentPageArgumentsCopyWithImpl<$Res> + implements _$$_DesignComponentPageArgumentsCopyWith<$Res> { + __$$_DesignComponentPageArgumentsCopyWithImpl( + _$_DesignComponentPageArguments _value, + $Res Function(_$_DesignComponentPageArguments) _then) + : super(_value, (v) => _then(v as _$_DesignComponentPageArguments)); + + @override + _$_DesignComponentPageArguments get _value => + super._value as _$_DesignComponentPageArguments; + + @override + $Res call({ + Object? component = freezed, + }) { + return _then(_$_DesignComponentPageArguments( + component: component == freezed + ? _value.component + : component // ignore: cast_nullable_to_non_nullable + as ComponentEntry, + )); + } +} + +/// @nodoc + +class _$_DesignComponentPageArguments implements _DesignComponentPageArguments { + const _$_DesignComponentPageArguments({required this.component}); + + @override + final ComponentEntry component; + + @override + String toString() { + return 'DesignComponentPageArguments(component: $component)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_DesignComponentPageArguments && + const DeepCollectionEquality().equals(other.component, component)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(component)); + + @JsonKey(ignore: true) + @override + _$$_DesignComponentPageArgumentsCopyWith<_$_DesignComponentPageArguments> + get copyWith => __$$_DesignComponentPageArgumentsCopyWithImpl< + _$_DesignComponentPageArguments>(this, _$identity); +} + +abstract class _DesignComponentPageArguments + implements DesignComponentPageArguments { + const factory _DesignComponentPageArguments( + {required final ComponentEntry component}) = + _$_DesignComponentPageArguments; + + @override + ComponentEntry get component => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + _$$_DesignComponentPageArgumentsCopyWith<_$_DesignComponentPageArguments> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/pages_arguments/edit_component.dart b/lib/pages_arguments/edit_component.dart index 3901484..d88d847 100644 --- a/lib/pages_arguments/edit_component.dart +++ b/lib/pages_arguments/edit_component.dart @@ -1,5 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:logic_circuits_simulator/models/project.dart'; +import 'package:logic_circuits_simulator/models.dart'; part 'edit_component.freezed.dart'; diff --git a/lib/state/component.dart b/lib/state/component.dart new file mode 100644 index 0000000..b4a476b --- /dev/null +++ b/lib/state/component.dart @@ -0,0 +1,135 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:logic_circuits_simulator/models.dart'; +import 'package:logic_circuits_simulator/utils/simulation.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; +import 'package:tuple/tuple.dart'; + +class ComponentState extends ChangeNotifier { + ProjectEntry? _currentProject; + ComponentEntry? _currentComponent; + Wiring _wiring = const Wiring(instances: [], wires: []); + SimulatedComponent? _simulatedComponent; + + final Map> _dependenciesMap = {}; + + ProjectEntry? get currentProject => _currentProject; + ComponentEntry? get currentComponent => _currentComponent; + Wiring get wiring => _wiring; + + Future _getComponentDir() async { + if (_currentProject == null) { + throw Exception('Cannot get component directory without knowing project'); + } + if (_currentComponent == null) { + throw Exception('Cannot get component directory of null'); + } + final appDir = await getApplicationDocumentsDirectory(); + final result = Directory(path.join(appDir.path, 'LogicCircuitsSimulator', 'projects', _currentProject!.projectId, 'components', _currentComponent!.componentId)); + if (!await result.exists()) { + await result.create(recursive: true); + } + return result; + } + + Future _getWiringFile() async { + final result = File(path.join((await _getComponentDir()).path, 'wiring.json')); + return result; + } + + Future _loadComponentFiles() async { + final wiringFile = await _getWiringFile(); + if (!await wiringFile.exists()) { + _wiring = const Wiring(instances: [], wires: []); + await wiringFile.writeAsString(jsonEncode(_wiring)); + } + else { + _wiring = Wiring.fromJson(jsonDecode(await wiringFile.readAsString())); + } + } + + Future setCurrentComponent({ + required ProjectEntry project, + required ComponentEntry component, + required Future?> Function(String projectId, String componentId) onDependencyNeeded, + }) async { + _dependenciesMap.clear(); + _simulatedComponent = null; + + _currentProject = project; + _currentComponent = component; + + // Load dependencies + final unsatisfiedDependencies = []; + for (final depId in component.dependencies) { + final splitted = depId.split('/'); + final maybeDep = await onDependencyNeeded(splitted[0], splitted[1]); + if (maybeDep == null) { + unsatisfiedDependencies.add(depId); + } + else { + _dependenciesMap[depId] = maybeDep; + } + } + if (unsatisfiedDependencies.isNotEmpty) { + throw DependenciesNotSatisfiedException(dependencies: unsatisfiedDependencies); + } + + return _loadComponentFiles().then((_) => notifyListeners()); + } + + void noComponent() { + _dependenciesMap.clear(); + _currentProject = null; + _currentComponent = null; + _wiring = const Wiring(instances: [], wires: []); + _simulatedComponent = null; + + notifyListeners(); + } + + Future> simulate(Map inputs) async { + Future onRequiredDependency(String depId) async { + final t = _dependenciesMap[depId]!; + final proj = t.item1; + final comp = t.item2; + final state = comp.visualDesigned ? ComponentState() : null; + if (state != null) { + await state.setCurrentComponent( + project: proj, + component: comp, + onDependencyNeeded: (projId, compId) async => _dependenciesMap['$projId/$compId'], + ); + } + return SimulatedComponent( + project: proj, + component: comp, + onRequiredDependency: onRequiredDependency, + state: state, + ); + } + + _simulatedComponent ??= SimulatedComponent( + project: _currentProject!, + component: _currentComponent!, + onRequiredDependency: onRequiredDependency, + state: this, + ); + + return _simulatedComponent!.simulate(inputs); + } +} + +class DependenciesNotSatisfiedException with Exception { + final List dependencies; + + const DependenciesNotSatisfiedException({required this.dependencies}); + + @override + String toString() { + return 'DependenciesNotSatisfiedException(${dependencies.join(", ")})'; + } +} diff --git a/lib/state/project.dart b/lib/state/project.dart index 191f77b..9655145 100644 --- a/lib/state/project.dart +++ b/lib/state/project.dart @@ -2,8 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; -import 'package:logic_circuits_simulator/models/project.dart'; -import 'package:logic_circuits_simulator/models/projects.dart'; +import 'package:logic_circuits_simulator/models.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; import 'package:uuid/uuid.dart'; @@ -55,9 +54,9 @@ class ProjectState extends ChangeNotifier { notifyListeners(); } - set currentProject(ProjectEntry? p) { + Future setCurrentProject(ProjectEntry? p) { _currentProject = p; - _loadProjectFiles().then((_) => notifyListeners()); + return _loadProjectFiles().then((_) => notifyListeners()); } void noProject() { diff --git a/lib/state/projects.dart b/lib/state/projects.dart index 3828188..13a0256 100644 --- a/lib/state/projects.dart +++ b/lib/state/projects.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:archive/archive_io.dart'; import 'package:flutter/foundation.dart'; -import 'package:logic_circuits_simulator/models/projects.dart'; +import 'package:logic_circuits_simulator/models.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; import 'package:uuid/uuid.dart'; diff --git a/lib/utils/simulation.dart b/lib/utils/simulation.dart new file mode 100644 index 0000000..1444aba --- /dev/null +++ b/lib/utils/simulation.dart @@ -0,0 +1,127 @@ +import 'package:logic_circuits_simulator/models.dart'; +import 'package:logic_circuits_simulator/state/component.dart'; +import 'package:logic_circuits_simulator/utils/iterable_extension.dart'; +import 'package:logic_circuits_simulator/utils/logic_expressions.dart'; + +class SimulatedComponent { + final ProjectEntry project; + final ComponentEntry component; + final ComponentState? state; + final Future Function(String depId) onRequiredDependency; + final _instances = {}; + + SimulatedComponent({ + required this.project, + required this.component, + required this.onRequiredDependency, + this.state + }); + + Future _getInstance(String instanceId, String? depId) async { + if (!_instances.containsKey(instanceId)) { + if (depId != null) { + _instances[instanceId] = await onRequiredDependency(depId); + } + else { + throw Exception('Attempted to get instance of unknown component'); + } + } + return _instances[instanceId]!; + } + + Future> simulate(Map inputs) async { + final input = int.parse(component.inputs.map((input) => inputs[input]! ? '1' : '0').join(), radix: 2); + if (component.truthTable != null) { + final output = component.truthTable![input]; + return { + for (final it in component.outputs.indexedMap((index, outName) => [outName, output[index]])) + it[0] : it[1] == '1' + }; + } + else if (component.logicExpression != null) { + // Somehow? + // A truth table should be automatically generated for every logic expression component. + // Might as well handle cases where that isn't done anyway. + final results = component.outputs.zipWith( + [component.logicExpression!], + (zips) { + final output = zips[0]; + final le = LogicExpression.parse(zips[1]); + return [output, le.evaluate(inputs)]; + }, + ); + return { + for (final it in results) + it[0] as String : it[1] as bool + }; + } + else if (state == null) { + throw Exception('Cannot simulate designed component without its state'); + } + else { + // Create instances + final wiring = state!.wiring; + for (final instance in wiring.instances) { + _getInstance(instance.instanceId, instance.componentId); + } + + // Simulate + final requiredSinks = [ + ...component.outputs.map((output) => 'self/$output'), + ]; + final knownSources = { + for (final entry in inputs.entries) + 'self/${entry.key}': entry.value + }; + final knownSinks = {}; + + while (requiredSinks.isNotEmpty) { + final sink = requiredSinks.removeAt(0); + // C-SOURCE - WIRE-OUT -> WIRE-IN - C-SINK + if (knownSinks.containsKey(sink)) { + // Requirement satisfied + continue; + } + else { + // Find wire that provides sink + final wire = wiring.wires.where((wire) => wire.input == sink).first; + if (knownSources.containsKey(wire.output)) { + // If we know the output provided through the wire, + // we know the input provided to the sink + knownSinks[sink] = knownSources[wire.output]!; + } + else { + // The instance providing the source for the wire has not been simulated. + // See if all its sinks are known: + final instanceId = wire.output.split('/')[0]; + final instance = await _getInstance(instanceId, null); + final depSinks = instance.component.inputs.map((input) => '$instanceId/$input').toList(); + if (depSinks.map((depSink) => !knownSinks.containsKey(depSink)).where((cond) => cond).isEmpty) { + // If so, then simulate + final results = await instance.simulate({ + for (final depSink in depSinks) + depSink.split('/')[1] : knownSinks[depSink]! + }); + knownSources.addAll({ + for (final result in results.entries) + '$instanceId/${result.key}' : result.value + }); + // And resolve needed sink + knownSinks[sink] = knownSources[wire.output]!; + } + else { + // Otherwise, require the sinks and reschedule the current one + requiredSinks.addAll(depSinks.where((depSink) => !knownSinks.containsKey(depSink))); + requiredSinks.add(sink); + } + } + } + } + + return { + for (final output in component.outputs) + output : knownSinks['self/$output']! + }; + } + } +} \ No newline at end of file diff --git a/lib/utils/stack_canvas_controller_hook.dart b/lib/utils/stack_canvas_controller_hook.dart new file mode 100644 index 0000000..867e3fc --- /dev/null +++ b/lib/utils/stack_canvas_controller_hook.dart @@ -0,0 +1,62 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:stack_canvas/stack_canvas.dart'; + +StackCanvasController useStackCanvasController({ + double zoomChangeUnit = 0.10, + double moveChangeUnit = 30.00, + Reference offsetReference = Reference.TopLeft, + Reference zoomReference = Reference.TopLeft, +}) { + return use(_StackCanvasControllerHookCreator( + moveChangeUnit: moveChangeUnit, + offsetReference: offsetReference, + zoomChangeUnit: zoomChangeUnit, + zoomReference: zoomReference, + )); +} + +class _StackCanvasControllerHookCreator extends Hook { + final double zoomChangeUnit; + final double moveChangeUnit; + final Reference offsetReference; + final Reference zoomReference; + + const _StackCanvasControllerHookCreator({ + this.zoomChangeUnit = 0.10, + this.moveChangeUnit = 30.00, + this.offsetReference = Reference.TopLeft, + this.zoomReference = Reference.TopLeft, + }); + + @override + HookState> createState() { + return _StackCanvasControllerHookCreatorState(); + } +} + +class _StackCanvasControllerHookCreatorState extends HookState { + late StackCanvasController _controller; + + @override + void initHook() { + super.initHook(); + _controller = StackCanvasController( + moveChangeUnit: hook.moveChangeUnit, + offsetReference: hook.offsetReference, + zoomChangeUnit: hook.zoomChangeUnit, + zoomReference: hook.zoomReference, + ); + } + + @override + StackCanvasController build(BuildContext context) { + return _controller; + } + + @override + void dispose() { + super.dispose(); + _controller.dispose(); + } +} diff --git a/pubspec.lock b/pubspec.lock index c1e2011..9d7b467 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -485,6 +485,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" share_plus: dependency: "direct main" description: @@ -623,6 +630,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.2" + stack_canvas: + dependency: "direct main" + description: + name: stack_canvas + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0+2" stack_trace: dependency: transitive description: @@ -672,6 +686,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + tuple: + dependency: "direct main" + description: + name: tuple + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0521d2d..a5f613f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,8 @@ dependencies: archive: ^3.3.0 file_picker: ^4.6.1 share_plus: ^4.0.8 + stack_canvas: ^0.2.0+2 + tuple: ^2.0.0 dev_dependencies: flutter_test: