diff --git a/lib/entity_class/const.dart b/lib/entity_class/const.dart index 4d62311..9e338e5 100644 --- a/lib/entity_class/const.dart +++ b/lib/entity_class/const.dart @@ -28,6 +28,7 @@ class EntityState { static const unavailable = 'unavailable'; static const ok = 'ok'; static const problem = 'problem'; + static const active = 'active'; } class EntityUIAction { diff --git a/lib/entity_class/timer_entity.dart b/lib/entity_class/timer_entity.dart new file mode 100644 index 0000000..6a2a3ec --- /dev/null +++ b/lib/entity_class/timer_entity.dart @@ -0,0 +1,36 @@ +part of '../main.dart'; + +class TimerEntity extends Entity { + TimerEntity(Map rawData) : super(rawData); + + Duration duration; + + @override + void update(Map rawData) { + super.update(rawData); + String durationSource = "${attributes["duration"]}"; + List durationList = durationSource.split(":"); + if (durationList.length == 1) { + duration = Duration(seconds: int.tryParse(durationList[0] ?? 0)); + } else if (durationList.length == 2) { + duration = Duration( + hours: int.tryParse(durationList[0]) ?? 0, + minutes: int.tryParse(durationList[1]) ?? 0 + ); + } else if (durationList.length == 3) { + duration = Duration( + hours: int.tryParse(durationList[0]) ?? 0, + minutes: int.tryParse(durationList[1]) ?? 0, + seconds: int.tryParse(durationList[2]) ?? 0 + ); + } else { + Logger.e("Cann't parse $entityId duration: $durationSource"); + duration = Duration(seconds: 0); + } + } + + @override + Widget _buildStatePart(BuildContext context) { + return TimerState(); + } +} \ No newline at end of file diff --git a/lib/entity_collection.class.dart b/lib/entity_collection.class.dart index 7c26102..3b4a07d 100644 --- a/lib/entity_collection.class.dart +++ b/lib/entity_collection.class.dart @@ -92,6 +92,9 @@ class EntityCollection { case "alarm_control_panel": { return AlarmControlPanelEntity(rawEntityData); } + case "timer": { + return TimerEntity(rawEntityData); + } default: { return Entity(rawEntityData); } diff --git a/lib/entity_widgets/entity_colors.class.dart b/lib/entity_widgets/entity_colors.class.dart index 5be413b..83233b2 100644 --- a/lib/entity_widgets/entity_colors.class.dart +++ b/lib/entity_widgets/entity_colors.class.dart @@ -10,7 +10,7 @@ class EntityColor { static const _stateColors = { EntityState.on: Colors.amber, "auto": Colors.amber, - EntityState.idle: Colors.amber, + EntityState.active: Colors.amber, EntityState.playing: Colors.amber, "above_horizon": Colors.amber, EntityState.home: Colors.amber, @@ -19,6 +19,7 @@ class EntityColor { EntityState.closed: Color.fromRGBO(68, 115, 158, 1.0), "below_horizon": Color.fromRGBO(68, 115, 158, 1.0), "default": Color.fromRGBO(68, 115, 158, 1.0), + EntityState.idle: Color.fromRGBO(68, 115, 158, 1.0), "heat": Colors.redAccent, "cool": Colors.lightBlue, EntityState.unavailable: Colors.black26, diff --git a/lib/entity_widgets/state/simple_state.dart b/lib/entity_widgets/state/simple_state.dart index c53dda2..8f8ab9f 100644 --- a/lib/entity_widgets/state/simple_state.dart +++ b/lib/entity_widgets/state/simple_state.dart @@ -6,14 +6,20 @@ class SimpleEntityState extends StatelessWidget { final TextAlign textAlign; final EdgeInsetsGeometry padding; final int maxLines; + final String customValue; - const SimpleEntityState({Key key, this.maxLines: 10, this.expanded: true, this.textAlign: TextAlign.right, this.padding: const EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0)}) : super(key: key); + const SimpleEntityState({Key key, this.maxLines: 10, this.expanded: true, this.textAlign: TextAlign.right, this.padding: const EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0), this.customValue}) : super(key: key); @override Widget build(BuildContext context) { final entityModel = EntityModel.of(context); - String state = entityModel.entityWrapper.entity.displayState ?? ""; - state = state.replaceAll("\n", "").replaceAll("\t", " ").trim(); + String state; + if (customValue == null) { + state = entityModel.entityWrapper.entity.displayState ?? ""; + state = state.replaceAll("\n", "").replaceAll("\t", " ").trim(); + } else { + state = customValue; + } TextStyle textStyle = TextStyle( fontSize: Sizes.stateFontSize, ); diff --git a/lib/entity_widgets/state/timer_state.dart b/lib/entity_widgets/state/timer_state.dart new file mode 100644 index 0000000..c5ce94e --- /dev/null +++ b/lib/entity_widgets/state/timer_state.dart @@ -0,0 +1,65 @@ +part of '../../main.dart'; + +class TimerState extends StatefulWidget { + //final bool expanded; + //final TextAlign textAlign; + //final EdgeInsetsGeometry padding; + //final int maxLines; + + const TimerState({Key key}) : super(key: key); + + @override + _TimerStateState createState() => _TimerStateState(); + +} + +class _TimerStateState extends State { + + Timer timer; + Duration remaining = Duration(seconds: 0); + + void checkState(TimerEntity entity) { + if (entity.state == EntityState.active) { + //Logger.d("Timer is active"); + if (timer == null || !timer.isActive) { + timer = Timer.periodic(Duration(seconds: 1), (timer) { + setState(() { + try { + int passed = DateTime + .now() + .difference(entity._lastUpdated) + .inSeconds; + remaining = Duration(seconds: entity.duration.inSeconds - passed); + } catch (e) { + Logger.e("Error calculating ${entity.entityId} remaining time: ${e.toString()}"); + remaining = Duration(seconds: 0); + } + }); + }); + } + } else { + timer?.cancel(); + } + } + + @override + Widget build(BuildContext context) { + EntityModel model = EntityModel.of(context); + TimerEntity entity = model.entityWrapper.entity; + checkState(entity); + if (entity.state != EntityState.active) { + return SimpleEntityState(); + } else { + return SimpleEntityState( + customValue: "${remaining.toString().split('.')[0]}", + ); + } + } + + @override + void dispose() { + timer?.cancel(); + super.dispose(); + } + +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 27b5b84..22b4f06 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,6 +21,7 @@ import 'package:flutter_custom_tabs/flutter_custom_tabs.dart'; part 'entity_class/const.dart'; part 'entity_class/entity.class.dart'; part 'entity_class/entity_wrapper.class.dart'; +part 'entity_class/timer_entity.dart'; part 'entity_class/switch_entity.class.dart'; part 'entity_class/button_entity.class.dart'; part 'entity_class/text_entity.class.dart'; @@ -67,6 +68,7 @@ part 'entity_widgets/controls/slider_controls.dart'; part 'entity_widgets/state/text_input_state.dart'; part 'entity_widgets/state/select_state.dart'; part 'entity_widgets/state/simple_state.dart'; +part 'entity_widgets/state/timer_state.dart'; part 'entity_widgets/state/climate_state.dart'; part 'entity_widgets/state/cover_state.dart'; part 'entity_widgets/state/date_time_state.dart';