Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion lib/pages/dashboard/add_widget_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import 'package:flutter/material.dart';

import 'package:collection/collection.dart';
import 'package:popover/popover.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'package:elastic_dashboard/services/nt_connection.dart';
import 'package:elastic_dashboard/services/nt_widget_registry.dart';
import 'package:elastic_dashboard/widgets/dialog_widgets/dialog_text_input.dart';
import 'package:elastic_dashboard/widgets/dialog_widgets/dialog_toggle_switch.dart';
import 'package:elastic_dashboard/widgets/dialog_widgets/layout_drag_tile.dart';
import 'package:elastic_dashboard/widgets/dialog_widgets/nt_widget_drag_tile.dart';
import 'package:elastic_dashboard/widgets/draggable_containers/models/layout_container_model.dart';
import 'package:elastic_dashboard/widgets/draggable_containers/models/widget_container_model.dart';
import 'package:elastic_dashboard/widgets/draggable_dialog.dart';
Expand Down Expand Up @@ -94,7 +97,7 @@ class _AddWidgetDialogState extends State<AddWidgetDialog> {
const TabBar(
tabs: [
Tab(text: 'Network Tables'),
Tab(text: 'Layouts'),
Tab(text: 'Widgets'),
],
),
const SizedBox(height: 5),
Expand All @@ -114,6 +117,23 @@ class _AddWidgetDialogState extends State<AddWidgetDialog> {
),
ListView(
children: [
ExpansionTile(
title: const Text('Network Tables Widgets'),
children: NTWidgetRegistry.registeredWidgetNames
.sorted((a, b) => a.compareTo(b))
.map(
(widgetName) => NTWidgetDragTile(
ntConnection: widget.ntConnection,
preferences: widget.preferences,
gridIndex: widget.gridIndex,
widgetName: widgetName,
onDragUpdate: widget.onNTDragUpdate,
onDragEnd: widget.onNTDragEnd,
onRemoveWidget: () => onRemove(widget.grid),
),
)
.toList(),
),
LayoutDragTile(
gridIndex: widget.gridIndex,
title: 'List Layout',
Expand Down
16 changes: 11 additions & 5 deletions lib/services/nt_widget_registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ typedef NTModelProvider<T extends NTWidgetModel> =
T Function({
required NTConnection ntConnection,
required SharedPreferences preferences,
required String topic,
required String? topic,
NT4Type? dataType,
double? period,
NT4StructMeta? ntStructMeta,
Expand All @@ -68,13 +68,15 @@ typedef MultiTopicNTModelProvider<T extends MultiTopicNTWidgetModel> =
T Function({
required NTConnection ntConnection,
required SharedPreferences preferences,
required String topic,
required String? topic,
double? period,
});

typedef NTWidgetProvider<T extends NTWidget> = T Function({Key? key});

class NTWidgetRegistry {
static final List<String> _registeredNames = [];

static final Map<String, NTWidgetProvider> _widgetNameBuildMap = {};

static final Map<String, NTModelProvider> _modelNameBuildMap = {};
Expand All @@ -89,6 +91,9 @@ class NTWidgetRegistry {

static const double _normalSize = 128.0;

static List<String> get registeredWidgetNames =>
_registeredNames.toList(growable: false);

NTWidgetRegistry._();

static bool _initialized = false;
Expand Down Expand Up @@ -442,7 +447,7 @@ class NTWidgetRegistry {
SharedPreferences preferences,
NT4StructMeta? ntStructMeta,
String type,
String topic, {
String? topic, {
NT4Type? dataType,
double? period,
}) {
Expand Down Expand Up @@ -617,7 +622,7 @@ class NTWidgetRegistry {
({
required NTConnection ntConnection,
required SharedPreferences preferences,
required String topic,
required String? topic,
double? period,
NT4Type? dataType,
NT4StructMeta? ntStructMeta,
Expand Down Expand Up @@ -649,7 +654,7 @@ class NTWidgetRegistry {
({
required NTConnection ntConnection,
required SharedPreferences preferences,
required String topic,
required String? topic,
double? period,
NT4Type? dataType,
NT4StructMeta? ntStructMeta,
Expand Down Expand Up @@ -719,6 +724,7 @@ class NTWidgetRegistry {
required double? defaultWidth,
required double? defaultHeight,
}) {
_registeredNames.add(names.first);
for (String name in names) {
register(
name: name,
Expand Down
6 changes: 6 additions & 0 deletions lib/widgets/dialog_widgets/layout_drag_tile.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

import 'package:collection/collection.dart';

import 'package:elastic_dashboard/widgets/draggable_containers/models/layout_container_model.dart';
import 'package:elastic_dashboard/widgets/gesture/drag_listener.dart';

Expand Down Expand Up @@ -67,6 +69,10 @@ class _LayoutDragTileState extends State<LayoutDragTile> {
Widget build(BuildContext context) => InkWell(
onTap: () {},
child: DragListener(
overrideVertical: false,
supportedDevices: PointerDeviceKind.values
.whereNot((element) => element == PointerDeviceKind.trackpad)
.toSet(),
onDragStart: (details) {
if (draggingWidget != null) {
return;
Expand Down
160 changes: 160 additions & 0 deletions lib/widgets/dialog_widgets/nt_widget_drag_tile.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import 'dart:ui';

import 'package:flutter/material.dart';

import 'package:collection/collection.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'package:elastic_dashboard/services/nt4_client.dart';
import 'package:elastic_dashboard/services/nt_connection.dart';
import 'package:elastic_dashboard/services/nt_widget_registry.dart';
import 'package:elastic_dashboard/widgets/draggable_containers/models/nt_widget_container_model.dart';
import 'package:elastic_dashboard/widgets/draggable_containers/models/widget_container_model.dart';
import 'package:elastic_dashboard/widgets/gesture/drag_listener.dart';
import 'package:elastic_dashboard/widgets/nt_widgets/nt_widget.dart';

class NTWidgetDragTile extends StatefulWidget {
final NTConnection ntConnection;
final SharedPreferences preferences;
final NT4StructMeta? ntStructMeta;

final int gridIndex;
final String widgetName;

final void Function(Offset globalPosition, WidgetContainerModel widget)
onDragUpdate;

final void Function(WidgetContainerModel widget) onDragEnd;

final void Function() onRemoveWidget;

const NTWidgetDragTile({
super.key,
required this.ntConnection,
required this.preferences,
this.ntStructMeta,
required this.gridIndex,
required this.widgetName,
required this.onDragUpdate,
required this.onDragEnd,
required this.onRemoveWidget,
});

@override
State<NTWidgetDragTile> createState() => _NTWidgetDragTileState();
}

class _NTWidgetDragTileState extends State<NTWidgetDragTile> {
WidgetContainerModel? draggingWidget;

void cancelDrag() {
if (draggingWidget != null) {
draggingWidget?.unSubscribe();
draggingWidget?.softDispose(deleting: true);
draggingWidget?.dispose();

widget.onRemoveWidget();

draggingWidget = null;
}
}

@override
void didUpdateWidget(NTWidgetDragTile oldWidget) {
if (widget.gridIndex != oldWidget.gridIndex) {
cancelDrag();
}
super.didUpdateWidget(oldWidget);
}

@override
void dispose() {
cancelDrag();

super.dispose();
}

@override
Widget build(BuildContext context) => InkWell(
onTap: () {},
child: DragListener(
overrideVertical: false,
supportedDevices: PointerDeviceKind.values
.whereNot((element) => element == PointerDeviceKind.trackpad)
.toSet(),
onDragStart: (details) {
if (draggingWidget != null) {
return;
}

// Prevents 2 finger drags from dragging a widget
if (details.kind != null &&
details.kind! == PointerDeviceKind.trackpad) {
draggingWidget = null;
return;
}

setState(() {
NTWidgetModel widgetModel = NTWidgetRegistry.buildNTModelFromType(
widget.ntConnection,
widget.preferences,
widget.ntStructMeta,
widget.widgetName,
null,
);

NTWidget? ntWidget = NTWidgetRegistry.buildNTWidgetFromModel(
widgetModel,
);

if (ntWidget == null) {
widgetModel.unSubscribe();
widgetModel.softDispose(deleting: true);
widgetModel.dispose();
return;
}

double width = NTWidgetRegistry.getDefaultWidth(widgetModel);
double height = NTWidgetRegistry.getDefaultHeight(widgetModel);

draggingWidget = NTWidgetContainerModel(
ntConnection: widget.ntConnection,
preferences: widget.preferences,
initialPosition: Rect.fromLTWH(0.0, 0.0, width, height),
title: widget.widgetName,
childModel: widgetModel,
);
});
},
onDragUpdate: (details) {
if (draggingWidget == null) {
return;
}

widget.onDragUpdate.call(details.globalPosition, draggingWidget!);
},
onDragEnd: (details) {
if (draggingWidget == null) {
return;
}

widget.onDragEnd.call(draggingWidget!);

setState(() => draggingWidget = null);
},
child: Column(
children: [
Padding(
padding: const EdgeInsetsDirectional.only(start: 32),
child: ListTile(
dense: true,
contentPadding: const EdgeInsets.only(right: 20),
title: Text(widget.widgetName),
),
),
const Divider(height: 0),
],
),
),
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,12 @@ class NTWidgetContainerModel extends WidgetContainerModel {
Flexible(
child: DialogTextInput(
onSubmit: (value) {
childModel.topic = value;
childModel.topic = value.isNotEmpty ? value : null;
childModel.resetSubscription();
},
label: 'Topic',
initialText: childModel.topic,
allowEmptySubmission: true,
),
),
const SizedBox(width: 5),
Expand Down
13 changes: 9 additions & 4 deletions lib/widgets/nt_widgets/multi_topic/accelerometer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ class AccelerometerModel extends MultiTopicNTWidgetModel {
@override
String type = AccelerometerWidget.widgetType;

late NT4Subscription _valueSubscription;
NT4Subscription get valueSubscription => _valueSubscription;
NT4Subscription? _valueSubscription;
NT4Subscription? get valueSubscription => _valueSubscription;

String get valueTopic => '$topic/Value';

@override
List<NT4Subscription> get subscriptions => [_valueSubscription];
List<NT4Subscription> get subscriptions => [?_valueSubscription];

AccelerometerModel({
required super.ntConnection,
Expand All @@ -33,6 +33,11 @@ class AccelerometerModel extends MultiTopicNTWidgetModel {

@override
void initializeSubscriptions() {
if (topic == null) {
_valueSubscription = null;
return;
}

_valueSubscription = ntConnection.subscribe(valueTopic, super.period);
}
}
Expand All @@ -47,7 +52,7 @@ class AccelerometerWidget extends NTWidget {
AccelerometerModel model = cast(context.watch<NTWidgetModel>());

return ValueListenableBuilder(
valueListenable: model.valueSubscription,
valueListenable: model.valueSubscription ?? ValueNotifier(null),
builder: (context, data, child) {
double value = tryCast(data) ?? 0.0;

Expand Down
Loading
Loading