Browse Source

Implemented simulation

For now just the code, without UI that shows the simulation.
However, the code works.
Also added ground work for visual designer.
master
Kenneth Bruen 2 years ago
parent
commit
1e65e42115
Signed by: kbruen
GPG Key ID: C1980A470C3EE5B1
  1. 75
      lib/dialogs/unsatisfied_dependencies.dart
  2. 15
      lib/main.dart
  3. 4
      lib/models.dart
  4. 26
      lib/models/component.dart
  5. 380
      lib/models/component.freezed.dart
  6. 51
      lib/models/component.g.dart
  7. 23
      lib/models/project.dart
  8. 365
      lib/models/project.freezed.dart
  9. 44
      lib/models/project.g.dart
  10. 35
      lib/models/wiring.dart
  11. 497
      lib/models/wiring.freezed.dart
  12. 47
      lib/models/wiring.g.dart
  13. 69
      lib/pages/design_component.dart
  14. 66
      lib/pages/edit_component.dart
  15. 2
      lib/pages/project.dart
  16. 4
      lib/pages/projects.dart
  17. 11
      lib/pages_arguments/design_component.dart
  18. 150
      lib/pages_arguments/design_component.freezed.dart
  19. 2
      lib/pages_arguments/edit_component.dart
  20. 135
      lib/state/component.dart
  21. 7
      lib/state/project.dart
  22. 2
      lib/state/projects.dart
  23. 127
      lib/utils/simulation.dart
  24. 62
      lib/utils/stack_canvas_controller_hook.dart
  25. 21
      pubspec.lock
  26. 2
      pubspec.yaml

75
lib/dialogs/unsatisfied_dependencies.dart

@ -0,0 +1,75 @@
import 'package:flutter/material.dart';
class UnsatisfiedDependenciesDialog extends StatelessWidget {
final List<String> dependencies;
const UnsatisfiedDependenciesDialog({required this.dependencies, super.key});
List<String> get projectIds {
return dependencies
.map((dep) => dep.split('/')[0])
.toSet()
.toList();
}
List<String> 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'),
),
],
);
}
}

15
lib/main.dart

@ -1,11 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/intl_standalone.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/edit_component.dart';
import 'package:logic_circuits_simulator/pages/project.dart'; import 'package:logic_circuits_simulator/pages/project.dart';
import 'package:logic_circuits_simulator/pages/projects.dart'; import 'package:logic_circuits_simulator/pages/projects.dart';
import 'package:logic_circuits_simulator/pages/settings.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/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/project.dart';
import 'package:logic_circuits_simulator/state/projects.dart'; import 'package:logic_circuits_simulator/state/projects.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -29,6 +32,7 @@ class MyApp extends StatelessWidget {
providers: [ providers: [
ChangeNotifierProvider(create: (_) => ProjectsState()), ChangeNotifierProvider(create: (_) => ProjectsState()),
ChangeNotifierProvider(create: (_) => ProjectState()), ChangeNotifierProvider(create: (_) => ProjectState()),
ChangeNotifierProvider(create: (_) => ComponentState()),
], ],
child: MaterialApp( child: MaterialApp(
title: 'Logic Circuits Simulator', title: 'Logic Circuits Simulator',
@ -53,11 +57,12 @@ class MyApp extends StatelessWidget {
return const ProjectPage(); return const ProjectPage();
}, },
EditComponentPage.routeName: (context) { EditComponentPage.routeName: (context) {
final arguments = ModalRoute.of(context)!.settings.arguments as EditComponentPageArguments; final args = ModalRoute.of(context)!.settings.arguments as EditComponentPageArguments;
return EditComponentPage( return EditComponentPage.fromArguments(args);
component: arguments.component, },
newComponent: arguments.newComponent, DesignComponentPage.routeName: (context) {
); final args = ModalRoute.of(context)!.settings.arguments as DesignComponentPageArguments;
return DesignComponentPage.fromArguments(args);
}, },
}, },
initialRoute: MainPage.routeName, initialRoute: MainPage.routeName,

4
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';

26
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<String> inputs,
required List<String> outputs,
@JsonKey(includeIfNull: false)
List<String>? truthTable,
@JsonKey(includeIfNull: false)
List<String>? logicExpression,
@JsonKey(defaultValue: false)
required bool visualDesigned,
@JsonKey(defaultValue: [])
required List<String> dependencies,
}) = _ComponentEntry;
factory ComponentEntry.fromJson(Map<String, Object?> json) => _$ComponentEntryFromJson(json);
}

380
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>(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<String, dynamic> 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<String> get inputs => throw _privateConstructorUsedError;
List<String> get outputs => throw _privateConstructorUsedError;
@JsonKey(includeIfNull: false)
List<String>? get truthTable => throw _privateConstructorUsedError;
@JsonKey(includeIfNull: false)
List<String>? get logicExpression => throw _privateConstructorUsedError;
@JsonKey(defaultValue: false)
bool get visualDesigned => throw _privateConstructorUsedError;
@JsonKey(defaultValue: [])
List<String> get dependencies => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ComponentEntryCopyWith<ComponentEntry> 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<String> inputs,
List<String> outputs,
@JsonKey(includeIfNull: false) List<String>? truthTable,
@JsonKey(includeIfNull: false) List<String>? logicExpression,
@JsonKey(defaultValue: false) bool visualDesigned,
@JsonKey(defaultValue: []) List<String> 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<String>,
outputs: outputs == freezed
? _value.outputs
: outputs // ignore: cast_nullable_to_non_nullable
as List<String>,
truthTable: truthTable == freezed
? _value.truthTable
: truthTable // ignore: cast_nullable_to_non_nullable
as List<String>?,
logicExpression: logicExpression == freezed
? _value.logicExpression
: logicExpression // ignore: cast_nullable_to_non_nullable
as List<String>?,
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<String>,
));
}
}
/// @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<String> inputs,
List<String> outputs,
@JsonKey(includeIfNull: false) List<String>? truthTable,
@JsonKey(includeIfNull: false) List<String>? logicExpression,
@JsonKey(defaultValue: false) bool visualDesigned,
@JsonKey(defaultValue: []) List<String> 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<String>,
outputs: outputs == freezed
? _value._outputs
: outputs // ignore: cast_nullable_to_non_nullable
as List<String>,
truthTable: truthTable == freezed
? _value._truthTable
: truthTable // ignore: cast_nullable_to_non_nullable
as List<String>?,
logicExpression: logicExpression == freezed
? _value._logicExpression
: logicExpression // ignore: cast_nullable_to_non_nullable
as List<String>?,
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<String>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_ComponentEntry implements _ComponentEntry {
const _$_ComponentEntry(
{required this.componentId,
required this.componentName,
@JsonKey(includeIfNull: false) this.componentDescription,
required final List<String> inputs,
required final List<String> outputs,
@JsonKey(includeIfNull: false) final List<String>? truthTable,
@JsonKey(includeIfNull: false) final List<String>? logicExpression,
@JsonKey(defaultValue: false) required this.visualDesigned,
@JsonKey(defaultValue: []) required final List<String> dependencies})
: _inputs = inputs,
_outputs = outputs,
_truthTable = truthTable,
_logicExpression = logicExpression,
_dependencies = dependencies;
factory _$_ComponentEntry.fromJson(Map<String, dynamic> json) =>
_$$_ComponentEntryFromJson(json);
@override
final String componentId;
@override
final String componentName;
@override
@JsonKey(includeIfNull: false)
final String? componentDescription;
final List<String> _inputs;
@override
List<String> get inputs {
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_inputs);
}
final List<String> _outputs;
@override
List<String> get outputs {
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_outputs);
}
final List<String>? _truthTable;
@override
@JsonKey(includeIfNull: false)
List<String>? get truthTable {
final value = _truthTable;
if (value == null) return null;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
final List<String>? _logicExpression;
@override
@JsonKey(includeIfNull: false)
List<String>? 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<String> _dependencies;
@override
@JsonKey(defaultValue: [])
List<String> 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<String, dynamic> 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<String> inputs,
required final List<String> outputs,
@JsonKey(includeIfNull: false)
final List<String>? truthTable,
@JsonKey(includeIfNull: false)
final List<String>? logicExpression,
@JsonKey(defaultValue: false)
required final bool visualDesigned,
@JsonKey(defaultValue: [])
required final List<String> dependencies}) = _$_ComponentEntry;
factory _ComponentEntry.fromJson(Map<String, dynamic> 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<String> get inputs => throw _privateConstructorUsedError;
@override
List<String> get outputs => throw _privateConstructorUsedError;
@override
@JsonKey(includeIfNull: false)
List<String>? get truthTable => throw _privateConstructorUsedError;
@override
@JsonKey(includeIfNull: false)
List<String>? get logicExpression => throw _privateConstructorUsedError;
@override
@JsonKey(defaultValue: false)
bool get visualDesigned => throw _privateConstructorUsedError;
@override
@JsonKey(defaultValue: [])
List<String> get dependencies => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$$_ComponentEntryCopyWith<_$_ComponentEntry> get copyWith =>
throw _privateConstructorUsedError;
}

51
lib/models/component.g.dart

@ -0,0 +1,51 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'component.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_ComponentEntry _$$_ComponentEntryFromJson(Map<String, dynamic> json) =>
_$_ComponentEntry(
componentId: json['componentId'] as String,
componentName: json['componentName'] as String,
componentDescription: json['componentDescription'] as String?,
inputs:
(json['inputs'] as List<dynamic>).map((e) => e as String).toList(),
outputs:
(json['outputs'] as List<dynamic>).map((e) => e as String).toList(),
truthTable: (json['truthTable'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
logicExpression: (json['logicExpression'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
visualDesigned: json['visualDesigned'] as bool? ?? false,
dependencies: (json['dependencies'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
[],
);
Map<String, dynamic> _$$_ComponentEntryToJson(_$_ComponentEntry instance) {
final val = <String, dynamic>{
'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;
}

23
lib/models/project.dart

@ -1,4 +1,5 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:logic_circuits_simulator/models.dart';
part 'project.freezed.dart'; part 'project.freezed.dart';
part 'project.g.dart'; part 'project.g.dart';
@ -11,25 +12,3 @@ class ProjectIndex with _$ProjectIndex {
factory ProjectIndex.fromJson(Map<String, Object?> json) => _$ProjectIndexFromJson(json); factory ProjectIndex.fromJson(Map<String, Object?> json) => _$ProjectIndexFromJson(json);
} }
@freezed
class ComponentEntry with _$ComponentEntry {
const factory ComponentEntry({
required String componentId,
required String componentName,
@JsonKey(includeIfNull: false)
String? componentDescription,
required List<String> inputs,
required List<String> outputs,
@JsonKey(includeIfNull: false)
List<String>? truthTable,
@JsonKey(includeIfNull: false)
List<String>? logicExpression,
@JsonKey(defaultValue: false)
required bool visualDesigned,
@JsonKey(defaultValue: [])
required List<String> dependencies,
}) = _ComponentEntry;
factory ComponentEntry.fromJson(Map<String, Object?> json) => _$ComponentEntryFromJson(json);
}

365
lib/models/project.freezed.dart

@ -151,368 +151,3 @@ abstract class _ProjectIndex implements ProjectIndex {
_$$_ProjectIndexCopyWith<_$_ProjectIndex> get copyWith => _$$_ProjectIndexCopyWith<_$_ProjectIndex> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
ComponentEntry _$ComponentEntryFromJson(Map<String, dynamic> 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<String> get inputs => throw _privateConstructorUsedError;
List<String> get outputs => throw _privateConstructorUsedError;
@JsonKey(includeIfNull: false)
List<String>? get truthTable => throw _privateConstructorUsedError;
@JsonKey(includeIfNull: false)
List<String>? get logicExpression => throw _privateConstructorUsedError;
@JsonKey(defaultValue: false)
bool get visualDesigned => throw _privateConstructorUsedError;
@JsonKey(defaultValue: [])
List<String> get dependencies => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ComponentEntryCopyWith<ComponentEntry> 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<String> inputs,
List<String> outputs,
@JsonKey(includeIfNull: false) List<String>? truthTable,
@JsonKey(includeIfNull: false) List<String>? logicExpression,
@JsonKey(defaultValue: false) bool visualDesigned,
@JsonKey(defaultValue: []) List<String> 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<String>,
outputs: outputs == freezed
? _value.outputs
: outputs // ignore: cast_nullable_to_non_nullable
as List<String>,
truthTable: truthTable == freezed
? _value.truthTable
: truthTable // ignore: cast_nullable_to_non_nullable
as List<String>?,
logicExpression: logicExpression == freezed
? _value.logicExpression
: logicExpression // ignore: cast_nullable_to_non_nullable
as List<String>?,
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<String>,
));
}
}
/// @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<String> inputs,
List<String> outputs,
@JsonKey(includeIfNull: false) List<String>? truthTable,
@JsonKey(includeIfNull: false) List<String>? logicExpression,
@JsonKey(defaultValue: false) bool visualDesigned,
@JsonKey(defaultValue: []) List<String> 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<String>,
outputs: outputs == freezed
? _value._outputs
: outputs // ignore: cast_nullable_to_non_nullable
as List<String>,
truthTable: truthTable == freezed
? _value._truthTable
: truthTable // ignore: cast_nullable_to_non_nullable
as List<String>?,
logicExpression: logicExpression == freezed
? _value._logicExpression
: logicExpression // ignore: cast_nullable_to_non_nullable
as List<String>?,
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<String>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_ComponentEntry implements _ComponentEntry {
const _$_ComponentEntry(
{required this.componentId,
required this.componentName,
@JsonKey(includeIfNull: false) this.componentDescription,
required final List<String> inputs,
required final List<String> outputs,
@JsonKey(includeIfNull: false) final List<String>? truthTable,
@JsonKey(includeIfNull: false) final List<String>? logicExpression,
@JsonKey(defaultValue: false) required this.visualDesigned,
@JsonKey(defaultValue: []) required final List<String> dependencies})
: _inputs = inputs,
_outputs = outputs,
_truthTable = truthTable,
_logicExpression = logicExpression,
_dependencies = dependencies;
factory _$_ComponentEntry.fromJson(Map<String, dynamic> json) =>
_$$_ComponentEntryFromJson(json);
@override
final String componentId;
@override
final String componentName;
@override
@JsonKey(includeIfNull: false)
final String? componentDescription;
final List<String> _inputs;
@override
List<String> get inputs {
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_inputs);
}
final List<String> _outputs;
@override
List<String> get outputs {
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_outputs);
}
final List<String>? _truthTable;
@override
@JsonKey(includeIfNull: false)
List<String>? get truthTable {
final value = _truthTable;
if (value == null) return null;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
final List<String>? _logicExpression;
@override
@JsonKey(includeIfNull: false)
List<String>? 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<String> _dependencies;
@override
@JsonKey(defaultValue: [])
List<String> 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<String, dynamic> 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<String> inputs,
required final List<String> outputs,
@JsonKey(includeIfNull: false)
final List<String>? truthTable,
@JsonKey(includeIfNull: false)
final List<String>? logicExpression,
@JsonKey(defaultValue: false)
required final bool visualDesigned,
@JsonKey(defaultValue: [])
required final List<String> dependencies}) = _$_ComponentEntry;
factory _ComponentEntry.fromJson(Map<String, dynamic> 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<String> get inputs => throw _privateConstructorUsedError;
@override
List<String> get outputs => throw _privateConstructorUsedError;
@override
@JsonKey(includeIfNull: false)
List<String>? get truthTable => throw _privateConstructorUsedError;
@override
@JsonKey(includeIfNull: false)
List<String>? get logicExpression => throw _privateConstructorUsedError;
@override
@JsonKey(defaultValue: false)
bool get visualDesigned => throw _privateConstructorUsedError;
@override
@JsonKey(defaultValue: [])
List<String> get dependencies => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$$_ComponentEntryCopyWith<_$_ComponentEntry> get copyWith =>
throw _privateConstructorUsedError;
}

44
lib/models/project.g.dart

@ -17,47 +17,3 @@ Map<String, dynamic> _$$_ProjectIndexToJson(_$_ProjectIndex instance) =>
<String, dynamic>{ <String, dynamic>{
'components': instance.components, 'components': instance.components,
}; };
_$_ComponentEntry _$$_ComponentEntryFromJson(Map<String, dynamic> json) =>
_$_ComponentEntry(
componentId: json['componentId'] as String,
componentName: json['componentName'] as String,
componentDescription: json['componentDescription'] as String?,
inputs:
(json['inputs'] as List<dynamic>).map((e) => e as String).toList(),
outputs:
(json['outputs'] as List<dynamic>).map((e) => e as String).toList(),
truthTable: (json['truthTable'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
logicExpression: (json['logicExpression'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
visualDesigned: json['visualDesigned'] as bool? ?? false,
dependencies: (json['dependencies'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
[],
);
Map<String, dynamic> _$$_ComponentEntryToJson(_$_ComponentEntry instance) {
final val = <String, dynamic>{
'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;
}

35
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<WiringInstance> instances,
required List<WiringWire> wires,
}) = _Wiring;
factory Wiring.fromJson(Map<String, dynamic> json) => _$WiringFromJson(json);
}
@freezed
class WiringInstance with _$WiringInstance {
const factory WiringInstance({
required String instanceId,
required String componentId,
}) = _WiringInstance;
factory WiringInstance.fromJson(Map<String, dynamic> 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<String, dynamic> json) => _$WiringWireFromJson(json);
}

497
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>(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<String, dynamic> json) {
return _Wiring.fromJson(json);
}
/// @nodoc
mixin _$Wiring {
List<WiringInstance> get instances => throw _privateConstructorUsedError;
List<WiringWire> get wires => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$WiringCopyWith<Wiring> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $WiringCopyWith<$Res> {
factory $WiringCopyWith(Wiring value, $Res Function(Wiring) then) =
_$WiringCopyWithImpl<$Res>;
$Res call({List<WiringInstance> instances, List<WiringWire> 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<WiringInstance>,
wires: wires == freezed
? _value.wires
: wires // ignore: cast_nullable_to_non_nullable
as List<WiringWire>,
));
}
}
/// @nodoc
abstract class _$$_WiringCopyWith<$Res> implements $WiringCopyWith<$Res> {
factory _$$_WiringCopyWith(_$_Wiring value, $Res Function(_$_Wiring) then) =
__$$_WiringCopyWithImpl<$Res>;
@override
$Res call({List<WiringInstance> instances, List<WiringWire> 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<WiringInstance>,
wires: wires == freezed
? _value._wires
: wires // ignore: cast_nullable_to_non_nullable
as List<WiringWire>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_Wiring implements _Wiring {
const _$_Wiring(
{required final List<WiringInstance> instances,
required final List<WiringWire> wires})
: _instances = instances,
_wires = wires;
factory _$_Wiring.fromJson(Map<String, dynamic> json) =>
_$$_WiringFromJson(json);
final List<WiringInstance> _instances;
@override
List<WiringInstance> get instances {
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_instances);
}
final List<WiringWire> _wires;
@override
List<WiringWire> 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<String, dynamic> toJson() {
return _$$_WiringToJson(this);
}
}
abstract class _Wiring implements Wiring {
const factory _Wiring(
{required final List<WiringInstance> instances,
required final List<WiringWire> wires}) = _$_Wiring;
factory _Wiring.fromJson(Map<String, dynamic> json) = _$_Wiring.fromJson;
@override
List<WiringInstance> get instances => throw _privateConstructorUsedError;
@override
List<WiringWire> get wires => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$$_WiringCopyWith<_$_Wiring> get copyWith =>
throw _privateConstructorUsedError;
}
WiringInstance _$WiringInstanceFromJson(Map<String, dynamic> json) {
return _WiringInstance.fromJson(json);
}
/// @nodoc
mixin _$WiringInstance {
String get instanceId => throw _privateConstructorUsedError;
String get componentId => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$WiringInstanceCopyWith<WiringInstance> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> json) {
return _WiringWire.fromJson(json);
}
/// @nodoc
mixin _$WiringWire {
String get wireId => throw _privateConstructorUsedError;
String get output => throw _privateConstructorUsedError;
String get input => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$WiringWireCopyWith<WiringWire> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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;
}

47
lib/models/wiring.g.dart

@ -0,0 +1,47 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'wiring.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_Wiring _$$_WiringFromJson(Map<String, dynamic> json) => _$_Wiring(
instances: (json['instances'] as List<dynamic>)
.map((e) => WiringInstance.fromJson(e as Map<String, dynamic>))
.toList(),
wires: (json['wires'] as List<dynamic>)
.map((e) => WiringWire.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$$_WiringToJson(_$_Wiring instance) => <String, dynamic>{
'instances': instance.instances,
'wires': instance.wires,
};
_$_WiringInstance _$$_WiringInstanceFromJson(Map<String, dynamic> json) =>
_$_WiringInstance(
instanceId: json['instanceId'] as String,
componentId: json['componentId'] as String,
);
Map<String, dynamic> _$$_WiringInstanceToJson(_$_WiringInstance instance) =>
<String, dynamic>{
'instanceId': instance.instanceId,
'componentId': instance.componentId,
};
_$_WiringWire _$$_WiringWireFromJson(Map<String, dynamic> json) =>
_$_WiringWire(
wireId: json['wireId'] as String,
output: json['output'] as String,
input: json['input'] as String,
);
Map<String, dynamic> _$$_WiringWireToJson(_$_WiringWire instance) =>
<String, dynamic>{
'wireId': instance.wireId,
'output': instance.output,
'input': instance.input,
};

69
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<ComponentState>();
final canvasController = useStackCanvasController();
final widgets = useState(<CanvasObject<Widget>>[]);
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,
),
),
],
);
}
}
),
);
}
}

66
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/logic_expression_field.dart';
import 'package:logic_circuits_simulator/components/truth_table.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/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/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/iterable_extension.dart';
import 'package:logic_circuits_simulator/utils/logic_expressions.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/logic_operators.dart';
import 'package:logic_circuits_simulator/utils/provider_hook.dart'; import 'package:logic_circuits_simulator/utils/provider_hook.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
class EditComponentPage extends HookWidget { class EditComponentPage extends HookWidget {
final bool newComponent; final bool newComponent;
final ComponentEntry component; 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'; static const String routeName = '/project/component/edit';
@ -63,7 +73,7 @@ class EditComponentPage extends HookWidget {
return false; return false;
} }
if (componentNameEditingController.text != ce().componentName) { if (componentNameEditingController.text.trim() != ce().componentName.trim()) {
return true; return true;
} }
if (!le.equals(inputs.value, ce().inputs)) { if (!le.equals(inputs.value, ce().inputs)) {
@ -456,7 +466,7 @@ class EditComponentPage extends HookWidget {
padding: EdgeInsets.all(8.0), padding: EdgeInsets.all(8.0),
child: OutlinedButton( child: OutlinedButton(
onPressed: null, onPressed: null,
child: const Text('Script'), child: Text('Script'),
), ),
), ),
], ],
@ -563,9 +573,51 @@ class EditComponentPage extends HookWidget {
) else Padding( ) else Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: ElevatedButton( child: ElevatedButton(
// TODO: Implement visual designer onPressed: () async {
onPressed: null, final nav = Navigator.of(context);
child: Text('Open Designer'), final projectsState = Provider.of<ProjectsState>(context, listen: false);
try {
await Provider.of<ComponentState>(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'),
), ),
), ),
], ],

2
lib/pages/project.dart

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; 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/edit_component.dart';
import 'package:logic_circuits_simulator/pages_arguments/edit_component.dart'; import 'package:logic_circuits_simulator/pages_arguments/edit_component.dart';
import 'package:logic_circuits_simulator/state/project.dart'; import 'package:logic_circuits_simulator/state/project.dart';

4
lib/pages/projects.dart

@ -5,7 +5,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:logic_circuits_simulator/dialogs/new_project.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/pages/project.dart';
import 'package:logic_circuits_simulator/state/project.dart'; import 'package:logic_circuits_simulator/state/project.dart';
import 'package:logic_circuits_simulator/state/projects.dart'; import 'package:logic_circuits_simulator/state/projects.dart';
@ -58,7 +58,7 @@ class ProjectsPage extends StatelessWidget {
} }
void onProjectSelect(BuildContext context, ProjectEntry p) { void onProjectSelect(BuildContext context, ProjectEntry p) {
Provider.of<ProjectState>(context, listen: false).currentProject = p; Provider.of<ProjectState>(context, listen: false).setCurrentProject(p);
Provider.of<ProjectState>(context, listen: false).registerSaveHandler((p) async { Provider.of<ProjectState>(context, listen: false).registerSaveHandler((p) async {
await Provider.of<ProjectsState>(context, listen: false).updateProject(p); await Provider.of<ProjectsState>(context, listen: false).updateProject(p);
}); });

11
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;
}

150
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>(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<DesignComponentPageArguments>
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;
}

2
lib/pages_arguments/edit_component.dart

@ -1,5 +1,5 @@
import 'package:freezed_annotation/freezed_annotation.dart'; 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'; part 'edit_component.freezed.dart';

135
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<String, Tuple2<ProjectEntry, ComponentEntry>> _dependenciesMap = {};
ProjectEntry? get currentProject => _currentProject;
ComponentEntry? get currentComponent => _currentComponent;
Wiring get wiring => _wiring;
Future<Directory> _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<File> _getWiringFile() async {
final result = File(path.join((await _getComponentDir()).path, 'wiring.json'));
return result;
}
Future<void> _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<void> setCurrentComponent({
required ProjectEntry project,
required ComponentEntry component,
required Future<Tuple2<ProjectEntry, ComponentEntry>?> Function(String projectId, String componentId) onDependencyNeeded,
}) async {
_dependenciesMap.clear();
_simulatedComponent = null;
_currentProject = project;
_currentComponent = component;
// Load dependencies
final unsatisfiedDependencies = <String>[];
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<Map<String, bool>> simulate(Map<String, bool> inputs) async {
Future<SimulatedComponent> 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<String> dependencies;
const DependenciesNotSatisfiedException({required this.dependencies});
@override
String toString() {
return 'DependenciesNotSatisfiedException(${dependencies.join(", ")})';
}
}

7
lib/state/project.dart

@ -2,8 +2,7 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:logic_circuits_simulator/models/project.dart'; import 'package:logic_circuits_simulator/models.dart';
import 'package:logic_circuits_simulator/models/projects.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
@ -55,9 +54,9 @@ class ProjectState extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
set currentProject(ProjectEntry? p) { Future<void> setCurrentProject(ProjectEntry? p) {
_currentProject = p; _currentProject = p;
_loadProjectFiles().then((_) => notifyListeners()); return _loadProjectFiles().then((_) => notifyListeners());
} }
void noProject() { void noProject() {

2
lib/state/projects.dart

@ -3,7 +3,7 @@ import 'dart:io';
import 'package:archive/archive_io.dart'; import 'package:archive/archive_io.dart';
import 'package:flutter/foundation.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_provider/path_provider.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';

127
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<SimulatedComponent> Function(String depId) onRequiredDependency;
final _instances = <String, SimulatedComponent>{};
SimulatedComponent({
required this.project,
required this.component,
required this.onRequiredDependency,
this.state
});
Future<SimulatedComponent> _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<Map<String, bool>> simulate(Map<String, bool> 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 = <String>[
...component.outputs.map((output) => 'self/$output'),
];
final knownSources = {
for (final entry in inputs.entries)
'self/${entry.key}': entry.value
};
final knownSinks = <String, bool>{};
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']!
};
}
}
}

62
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<StackCanvasController> {
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<StackCanvasController, Hook<StackCanvasController>> createState() {
return _StackCanvasControllerHookCreatorState();
}
}
class _StackCanvasControllerHookCreatorState extends HookState<StackCanvasController, _StackCanvasControllerHookCreator> {
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();
}
}

21
pubspec.lock

@ -485,6 +485,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
share_plus: share_plus:
dependency: "direct main" dependency: "direct main"
description: description:
@ -623,6 +630,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.2" 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: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -672,6 +686,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.0" version: "1.0.0"
tuple:
dependency: "direct main"
description:
name: tuple
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

2
pubspec.yaml

@ -38,6 +38,8 @@ dependencies:
archive: ^3.3.0 archive: ^3.3.0
file_picker: ^4.6.1 file_picker: ^4.6.1
share_plus: ^4.0.8 share_plus: ^4.0.8
stack_canvas: ^0.2.0+2
tuple: ^2.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

Loading…
Cancel
Save