Files
gomix_flutter/lib/mixing_card.dart
minie4 fb28b9361a Implement port connection dialog
Implements:
- Viewing connections (routes)
- Creating and deleting connections
- Changing volume of connectons
- Muting / unmuting connections
2024-08-28 23:20:48 +02:00

181 lines
5.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:gomix_flutter/mixer_state.dart' as mixer;
import 'package:gomix_flutter/port_connection_dialog.dart';
import 'package:gomix_flutter/utils.dart';
class MixingCard extends StatefulWidget {
final mixer.Port port;
final mixer.MixerState mixerState;
final Function(Map<String, Object> data) sendAction;
final bool isOutput;
const MixingCard(
{super.key,
required this.port,
required this.mixerState,
required this.sendAction,
this.isOutput = false});
@override
State<MixingCard> createState() => _MixingCardState();
}
class DialogDataModel extends ChangeNotifier {
String? portUUID;
late mixer.MixerState mixerState;
late mixer.Port port;
void updatePort(bool force) {
if (portUUID == null) {
return;
}
// Only update port reference if it is actually outdated
if (force ||
(!mixerState.inputs.contains(port) &&
!mixerState.outputs.contains(port))) {
mixer.Port? newPort = findPort(mixerState, portUUID!);
if (newPort != null) port = newPort;
}
}
void setPortUUID(String uuid) {
portUUID = uuid;
updatePort(true);
}
void setMixerState(mixer.MixerState state) {
mixerState = state;
updatePort(false);
notifyListeners();
}
}
class _MixingCardState extends State<MixingCard> {
double _sliderValue = 0;
int _debounceTimer = 0;
bool _sliderActive = false;
DialogDataModel dataModel = DialogDataModel();
@override
void initState() {
super.initState();
dataModel.setMixerState(widget.mixerState);
_sliderValue = widget.port.state.volume;
}
@override
void didUpdateWidget(MixingCard oldWidget) {
if (_sliderActive) return;
dataModel.setMixerState(widget.mixerState);
_sliderValue = widget.port.state.volume;
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
var labelStyle = Theme.of(context)
.textTheme
.labelLarge
?.apply(color: Theme.of(context).colorScheme.primary);
return Card(
margin: const EdgeInsets.all(0),
shadowColor: Colors.transparent,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 15, right: 15, top: 15),
child: Row(
children: [
Expanded(child: Text(widget.port.name, style: labelStyle)),
SizedBox(
height: 40,
width: 40,
child: IconButton.filledTonal(
iconSize: 20,
isSelected: widget.port.state.mute,
onPressed: () {
widget.sendAction({
"method": "setPortState",
"UUID": widget.port.uuid,
"stateData": {"mute": !widget.port.state.mute}
});
},
icon: widget.isOutput
? (widget.port.state.mute
? const Icon(Icons.volume_off_outlined)
: const Icon(Icons.volume_up_outlined))
: (widget.port.state.mute
? const Icon(Icons.mic_off_outlined)
: const Icon(Icons.mic_none_outlined)),
),
),
const SizedBox(width: 5),
SizedBox(
height: 40,
width: 40,
child: IconButton.outlined(
iconSize: 20,
isSelected: false,
onPressed: () {
dataModel.setPortUUID(widget.port.uuid);
PortConnectionDialog(
sendAction: widget.sendAction,
port: widget.port,
isOutput: widget.isOutput,
dataModel: dataModel,
mixerState: widget.mixerState)
.show(context);
},
icon: const Icon(Icons.unfold_more)))
],
),
),
SizedBox(
width: MediaQuery.of(context).size.width + 180,
child: Slider(
value: _sliderValue,
min: 0,
max: 4,
label: _sliderValue.toStringAsFixed(2),
onChangeStart: ((val) {
_sliderActive = true;
}),
onChangeEnd: ((val) {
// Send the current state to make sure we
// don't miss the last value due to the debounce
widget.sendAction({
"method": "setPortState",
"UUID": widget.port.uuid,
"stateData": {"volume": val}
});
// Make sure the slider value is still correct
// after suppressing updates
_sliderActive = false;
setState(() {
_sliderValue = widget.port.state.volume;
});
}),
onChanged: (val) {
setState(() {
_sliderValue = val;
});
if (DateTime.now().millisecondsSinceEpoch - _debounceTimer <
30) {
return;
}
_debounceTimer = DateTime.now().millisecondsSinceEpoch;
widget.sendAction({
"method": "setPortState",
"UUID": widget.port.uuid,
"stateData": {"volume": val}
});
},
),
),
],
),
);
}
}