diff --git a/veilid-flutter/example/lib/history_text_editing_controller.dart b/veilid-flutter/example/lib/history_text_editing_controller.dart new file mode 100644 index 00000000..f9646e53 --- /dev/null +++ b/veilid-flutter/example/lib/history_text_editing_controller.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +/// TextField History Controller +class HistoryTextEditingController { + HistoryTextEditingController( + {required this.setState, TextEditingController? controller}) + : _controller = controller ?? TextEditingController() { + _historyFocusNode = FocusNode(onKeyEvent: (_node, event) { + if (event.runtimeType == KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.arrowUp) { + if (_historyPosition > 0) { + if (_historyPosition == _history.length) { + _historyCurrentEdit = _controller.text; + } + _historyPosition -= 1; + setState(() { + _controller.text = _history[_historyPosition]; + }); + } + return KeyEventResult.handled; + } else if (event.runtimeType == KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.arrowDown) { + if (_historyPosition < _history.length) { + _historyPosition += 1; + setState(() { + if (_historyPosition == _history.length) { + _controller.text = _historyCurrentEdit; + } else { + _controller.text = _history[_historyPosition]; + } + }); + } + return KeyEventResult.handled; + } else if (event.runtimeType == KeyDownEvent) { + _historyPosition = _history.length; + _historyCurrentEdit = _controller.text; + } + return KeyEventResult.ignored; + }); + } + + void submit(String v) { + // add to history + if (_history.isEmpty || _history.last != v) { + _history.add(v); + if (_history.length > 100) { + _history.removeAt(0); + } + } + _historyPosition = _history.length; + setState(() { + _controller.text = ''; + }); + } + + FocusNode get focusNode => _historyFocusNode; + TextEditingController get controller => _controller; + + //////////////////////////////////////////////////////////////////////////// + + late void Function(void Function()) setState; + final TextEditingController _controller; + late final FocusNode _historyFocusNode; + + final List _history = []; + int _historyPosition = 0; + String _historyCurrentEdit = ''; +} diff --git a/veilid-server/src/settings.rs b/veilid-server/src/settings.rs index e4455fd6..e09f1305 100644 --- a/veilid-server/src/settings.rs +++ b/veilid-server/src/settings.rs @@ -163,26 +163,26 @@ core: udp: enabled: true socket_pool_size: 0 - listen_address: '' + listen_address: ':5150' # public_address: '' tcp: connect: true listen: true max_connections: 32 - listen_address: '' + listen_address: ':5150' #'public_address: '' ws: connect: true listen: true max_connections: 32 - listen_address: '' + listen_address: ':5150' path: 'ws' # url: 'ws://localhost:5150/ws' wss: connect: true listen: false max_connections: 32 - listen_address: '' + listen_address: ':5150' path: 'ws' # url: '' "#, @@ -1676,26 +1676,40 @@ mod tests { ); assert_eq!(s.core.network.application.http.url, None); // + let valid_socket_addrs = [ + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 5150), + SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), 5150), + ]; + assert!(s.core.network.protocol.udp.enabled); assert_eq!(s.core.network.protocol.udp.socket_pool_size, 0); - assert_eq!(s.core.network.protocol.udp.listen_address.name, ""); - assert_eq!(s.core.network.protocol.udp.listen_address.addrs, vec![]); + assert_eq!(s.core.network.protocol.udp.listen_address.name, ":5150"); + for addr in &s.core.network.protocol.udp.listen_address.addrs { + assert!(valid_socket_addrs.contains(addr)); + } + assert!(!s.core.network.protocol.udp.listen_address.addrs.is_empty()); assert_eq!(s.core.network.protocol.udp.public_address, None); // assert!(s.core.network.protocol.tcp.connect); assert!(s.core.network.protocol.tcp.listen); assert_eq!(s.core.network.protocol.tcp.max_connections, 32); - assert_eq!(s.core.network.protocol.tcp.listen_address.name, ""); - assert_eq!(s.core.network.protocol.tcp.listen_address.addrs, vec![]); + assert_eq!(s.core.network.protocol.tcp.listen_address.name, ":5150"); + for addr in &s.core.network.protocol.tcp.listen_address.addrs { + assert!(valid_socket_addrs.contains(addr)); + } + assert!(!s.core.network.protocol.tcp.listen_address.addrs.is_empty()); assert_eq!(s.core.network.protocol.tcp.public_address, None); // assert!(s.core.network.protocol.ws.connect); assert!(s.core.network.protocol.ws.listen); assert_eq!(s.core.network.protocol.ws.max_connections, 32); - assert_eq!(s.core.network.protocol.ws.listen_address.name, ""); - assert_eq!(s.core.network.protocol.ws.listen_address.addrs, vec![]); + assert_eq!(s.core.network.protocol.ws.listen_address.name, ":5150"); + for addr in &s.core.network.protocol.ws.listen_address.addrs { + assert!(valid_socket_addrs.contains(addr)); + } + assert!(!s.core.network.protocol.ws.listen_address.addrs.is_empty()); assert_eq!( s.core.network.protocol.ws.path, std::path::PathBuf::from("ws") @@ -1705,8 +1719,11 @@ mod tests { assert!(s.core.network.protocol.wss.connect); assert!(!s.core.network.protocol.wss.listen); assert_eq!(s.core.network.protocol.wss.max_connections, 32); - assert_eq!(s.core.network.protocol.wss.listen_address.name, ""); - assert_eq!(s.core.network.protocol.wss.listen_address.addrs, vec![]); + assert_eq!(s.core.network.protocol.wss.listen_address.name, ":5150"); + for addr in &s.core.network.protocol.wss.listen_address.addrs { + assert!(valid_socket_addrs.contains(addr)); + } + assert!(!s.core.network.protocol.wss.listen_address.addrs.is_empty()); assert_eq!( s.core.network.protocol.wss.path, std::path::PathBuf::from("ws")