From 6ba32a7dfacb4feffedafa3c20ee0c57e04298aa Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 27 Aug 2024 15:38:21 +0200 Subject: [PATCH] Shared WS --- lib/core/models/shared_workspace_local.dart | 77 ++++++++++ lib/core/sections/end_drawer.dart | 69 +++++---- lib/core/sections/header/menu.dart | 3 +- .../specialized_services/shared_service.dart | 18 ++- lib/main.dart | 2 + lib/models/workflow.dart | 18 ++- lib/models/workspace.dart | 4 + lib/pages/shared.dart | 4 +- lib/pages/workflow.dart | 14 +- ..._shared.dart => new_shared_workspace.dart} | 0 .../{new_box.dart => new_workflow.dart} | 0 lib/widgets/forms/proxy_forms.dart | 81 +++++++++- lib/widgets/forms/scheduler_forms.dart | 66 +++++--- .../menu_clipper/shared_workspace_menu.dart | 142 ++++++++++++++++++ lib/widgets/menu_clipper/workspace_menu.dart | 14 +- .../flutter_flow_chart/lib/src/dashboard.dart | 2 + .../lib/src/flow_chart.dart | 9 +- .../lib/src/flow_chart_menu.dart | 11 +- .../lib/src/flow_chart_selected_menu.dart | 32 ++-- 19 files changed, 479 insertions(+), 87 deletions(-) create mode 100644 lib/core/models/shared_workspace_local.dart rename lib/widgets/dialog/{new_box_shared.dart => new_shared_workspace.dart} (100%) rename lib/widgets/dialog/{new_box.dart => new_workflow.dart} (100%) create mode 100644 lib/widgets/menu_clipper/shared_workspace_menu.dart diff --git a/lib/core/models/shared_workspace_local.dart b/lib/core/models/shared_workspace_local.dart new file mode 100644 index 0000000..120bc95 --- /dev/null +++ b/lib/core/models/shared_workspace_local.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:oc_front/core/sections/end_drawer.dart'; +import 'package:oc_front/core/services/specialized_services/shared_service.dart'; +import 'package:oc_front/models/shared.dart'; +import 'package:oc_front/models/workspace.dart'; +import 'package:oc_front/pages/catalog.dart'; +import 'package:oc_front/pages/catalog_item.dart'; +import 'package:oc_front/pages/workflow.dart'; + +class WorkSpaceItem { + String? id; + String? name; + WorkSpaceItem({this.id, this.name}); +} + +class SharedWorkspaceLocal { + static Map workspaces = {}; + static final SharedService _service = SharedService(); + + static void init(BuildContext context, bool changeCurrent) { + _service.all(context).then((value) { + if (value.data != null && value.data!.values.isNotEmpty ) { + var vals = value.data!.values; + for (var element in vals) { + var ws = SharedWorkspace().deserialize(element); + print(element); + if (ws.id == null) { continue; } + workspaces[ws.id!] = ws; + } + } + }); + } + + static SharedWorkspace? getSharedWorkspace(String id) { + return workspaces[id]; + } + + static Future deleteSharedWorkspace(String id) async { + if (workspaces.containsKey(id) && workspaces.length == 1) { return; } + workspaces.remove(id); + await _service.delete(null, id, {}); + } + + static Future createSharedWorkspace(String name, BuildContext? context) async { + Workspace n = Workspace(name: name); + await _service.post(context, n.serialize(), {}).then((value) { + if (value.data != null) { + workspaces[value.data!.id!] = value.data!; + endDrawerKey.currentState?.setState(() {}); + CatalogFactory.key.currentState?.setState(() {}); + CatalogItemFactory.key.currentState?.setState(() {}); + WorkflowFactory.key.currentState?.setState(() {}); + } + }); + } + + static void changeWorkspaceByName(String name) { + var id = workspaces.entries.firstWhere((element) => element.value.name == "${name}_workspace").key; + changeWorkspace(id); + } + + static void changeWorkspace(String id) { + _service.put(null, id, { "active" : true }, {}); + endDrawerKey.currentState?.setState(() {}); + CatalogFactory.key.currentState?.setState(() {}); + CatalogItemFactory.key.currentState?.setState(() {}); + WorkflowFactory.key.currentState?.setState(() {}); + } + + static List getSharedWorkspacesIDS() { + List res = []; + for (var element in workspaces.entries) { + res.add(WorkSpaceItem(id: element.key, name: element.value.name)); + } + return res; + } +} \ No newline at end of file diff --git a/lib/core/sections/end_drawer.dart b/lib/core/sections/end_drawer.dart index c35df85..1b3ea89 100644 --- a/lib/core/sections/end_drawer.dart +++ b/lib/core/sections/end_drawer.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/core/models/shared_workspace_local.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/pages/catalog.dart'; import 'package:oc_front/core/models/workspace_local.dart'; import 'package:oc_front/widgets/items/item_row.dart'; +import 'package:oc_front/widgets/menu_clipper/shared_workspace_menu.dart'; import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart'; GlobalKey endDrawerKey = GlobalKey(); @@ -15,36 +17,47 @@ class EndDrawerWidgetState extends State { @override Widget build(BuildContext context) { List itemRows = WorkspaceLocal.items.map( (e) => ItemRowWidget(contextWidth: 400, item: e, keys: [endDrawerKey, CatalogFactory.key],)).toList(); - return Container( - color: Colors.white, - width: 400, - height: MediaQuery.of(context).size.height, - child: SingleChildScrollView( + print(WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared); + print(SharedWorkspaceLocal.workspaces); + return Stack( children: [ + Container( + color: Colors.white, + width: 400, + height: MediaQuery.of(context).size.height, child: Column( children: [ - Container( - width: 400, - height: 50, - decoration: const BoxDecoration(color: Color.fromRGBO(38, 166, 154, 1)), - child: const Center( - child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding(padding: EdgeInsets.only(right: 20), child: Icon(Icons.shopping_cart_outlined, size: 18, color: Colors.white)), - Text("Workspace", style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.w600)) - ]) - + Container( + width: 400, + height: 50, + decoration: const BoxDecoration(color: Color.fromRGBO(38, 166, 154, 1)), + child: const Center( + child: Row( mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding(padding: EdgeInsets.only(right: 20), child: Icon(Icons.shopping_cart_outlined, size: 18, color: Colors.white)), + Text("Workspace", style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.w600)) + ]) + + ), ), - ), - MenuWorkspaceWidget(simpliest: true, width: 400), - itemRows.isEmpty ? Container( height: MediaQuery.of(context).size.height - 100, - color: Colors.grey.shade300, - child: const Center(child: Text("WORKSPACE IS EMPTY", - style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white)))) - : Container( child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Column( children: itemRows) - )), - ]) - ) + MenuWorkspaceWidget(simpliest: true, width: 400), + Column( children: [ + itemRows.isEmpty ? Container( height: MediaQuery.of(context).size.height - 100, + color: Colors.grey.shade300, + child: const Center(child: Text("WORKSPACE IS EMPTY", + style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white)))) + : Container( height: MediaQuery.of(context).size.height - 100, child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( children: [ ...itemRows, Container(height: 50)]) + )), + ]) + ]) + ), + Positioned( bottom: 0, left: 0, + child: SharedMenuWorkspaceWidget( width: 400, + excluded: const [], + before: WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared, + selected: WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared, + reverse: itemRows.isEmpty, contextID: WorkspaceLocal.current ?? "",) ) + ] ); } } \ No newline at end of file diff --git a/lib/core/sections/header/menu.dart b/lib/core/sections/header/menu.dart index fd4b271..67f9f91 100644 --- a/lib/core/sections/header/menu.dart +++ b/lib/core/sections/header/menu.dart @@ -34,7 +34,8 @@ class HeaderMenuWidgetState extends State { Tooltip( message: "login", child: Padding(padding: const EdgeInsets.only(left: 10), child: IconButton( icon: const Icon(Icons.login_outlined), - onPressed: () { showDialog(context: context, builder: (context) => LoginWidget()); }, + onPressed: () { showDialog(context: context, builder: (context) => + LoginWidget()); }, ) )), Tooltip( message: "navigation", child: Padding(padding: const EdgeInsets.only(left: 10), diff --git a/lib/core/services/specialized_services/shared_service.dart b/lib/core/services/specialized_services/shared_service.dart index f2f9686..bd8b10c 100644 --- a/lib/core/services/specialized_services/shared_service.dart +++ b/lib/core/services/specialized_services/shared_service.dart @@ -11,14 +11,26 @@ class SharedService extends AbstractService { @override String subPath = "/oc/shared/workspace/"; Future> addWorkspace(BuildContext? context, String id, String id2) { - return service.get("$id/workspace/$id2", true, context); + return service.post("$subPath$id/workspace/$id2", {}, context); } Future> addWorkflow(BuildContext? context, String id, String id2) { - return service.get("$id/workflow/$id2", true, context); + return service.post("$subPath$id/workflow/$id2", {}, context); } Future> addPeer(BuildContext? context, String id, String id2) { - return service.get("$id/peer/$id2", true, context); + return service.post("$subPath$id/peer/$id2", {}, context); + } + + Future> removeWorkspace(BuildContext? context, String id, String id2) { + return service.delete("$subPath$id/workspace/$id2", context); + } + + Future> removeWorkflow(BuildContext? context, String id, String id2) { + return service.delete("$subPath$id/workflow/$id2", context); + } + + Future> removePeer(BuildContext? context, String id, String id2) { + return service.delete("$subPath$id/peer/$id2", context); } } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 9ed3001..45f697d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:go_router/go_router.dart'; +import 'package:oc_front/core/models/shared_workspace_local.dart'; import 'package:oc_front/core/models/workspace_local.dart'; import 'package:oc_front/core/services/router.dart'; import 'package:oc_front/core/sections/end_drawer.dart'; @@ -51,6 +52,7 @@ class _MainPageState extends State { // fast, so that you can just rebuild anything that needs updating rather // than having to individually change instances of widgets. WorkspaceLocal.init(context, false); + SharedWorkspaceLocal.init(context, false); scaffoldKey = GlobalKey(); return Scaffold( key: scaffoldKey, diff --git a/lib/models/workflow.dart b/lib/models/workflow.dart index 7f4681d..f78d9a9 100644 --- a/lib/models/workflow.dart +++ b/lib/models/workflow.dart @@ -109,6 +109,7 @@ class Workflow extends SerializerDeserializer { Graph? graph; Scheduler? schedule; bool scheduleActive = false; + List shared; Workflow({ this.id, @@ -121,6 +122,7 @@ class Workflow extends SerializerDeserializer { this.graph, this.schedule, this.scheduleActive = false, + this.shared = const [], }); String getID() { @@ -139,6 +141,7 @@ class Workflow extends SerializerDeserializer { data: json.containsKey("datas") ? json["datas"] : [], scheduleActive: json.containsKey("schedule_active") ? json["schedule_active"] : false, storage: json.containsKey("storages") ? json["storages"] : [], + shared: json.containsKey("shared") ? json["shared"] : [], graph: json.containsKey("graph") ? Graph().deserialize(json["graph"]) : null, schedule: json.containsKey("schedule") ? Scheduler().deserialize(json["schedule"]) : null, ); @@ -181,6 +184,7 @@ class Workflow extends SerializerDeserializer { "graph": graph?.toDashboard(), "schedule_active": scheduleActive, "schedule": schedule?.toDashboard(), + "shared": shared, }; } } @@ -206,10 +210,12 @@ class Scheduler extends SerializerDeserializer { id = j["id"]; name = j["name"]; cron = j["cron"]; - start = DateTime.parse(j["start"]); - if (j.containsKey("end") && j["end"] != null) { - end = DateTime.parse(j["end"]); - } + try { + start = DateTime.parse(j["start"]); + if (j.containsKey("end") && j["end"] != null) { + end = DateTime.parse(j["end"]); + } + } catch (e) {} mode = int.parse(j["mode"].toString()); } Map toDashboard() { @@ -231,8 +237,8 @@ class Scheduler extends SerializerDeserializer { name: json.containsKey("name") ? json["name"] : "", cron: json.containsKey("cron") ? json["cron"] : "", mode: json.containsKey("mode") ? json["mode"] : "", - start: json.containsKey("start") ? DateTime.parse(json["start"]) : null, - end: json.containsKey("end") ? DateTime.parse(json["end"]) : null, + start: json.containsKey("start") && json["start"] != null ? DateTime.parse(json["start"]) : null, + end: json.containsKey("end") && json["end"] != null ? DateTime.parse(json["end"]) : null, ); } @override Map serialize() => { diff --git a/lib/models/workspace.dart b/lib/models/workspace.dart index 44b5189..6727a35 100644 --- a/lib/models/workspace.dart +++ b/lib/models/workspace.dart @@ -10,6 +10,7 @@ class Workspace extends SerializerDeserializer { List storages; List processings; List workflows; + String? shared; Workspace({ this.id, @@ -20,13 +21,16 @@ class Workspace extends SerializerDeserializer { this.datacenters = const [], this.storages = const [], this.processings = const [], + this.shared, }); @override deserialize(dynamic json) { try { json = json as Map; } catch (e) { return Workspace(); } + print(json); return Workspace( id: json.containsKey("id") ? json["id"] : null, + shared: json["shared"], name: json.containsKey("name") ? json["name"] : null, active: json.containsKey("active") ? json["active"] : false, processings: json.containsKey("processing_resources") ? fromListJson(json["processing_resources"], ProcessingItem()) : [], diff --git a/lib/pages/shared.dart b/lib/pages/shared.dart index a40bf45..bbe8220 100644 --- a/lib/pages/shared.dart +++ b/lib/pages/shared.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:oc_front/core/sections/header/header.dart'; import 'package:oc_front/pages/abstract_page.dart'; -import 'package:oc_front/widgets/dialog/new_box_shared.dart'; +import 'package:oc_front/widgets/dialog/new_shared_workspace.dart'; class SharedFactory implements AbstractFactory { static GlobalKey key = GlobalKey(); @@ -21,7 +21,7 @@ class SharedPageWidget extends StatefulWidget { class SharedPageWidgetState extends State { @override Widget build(BuildContext context) { - Future.delayed(Duration(milliseconds: 100), () { + Future.delayed( const Duration(milliseconds: 100), () { showDialog(context: context, builder: (BuildContext ctx) => AlertDialog( titlePadding: EdgeInsets.zero, insetPadding: EdgeInsets.zero, diff --git a/lib/pages/workflow.dart b/lib/pages/workflow.dart index 29acee7..010573f 100644 --- a/lib/pages/workflow.dart +++ b/lib/pages/workflow.dart @@ -8,10 +8,11 @@ import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/pages/abstract_page.dart'; -import 'package:oc_front/widgets/dialog/new_box.dart'; +import 'package:oc_front/widgets/dialog/new_workflow.dart'; import 'package:oc_front/widgets/forms/proxy_forms.dart'; import 'package:oc_front/widgets/forms/scheduler_forms.dart'; import 'package:oc_front/widgets/items/item_row.dart'; +import 'package:oc_front/widgets/menu_clipper/shared_workspace_menu.dart'; import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart'; Dashboard dash = Dashboard( @@ -57,7 +58,7 @@ final WorflowService _service = WorflowService(); } List getForms(FlowData? obj) { return obj == null ? [] : [ - ProxyFormsWidget(item: obj as AbstractItem), + ProxyFormsWidget(item: obj as AbstractItem, dash: dash), ]; } @@ -133,6 +134,12 @@ final WorflowService _service = WorflowService(); }); } + Widget onDashboardMenu(Dashboard dash) { + return SharedMenuWorkspaceWidget(width: MediaQuery.of(context).size.width / 2.5, contextID: dash.id ?? "", + excluded: dash.info["shared"] ?? [], + topMargin: 0, inner: true, type: SharedMenuWorkspaceType.workflow); + } + Widget onDashboardAlertOpened(BuildContext context, Dashboard dash) { return NewBoxWidget(service: _service, dash: dash, getItems: getItems); @@ -149,11 +156,12 @@ final WorflowService _service = WorflowService(); onDashboardAlertOpened: onDashboardAlertOpened, dashboard: dash, itemWidget: itemBuild, + menuWidget: onDashboardMenu, categories: const ["processing", "data", "datacenter", "storage", "workflows"], draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, false), itemWidgetTooltip: itemTooltipBuild, innerMenuWidth: quart > 80 ? quart : 80, - menuExtension: menuExtension, + menuExtension: MediaQuery.of(context).size.width > 600 ? menuExtension : null, width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height - HeaderConstants.height, onNewConnection: (p1, p2) { }, diff --git a/lib/widgets/dialog/new_box_shared.dart b/lib/widgets/dialog/new_shared_workspace.dart similarity index 100% rename from lib/widgets/dialog/new_box_shared.dart rename to lib/widgets/dialog/new_shared_workspace.dart diff --git a/lib/widgets/dialog/new_box.dart b/lib/widgets/dialog/new_workflow.dart similarity index 100% rename from lib/widgets/dialog/new_box.dart rename to lib/widgets/dialog/new_workflow.dart diff --git a/lib/widgets/forms/proxy_forms.dart b/lib/widgets/forms/proxy_forms.dart index ad3d1a2..61c7059 100644 --- a/lib/widgets/forms/proxy_forms.dart +++ b/lib/widgets/forms/proxy_forms.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:oc_front/models/search.dart'; import 'package:oc_front/pages/workflow.dart'; @@ -6,7 +8,8 @@ Map> proxyWfItem = {}; class ProxyFormsWidget extends StatefulWidget { AbstractItem item; - ProxyFormsWidget ({ super.key, required this.item }); + Dashboard dash; + ProxyFormsWidget ({ super.key, required this.item, required this.dash }); @override ProxyFormsWidgetState createState() => ProxyFormsWidgetState(); } class ProxyFormsWidgetState extends State { @@ -18,7 +21,7 @@ class ProxyFormsWidgetState extends State { children.add( Tooltip( message: child, child: Container( margin: EdgeInsets.only(top: children.isEmpty ? 0 : 15), - width: 160, height: 30, + width: 200, height: 30, child: TextFormField( textAlign: TextAlign.start, initialValue: widget.item.model?.model?[child]?.value, onChanged: (value) { @@ -48,8 +51,80 @@ class ProxyFormsWidgetState extends State { ))) ); } + if (widget.dash.scheduler["mode"] != null && widget.dash.scheduler["mode"] == 1) { + children.add( + Tooltip( message: "hostname", + child: Container( margin: EdgeInsets.only(top: children.isEmpty ? 0 : 15), + width: 200, height: 30, + child: TextFormField( textAlign: TextAlign.start, + onChanged: (value) { + widget.item.model ?? Model(); + Future.delayed(const Duration(seconds: 2), () { + if (widget.item.model!.model?["hostname"]?.value == value) { + dash.save!(dash.id); + } + }); + widget.item.model?.model?["hostname"]?.value = value; + }, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + hintText: "enter hostname...", + fillColor: Colors.white, + filled: true, + labelText: "hostname", + alignLabelWithHint: false, + errorStyle: TextStyle(fontSize: 0), + hintStyle: TextStyle(fontSize: 10), + labelStyle: TextStyle(fontSize: 10), + floatingLabelBehavior: FloatingLabelBehavior.always, + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + ))) + ); + children.add( + Tooltip( message: "port", + child: Container( margin: EdgeInsets.only(top: children.isEmpty ? 0 : 15), + width: 200, height: 50, + child: TextFormField( textAlign: TextAlign.start, + onChanged: (value) { + widget.item.model ?? Model(); + Future.delayed(const Duration(seconds: 2), () { + if (widget.item.model!.model?["port"]?.value == value) { + dash.save!(dash.id); + } + }); + try { + widget.item.model?.model?["port"]?.value = int.parse(value); + } catch (e) { /**/ } + }, + keyboardType: TextInputType.number, + + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], // Only numbers can be entered + maxLength: 4, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + hintText: "enter port...", + fillColor: Colors.white, + filled: true, + labelText: "port", + alignLabelWithHint: false, + errorStyle: TextStyle(fontSize: 0), + hintStyle: TextStyle(fontSize: 10), + labelStyle: TextStyle(fontSize: 10), + floatingLabelBehavior: FloatingLabelBehavior.always, + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + ))) + ); + } return Column( children: [ - Container( padding: const EdgeInsets.all(10), width: 200, height: 60, margin: const EdgeInsets.only(bottom: 15), + Container( padding: const EdgeInsets.all(10), width: 250, height: 60, margin: const EdgeInsets.only(bottom: 15), decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("ELEMENT INFO", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), diff --git a/lib/widgets/forms/scheduler_forms.dart b/lib/widgets/forms/scheduler_forms.dart index 916d05e..aee8628 100644 --- a/lib/widgets/forms/scheduler_forms.dart +++ b/lib/widgets/forms/scheduler_forms.dart @@ -1,10 +1,12 @@ import 'package:alert_banner/exports.dart'; import 'package:cron/cron.dart'; +import 'package:flutter/widgets.dart'; import 'package:intl/intl.dart' as intl; import 'package:flutter/material.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; import 'package:datetime_picker_formfield/datetime_picker_formfield.dart'; +import 'package:oc_front/core/models/shared_workspace_local.dart'; import 'package:oc_front/core/services/specialized_services/check_service.dart'; import 'package:oc_front/pages/workflow.dart'; import 'package:oc_front/widgets/dialog/alert.dart'; @@ -44,13 +46,15 @@ class SchedulerFormsWidgetState extends State { List> formKeys = [GlobalKey(), GlobalKey(), GlobalKey(), GlobalKey()]; return Column( children: [ - Container( padding: const EdgeInsets.all(10), width: 200, height: 60, + Container( padding: const EdgeInsets.all(10), width: 250, height: 60, decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("WORKFLOW INFO", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), Text("", style: TextStyle(fontSize: 12), textAlign: TextAlign.center), ])), - Container(height: 20), + Container(height: 20, + width: 250, + ), AdvancedSwitch( width: 140, initialValue: widget.item.scheduler["mode"] == 1, @@ -131,11 +135,10 @@ class SchedulerFormsWidgetState extends State { lastDate: DateTime(2100) ); if (date != null) { - var n = TimeOfDay.now(); - TimeOfDay? time = n; + TimeOfDay? time; var count = 0; - while(((time?.hour ?? 0) + ((time?.minute ?? 0) / 100)) <= (n.hour + ((n.minute + 1) / 100)) ) { - if (count > 0 && time != null) { + while(date!.microsecondsSinceEpoch <= (DateTime.now().microsecondsSinceEpoch) || time == null) { + if (count > 0) { showAlertBanner( context, () {}, const AlertAlertBannerChild( text: "must be at least 1 minute from now to let system check info"),// <-- Put any widget here you want! @@ -161,9 +164,9 @@ class SchedulerFormsWidgetState extends State { ); if (time == null) { return DateTime.now().add( const Duration(minutes: 1)); } count++; + date = DateTime(date.year, date.month, date.day, time.hour, time.minute); + widget.item.scheduler["start"] = date.toUtc().toIso8601String(); } - date = date.add(Duration(hours: time?.hour ?? 0, minutes: time?.minute ?? 0)); - widget.item.scheduler["start"] = date.toUtc().toIso8601String(); widget.item.save!(widget.item.id); } return date; @@ -228,13 +231,15 @@ class SchedulerFormsWidgetState extends State { ); if (date != null) { // ignore: use_build_context_synchronously - var n = TimeOfDay.now(); - TimeOfDay? time = TimeOfDay(hour: date.hour, minute: date.minute); + date = DateTime(date.year, date.month, date.day, date.hour, date.minute); + TimeOfDay? time; var count = 0; - while(((time?.hour ?? 0) + (time?.minute ?? 0 / 100)) <= (n.hour + ((n.minute + 1) / 100)) ) { - if (count > 0 && time != null) { + while(date!.microsecondsSinceEpoch <= (DateTime.now().microsecondsSinceEpoch) + || time == null + || (date.microsecondsSinceEpoch) <= (DateTime.parse(widget.item.scheduler["start"] ?? DateTime.now().toIso8601String()).microsecondsSinceEpoch)) { + if (count > 0) { showAlertBanner( context, () {}, - const AlertAlertBannerChild(text: "must be at least 1 minute from now to let system check info"),// <-- Put any widget here you want! + const AlertAlertBannerChild(text: "must be at least 1 minute from now to let system check info && upper starting date"),// <-- Put any widget here you want! alertBannerLocation: AlertBannerLocation.bottom,); } time = await showTimePicker(context: context, @@ -257,9 +262,9 @@ class SchedulerFormsWidgetState extends State { ); if (time == null) { return null; } count++; + date = DateTime(date.year, date.month, date.day, time.hour, time.minute); + widget.item.scheduler["end"] = date.toUtc().toIso8601String(); } - date = date.add(Duration(hours: time?.hour ?? 0, minutes: time?.minute ?? 0)); - widget.item.scheduler["end"] = date.toUtc().toIso8601String(); widget.item.save!(widget.item.id); } return date; @@ -326,7 +331,11 @@ class SchedulerFormsWidgetState extends State { contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), ), ))), - const Divider(color: Colors.grey), + Container( + width: 250, + height: 20, + decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.black, width: 1))), + ), Tooltip( message: "check booking", child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () { @@ -361,7 +370,7 @@ class SchedulerFormsWidgetState extends State { }, child: Container( margin: const EdgeInsets.all(10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: widget.booking == null && !dash.scheduleActive ? Colors.grey : (widget.booking == true || dash.scheduleActive ? Colors.green : Colors.red), width: 1)), - width: 140, height: 30, + width: 200, height: 30, child: Icon( Icons.verified_outlined, color: widget.booking == null && !dash.scheduleActive ? Colors.grey : (widget.booking == true || dash.scheduleActive ? Colors.green : Colors.red)), @@ -389,12 +398,31 @@ class SchedulerFormsWidgetState extends State { setState(() { }); }, child: Container( margin: const EdgeInsets.all(10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), - border: Border.all(color: dash.scheduleActive ? Colors.green : Colors.black, width: 1)), - width: 140, height: 30, + border: Border.all(color: dash.scheduleActive ? Colors.green : Colors.black)), + width: 200, height: 30, child: Icon( dash.scheduleActive ? Icons.cancel_schedule_send : Icons.schedule_send, color: dash.scheduleActive ? Colors.green : Colors.black), )) ), + widget.item.info["shared"] != null && (widget.item.info["shared"] as List).isNotEmpty ? Column( children: [ + Container( + height: 20, + width: 250, + decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.black))), + ), + Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 20), + child: Text( textAlign: TextAlign.center, + style: const TextStyle(fontSize: 14, color: Colors.black, fontWeight: FontWeight.bold), + "Workflow is shared in ${(widget.item.info["shared"] as List).length} workspace(s)")), + ...(widget.item.info["shared"] as List).where( (e) => SharedWorkspaceLocal.getSharedWorkspace(e) != null + ).map((e) { + return Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), + child: Row( children: [ + const Padding(padding: EdgeInsets.only(right: 10), child: Icon(Icons.work, color: Colors.grey, size: 15)), + Text(style: const TextStyle(fontSize: 12, color: Colors.grey), + "Workspace: ${SharedWorkspaceLocal.getSharedWorkspace(e)!.name}") ])); + },) + ]) : Container() ]); } } diff --git a/lib/widgets/menu_clipper/shared_workspace_menu.dart b/lib/widgets/menu_clipper/shared_workspace_menu.dart new file mode 100644 index 0000000..5151f8b --- /dev/null +++ b/lib/widgets/menu_clipper/shared_workspace_menu.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:oc_front/core/models/shared_workspace_local.dart'; +import 'package:oc_front/core/services/specialized_services/shared_service.dart'; +import 'package:oc_front/models/shared.dart'; +import 'package:oc_front/pages/catalog.dart'; +import 'package:oc_front/pages/catalog_item.dart'; +import 'package:oc_front/pages/workflow.dart'; + +enum SharedMenuWorkspaceType { workspace, workflow, peer } + +class SharedMenuWorkspaceWidget extends StatefulWidget { + List excluded = []; + SharedMenuWorkspaceType type = SharedMenuWorkspaceType.workspace; + double? width; + String contextID; + SharedService service = SharedService(); + String? selected; + bool inner = false; + bool reverse = false; + double? topMargin; + String? before; + TextEditingController ctrl = TextEditingController(); + SharedMenuWorkspaceWidget ({ Key? key, this.width, required this.contextID, this.selected, + this.type = SharedMenuWorkspaceType.workspace, this.topMargin, this.excluded = const [], + this.inner = false, this.reverse = false, this.before}): super(key: key); + @override SharedMenuWorkspaceWidgetState createState() => SharedMenuWorkspaceWidgetState(); +} +class SharedMenuWorkspaceWidgetState extends State { + @override Widget build(BuildContext context) { + return Row( children: [ + Tooltip( message: "current workspace", child: + Theme( + data: Theme.of(context).copyWith( + canvasColor: Colors.grey, + ), + child: Container( + margin: EdgeInsets.only(top: widget.topMargin ?? (widget.inner ? 0 : 10)), + height: 50, width: (widget.width ?? MediaQuery.of(context).size.width) - 100, + decoration: BoxDecoration( + color: widget.reverse ? Colors.white : ( widget.inner ? Color.fromRGBO(38, 166, 154, 1) : Colors.grey.shade300 ), + border: const Border(bottom: BorderSide(color: Colors.transparent, width: 1)) + ), + padding: EdgeInsets.only(left: (widget.width ?? 400) < 400 ? 20 : 50, right: (widget.width ?? 400) < 400 ? 20 : 0), + child: DropdownButtonFormField( + value: widget.selected, + isExpanded: true, + style: const TextStyle(color:Colors.black, fontSize: 15), + hint: Text("choose shared workspace...", style: TextStyle(color: widget.inner ? Colors.grey.shade300 : Colors.grey, fontSize: 15)), + icon: Icon( // Add this + Icons.arrow_drop_down, // Add this + color: widget.inner ? Colors.white : Colors.grey, // Add this + ), + decoration: InputDecoration( + filled: true, + suffixIconColor: widget.inner ? Colors.grey.shade300 : Colors.grey, + focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, + borderSide: BorderSide(color: Colors.transparent, width: 0), + ), + fillColor: widget.reverse ? Colors.white : (widget.inner ? const Color.fromRGBO(38, 166, 154, 1) : Colors.grey.shade300), + contentPadding: EdgeInsets.only(left: 0 , right: (widget.width ?? 400) < 400 ? 0 : 30, top: 10, bottom: 30), + enabledBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, + borderSide: BorderSide(color: Colors.transparent, width: 0), + ), + border: const OutlineInputBorder( borderRadius: BorderRadius.zero, + borderSide: BorderSide(color: Colors.transparent, width: 0)), + ), + items: SharedWorkspaceLocal.workspaces.values.where((element) => !widget.excluded.contains(element.id) + ).map((e) => DropdownMenuItem( + value: e.id ,child: Text(e.name ?? ""),)).toList(), + onChanged: (value) { + setState(() { + widget.before = widget.selected; + widget.selected = value.toString(); + }); + })))), + Tooltip( + message: 'share', + child:InkWell( + mouseCursor: widget.selected == null || widget.selected == widget.before ? MouseCursor.defer : SystemMouseCursors.click, + onTap: () async { + if (widget.selected != null && widget.contextID != "" && widget.selected != widget.before) { + if (widget.type == SharedMenuWorkspaceType.peer) { + await widget.service.addPeer(context, widget.selected!, widget.contextID); + } else if (widget.type == SharedMenuWorkspaceType.workflow) { + await widget.service.addWorkflow(context, widget.selected!, widget.contextID); + } else { + await widget.service.addWorkspace(context, widget.selected!, widget.contextID); + } + SharedWorkspaceLocal.init(context, false); + setState(() {}); + dash.selectedLeftMenuKey.currentState?.setState(() { }); + CatalogFactory.key.currentState?.setState(() {}); + CatalogItemFactory.key.currentState?.setState(() {}); + WorkflowFactory.key.currentState?.setState(() {}); + } + }, + child: Container( + margin: EdgeInsets.only(top: widget.topMargin ?? (widget.inner ? 0 : 10)), + width: 50, + height: 50, + color: Colors.black, + child: Icon(Icons.share_rounded, + color: widget.selected == null || widget.selected == widget.before ? Colors.grey : Colors.white) + ) + ) + ), + Tooltip( + message: 'unshare', + child:InkWell( + mouseCursor: widget.selected == null || widget.selected == widget.before ? MouseCursor.defer : SystemMouseCursors.click, + onTap: () async { + if (widget.selected != null && widget.contextID != "" && widget.selected != widget.before) { + if (widget.type == SharedMenuWorkspaceType.peer) { + await widget.service.removePeer(context, widget.selected!, widget.contextID); + } else if (widget.type == SharedMenuWorkspaceType.workflow) { + await widget.service.removeWorkflow(context, widget.selected!, widget.contextID); + } else { + await widget.service.removeWorkspace(context, widget.selected!, widget.contextID); + } + SharedWorkspaceLocal.init(context, false); + setState(() {}); + dash.selectedLeftMenuKey.currentState?.setState(() { }); + CatalogFactory.key.currentState?.setState(() {}); + CatalogItemFactory.key.currentState?.setState(() {}); + WorkflowFactory.key.currentState?.setState(() {}); + } + }, + child: Container( + decoration: const BoxDecoration( + color: Colors.black, + border: Border(left: BorderSide(color: Colors.white, width: 1)) + ), + margin: EdgeInsets.only( top: widget.topMargin ?? (widget.inner ? 0 : 10 )), + width: 50, + height: 50, + child: Icon(Icons.delete, color: widget.selected == null || widget.selected == widget.before ? Colors.grey : Colors.white) + ) + ) + ) + ]); + } +} \ No newline at end of file diff --git a/lib/widgets/menu_clipper/workspace_menu.dart b/lib/widgets/menu_clipper/workspace_menu.dart index c5fc1af..a7f99da 100644 --- a/lib/widgets/menu_clipper/workspace_menu.dart +++ b/lib/widgets/menu_clipper/workspace_menu.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/core/models/shared_workspace_local.dart'; import 'package:oc_front/core/models/workspace_local.dart'; +import 'package:oc_front/widgets/menu_clipper/shared_workspace_menu.dart'; class MenuWorkspaceWidget extends StatefulWidget { bool simpliest = false; double? width; @@ -17,7 +19,7 @@ class MenuWorkspaceWidgetState extends State { data: Theme.of(context).copyWith( canvasColor: widget.simpliest ? Colors.grey.shade300 : Colors.grey, ), - child: Container( height: 50, width: widget.width ?? MediaQuery.of(context).size.width / ( widget.simpliest ? 1 : 2), + child: Container( height: 50, width: widget.width ?? MediaQuery.of(context).size.width / ( widget.simpliest ? 1 : 3), decoration: BoxDecoration( color: widget.simpliest ? Colors.white : const Color.fromRGBO(38, 166, 154, 1), border: Border(bottom: BorderSide(color: widget.simpliest ? Colors.grey.shade300 : Colors.transparent, width: 1)) @@ -58,12 +60,13 @@ class MenuWorkspaceWidgetState extends State { } }); })))), + widget.simpliest ? Container() : Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( - width: (MediaQuery.of(context).size.width / 2) - 50, + width: (MediaQuery.of(context).size.width / 3) - 50, height: 50, decoration: const BoxDecoration(border: Border(left: BorderSide(color: Colors.white))), child: TextFormField( @@ -106,7 +109,12 @@ class MenuWorkspaceWidgetState extends State { ) ) ) - ]) + ]), + widget.simpliest ? Container() : SharedMenuWorkspaceWidget( inner: true, + excluded: const[], + before: WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared, + selected: WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared, + contextID: WorkspaceLocal.current ?? "", width: (MediaQuery.of(context).size.width / 3)) ]); } } \ No newline at end of file diff --git a/library/flutter_flow_chart/lib/src/dashboard.dart b/library/flutter_flow_chart/lib/src/dashboard.dart index 031d482..58bef45 100755 --- a/library/flutter_flow_chart/lib/src/dashboard.dart +++ b/library/flutter_flow_chart/lib/src/dashboard.dart @@ -30,6 +30,7 @@ class Dashboard extends ChangeNotifier { List> tempHistory = []; List> history = []; Map scheduler = {}; + Map info = {}; bool scheduleActive = false; String? id; String name; @@ -231,6 +232,7 @@ class Dashboard extends ChangeNotifier { void deserialize(Map graph) { elements = []; arrows = []; + info["shared"] = graph["shared"] ?? []; scheduler = graph['schedule'] ?? {}; scheduleActive = graph['schedule_active'] ?? false; setZoomFactor(graph["graph"]?["zoom"] ?? 1.0); diff --git a/library/flutter_flow_chart/lib/src/flow_chart.dart b/library/flutter_flow_chart/lib/src/flow_chart.dart index 0781cf7..e26b6f3 100755 --- a/library/flutter_flow_chart/lib/src/flow_chart.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart.dart @@ -55,6 +55,7 @@ class FlowChart extends StatefulWidget { this.categories = const [], required this.draggableItemBuilder, this.onDashboardAlertOpened, + this.menuWidget, this.menuExtension, }) {} final List categories; @@ -63,6 +64,7 @@ class FlowChart extends StatefulWidget { final double innerMenuWidth; Widget Function()? menuExtension; + Widget Function(Dashboard data)? menuWidget; double itemWidth = 80; double zoom = 1; @@ -416,6 +418,7 @@ class FlowChartState extends State { child: ChartWidget( key: widget.dashboard.chartKey, flowChart: this, + menuWidget: widget.menuWidget, dashboard: widget.dashboard, onNewConnection: widget.onNewConnection, onDashboardTapped: widget.onDashboardLongTapped, @@ -437,7 +440,7 @@ class FlowChartState extends State { String newID = const Uuid().v4(); double ratio = 1; if (e.getWidth() != null && e.getHeight() != null) { - ratio = (e.getHeight()! / (e.getWidth()! - 30)); + ratio = (e.getHeight()! / (e.getWidth()!)); } FlowElement el = FlowElement( dashboard: widget.dashboard, @@ -579,10 +582,13 @@ class ChartWidget extends StatefulWidget { this.onScaleUpdate, required this.dashboard, this.onNewConnection, + this.menuWidget, }) : super(key: key); FlowChartState flowChart; + Widget Function(Dashboard dash)? menuWidget; + final void Function(BuildContext context, Offset position)? onDashboardTapped; /// callback for long tap on dashboard @@ -905,6 +911,7 @@ class ChartWidgetState extends State { Positioned(top: 0, right: 0, child: FlowChartMenu( key: widget.dashboard.chartMenuKey, chart: this, + menuExtension: widget.menuWidget != null ? widget.menuWidget!(widget.dashboard) : null, dashboard: widget.dashboard, width: MediaQuery.of(context).size.width) ), diff --git a/library/flutter_flow_chart/lib/src/flow_chart_menu.dart b/library/flutter_flow_chart/lib/src/flow_chart_menu.dart index 55c03c7..a2d120b 100644 --- a/library/flutter_flow_chart/lib/src/flow_chart_menu.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart_menu.dart @@ -11,8 +11,9 @@ class FlowChartMenu extends StatefulWidget { ChartWidgetState chart; Dashboard dashboard; double width = 100; + Widget? menuExtension; - FlowChartMenu ({ super.key, required this.chart, required this.dashboard, this.width = 100 }); + FlowChartMenu ({ super.key, required this.chart, required this.dashboard, this.width = 100, this.menuExtension }); @override FlowChartMenuState createState() => FlowChartMenuState(); } class FlowChartMenuState extends State { @@ -22,7 +23,7 @@ class FlowChartMenuState extends State { return Container( // SHORTCUT width: widget.width, height: 50, - padding: EdgeInsets.symmetric(horizontal: 20), + padding: EdgeInsets.only(left: 20), color: const Color.fromRGBO(38, 166, 154, 1), child: Row( children : [ Expanded(flex: 2, child: Row( children: [ widget.chart.widget.flowChart.widget.onDashboardAlertOpened == null ? Container() : Container( @@ -240,6 +241,12 @@ class FlowChartMenuState extends State { style: TextStyle(color: Colors.white, fontSize: 14), textAlign: TextAlign.start), padding: EdgeInsets.symmetric(horizontal: 20))), ])), + widget.menuExtension != null && MediaQuery.of(context).size.width > 600 ? Container( + decoration: BoxDecoration( + border: Border(left: BorderSide(color: Colors.white, width: 1)) + ), + child: widget.menuExtension + ) : Container() ]) ); } diff --git a/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart b/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart index 3b4090e..514bc4b 100644 --- a/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart @@ -17,14 +17,14 @@ class FlowChartSelectedMenuState extends State { Widget? w; if (widget.isDashboardInfo && widget.dashboard.elementSelected.length == 1) { w = Container( - width: 200, + width: 250, height: widget.height, color: Colors.grey.shade300, child: Column( children: [ ...widget.dashboard.infoItemWidget != null ? widget.dashboard.infoItemWidget!(widget.dashboard.elementSelected.first.element) : [], widget.dashboard.arrowsSelected.isNotEmpty || widget.dashboard.elementSelected.isNotEmpty ? Container( - width: 200, + width: 250, margin: EdgeInsets.only(top: 15), decoration: BoxDecoration(border: Border( top: BorderSide(color: Colors.grey, width: 1), @@ -45,7 +45,7 @@ class FlowChartSelectedMenuState extends State { }); }, child: Container( margin: EdgeInsets.all(10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)), - width: 140, height: 30, + width: 200, height: 30, child: Icon(Icons.delete_outline, color: Colors.black), )) ), @@ -61,7 +61,7 @@ class FlowChartSelectedMenuState extends State { }); }, child: Container( margin: EdgeInsets.all(10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)), - width: 140, height: 30, + width: 200, height: 30, child: Icon(Icons.copy, color: Colors.black), )) ), @@ -71,24 +71,24 @@ class FlowChartSelectedMenuState extends State { ); } else if (widget.isDashboardInfo && widget.dashboard.infoWidget != null) { w = Container( - width: 200, + width: 250, height: widget.height, color: Colors.grey.shade300, child: Column( children: widget.dashboard.infoWidget != null ? widget.dashboard.infoWidget!() : []) ); } else { w = Container( // SHORTCUT - width: 200, + width: 250, height: widget.height, color: Colors.grey.shade300, child: Column( children: [ - Container( padding: EdgeInsets.all(10), width: 200, height: 60, + Container( padding: EdgeInsets.all(10), width: 250, height: 60, decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("STYLE ${widget.dashboard.elementSelected.isNotEmpty ? "ELEMENT" : "ARROW"}", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), Text("<${widget.dashboard.arrowsSelected.isEmpty && widget.dashboard.elementSelected.isEmpty ? "general" : "selected"}>", style: TextStyle(fontSize: 12), textAlign: TextAlign.center), ])), - Container( width: 200, height: widget.height - 60, child: SingleChildScrollView( child: Column( children: [ + Container( width: 250, height: widget.height - 60, child: SingleChildScrollView( child: Column( children: [ widget.dashboard.elementSelected.isNotEmpty ? Container() : Container( padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Column( children: [ @@ -293,7 +293,7 @@ class FlowChartSelectedMenuState extends State { }, style: TextStyle(fontSize: 12), decoration: InputDecoration( - fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade200 : Colors.white, + fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade300 : Colors.white, filled: true, labelText: "dash", labelStyle: TextStyle(fontSize: 10), @@ -330,7 +330,7 @@ class FlowChartSelectedMenuState extends State { }, style: TextStyle(fontSize: 12), decoration: InputDecoration( - fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade200 : Colors.white, + fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade300 : Colors.white, filled: true, labelText: "space", labelStyle: TextStyle(fontSize: 10), @@ -438,7 +438,7 @@ class FlowChartSelectedMenuState extends State { }, style: TextStyle(fontSize: 12), decoration: InputDecoration( - fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade200 : Colors.white, + fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade300 : Colors.white, filled: true, labelText: "forward size", labelStyle: TextStyle(fontSize: 10), @@ -490,7 +490,7 @@ class FlowChartSelectedMenuState extends State { }, style: TextStyle(fontSize: 12), decoration: InputDecoration( - fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade200 : Colors.white, + fillColor: widget.dashboard.defaultDashWidth <= 0 ? Colors.grey.shade300 : Colors.white, filled: true, labelText: "back size", labelStyle: TextStyle(fontSize: 10), @@ -516,7 +516,7 @@ class FlowChartSelectedMenuState extends State { ]) ])), widget.dashboard.arrowsSelected.isNotEmpty || widget.dashboard.elementSelected.isNotEmpty ? Container( - width: 200, + width: 250, decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [ Tooltip( message: "remove", @@ -562,7 +562,7 @@ class FlowChartSelectedMenuState extends State { } return Column( children: [ Container( // SHORTCUT - width: 200, + width: 250, height: 50, decoration: BoxDecoration(color: Colors.grey.shade300, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), child: Row( children: [ @@ -573,7 +573,7 @@ class FlowChartSelectedMenuState extends State { child: Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 10), color: widget.isDashboardInfo ? Colors.grey : Colors.grey.shade300, - width: 100, child: Icon(Icons.info, color: Colors.white)) + width: 125, child: Icon(Icons.info, color: Colors.white)) ) ), Tooltip( @@ -583,7 +583,7 @@ class FlowChartSelectedMenuState extends State { child: Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 10), color: !widget.isDashboardInfo ? Colors.grey : Colors.grey.shade300, - width: 100, child: Icon(Icons.format_paint, color: Colors.white)), + width: 125, child: Icon(Icons.format_paint, color: Colors.white)), )) ])), w