diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 898e677..b460aa9 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -5,8 +5,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_font_icons/flutter_font_icons.dart'; import 'package:provider/provider.dart'; import 'package:tuple/tuple.dart'; +import 'package:weechat/relay/nicklist.dart'; +import 'package:weechat/widgets/channel/user_list.dart'; import 'package:weechat/widgets/home/channel_list_item.dart'; -import 'package:weechat/pages/log.dart'; import 'package:weechat/pages/log/event_logger.dart'; import 'package:weechat/pages/settings.dart'; import 'package:weechat/pages/settings/config.dart'; @@ -108,10 +109,8 @@ class _HomePageState extends State with WidgetsBindingObserver { return _suspend(); } case AppLifecycleState.detached: - { - break; - } case AppLifecycleState.inactive: + case AppLifecycleState.hidden: { break; } @@ -313,20 +312,25 @@ class _HomePageState extends State with WidgetsBindingObserver { _channelListDrawerChanged(_relayConnection!, isOpen); } }, + endDrawer: _userListDrawer(context), appBar: AppBar( title: _title(), actions: [ + // show users button if connected + if (cs.connected) + Builder( + builder: (context) => IconButton( + icon: const Icon(Icons.group), + onPressed: () => _toggleUserList(context), + ), + ), + // settings button IconButton( + icon: const Icon(Icons.settings), onPressed: () { - Navigator.of(context).push(LogPage.route()); + Navigator.of(context).push(SettingsPage.route()); }, - icon: const Icon(Feather.info), - ), - IconButton( - onPressed: () { - Navigator.of(context).push(SettingsPage.route()); - }, - icon: const Icon(Icons.settings)), + ) ], ), @@ -387,6 +391,30 @@ class _HomePageState extends State with WidgetsBindingObserver { }); } + Widget? _userListDrawer(BuildContext context) { + if (_relayBuffer != null) { + return Drawer( + child: UserListWidget( + nicklist: RelayBufferNicklist( + bufferId: _relayBuffer!.bufferPointer, + connection: _relayBuffer!.relayConnection, + ), + ), + ); + } else { + return const Drawer(); + } + } + + void _toggleUserList(BuildContext context) { + final scaff = Scaffold.of(context); + if (scaff.isEndDrawerOpen) { + scaff.closeEndDrawer(); + } else { + scaff.openEndDrawer(); + } + } + Widget? _channelListDrawer(BuildContext context) { final con = RelayConnection.of(context, listen: false); if (!con.isConnected) return null; diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index 6ae0a37..82fb226 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_font_icons/flutter_font_icons.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:weechat/pages/log.dart'; import 'package:weechat/pages/settings/config.dart'; class SettingsPage extends StatefulWidget { @@ -23,6 +24,14 @@ class _SettingsState extends State { return Scaffold( appBar: AppBar( title: Text(loc.settingsTitle), + actions: [ + IconButton( + onPressed: () { + Navigator.of(context).push(LogPage.route()); + }, + icon: const Icon(Feather.info), + ), + ], ), body: ListView( children: [ diff --git a/lib/relay/nicklist.dart b/lib/relay/nicklist.dart new file mode 100644 index 0000000..00c74de --- /dev/null +++ b/lib/relay/nicklist.dart @@ -0,0 +1,55 @@ +import 'package:weechat/relay/connection.dart'; +import 'package:weechat/relay/protocol/message_body.dart'; + +class NicklistData { + final String name; + final String color; + final String prefix; + final String prefix_color; + + NicklistData({ + required this.name, + required this.color, + required this.prefix, + required this.prefix_color, + }); +} + +class RelayBufferNicklist { + final RelayConnection connection; + final String bufferId; + + RelayBufferNicklist({ + required this.connection, + required this.bufferId, + }); + + Map> get groups => Map.unmodifiable(_groups); + final Map> _groups = {}; + + Future?> load() async { + return await connection.command( + "nicklist $bufferId", + callback: (RelayMessageBody body) { + final lst = []; + for (final hdata in body.objects()) { + for (final obj in hdata.objects) { + print(obj); + // sort objects into _groups + if (obj.values[0] == "\x01") { + continue; + } else { + lst.add(NicklistData( + name: obj.values[3], + color: obj.values[4], + prefix: obj.values[5], + prefix_color: obj.values[6], + )); + } + } + } + return lst; + }, + ); + } +} diff --git a/lib/widgets/channel/user_list.dart b/lib/widgets/channel/user_list.dart new file mode 100644 index 0000000..84caace --- /dev/null +++ b/lib/widgets/channel/user_list.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:weechat/relay/nicklist.dart'; + +class UserListWidget extends StatefulWidget { + final RelayBufferNicklist nicklist; + + const UserListWidget({ + required this.nicklist, + super.key, + }); + + @override + State createState() { + return _State(); + } +} + +Future? _request; + +class _State extends State { + RelayBufferNicklist get nicklist => widget.nicklist; + + _State(); + + @override + Widget build(BuildContext context) { + // request nicklist from server + _request ??= nicklist.load(); + + return FutureBuilder( + future: _request, + builder: (context, snapshot) { + if (!snapshot.hasData) { + return _loading(); + } else if (snapshot.data == null) { + return _failed(); + } else { + return _userList(context, snapshot.data!); + } + }); + } + + Widget _loading() => Container(); + Widget _failed() => Container(); + + Widget _userList(BuildContext context, List nicks) { + return ListView( + children: nicks.map((nick) => _userWidget(context, nick)).toList(), + ); + } + + Widget _userWidget(BuildContext context, NicklistData nick) { + return ListTile( + title: Text("${nick.prefix}${nick.name}"), + ); + } +} diff --git a/lib/widgets/home/channel_list_item.dart b/lib/widgets/home/channel_list_item.dart index 7f55b76..c7b1d0c 100644 --- a/lib/widgets/home/channel_list_item.dart +++ b/lib/widgets/home/channel_list_item.dart @@ -24,12 +24,11 @@ class ChannelListItem extends StatelessWidget { ); @override - Widget build(BuildContext context, - { + Widget build( + BuildContext context, { RelayHotlistEntry? hotlist, Future Function(BuildContext)? openBuffer, }) { - final theme = Theme.of(context); var titleColor = theme.disabledColor; @@ -37,13 +36,13 @@ class ChannelListItem extends StatelessWidget { switch (hotlist?.priority) { case 0: // GUI_HOTLIST_LOW - titleColor = theme.colorScheme.inverseSurface.withAlpha(200); + titleColor = theme.colorScheme.onSurface.withAlpha(180); break; case 1: // GUI_HOTLIST_MESSAGE - titleColor = theme.colorScheme.secondary; + titleColor = theme.colorScheme.onSurface; break; case 2: // GUI_HOTLIST_PRIVATE - titleColor = theme.colorScheme.secondary; + titleColor = theme.colorScheme.onSurface; break; case 3: // GUI_HOTLIST_HIGHLIGHT titleColor = theme.colorScheme.primary; diff --git a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig index 0ec055c..da89a19 100644 --- a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig +++ b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -3,8 +3,8 @@ FLUTTER_ROOT=E:\dev\flutter FLUTTER_APPLICATION_PATH=E:\dev\weechat COCOAPODS_PARALLEL_CODE_SIGN=true FLUTTER_BUILD_DIR=build -FLUTTER_BUILD_NAME=1.24.10 -FLUTTER_BUILD_NUMBER=16 +FLUTTER_BUILD_NAME=1.24.12 +FLUTTER_BUILD_NUMBER=18 DART_OBFUSCATION=false TRACK_WIDGET_CREATION=true TREE_SHAKE_ICONS=false diff --git a/macos/Flutter/ephemeral/flutter_export_environment.sh b/macos/Flutter/ephemeral/flutter_export_environment.sh index 9e9e935..edde0b5 100644 --- a/macos/Flutter/ephemeral/flutter_export_environment.sh +++ b/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -4,8 +4,8 @@ export "FLUTTER_ROOT=E:\dev\flutter" export "FLUTTER_APPLICATION_PATH=E:\dev\weechat" export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "FLUTTER_BUILD_DIR=build" -export "FLUTTER_BUILD_NAME=1.24.10" -export "FLUTTER_BUILD_NUMBER=16" +export "FLUTTER_BUILD_NAME=1.24.12" +export "FLUTTER_BUILD_NUMBER=18" export "DART_OBFUSCATION=false" export "TRACK_WIDGET_CREATION=true" export "TREE_SHAKE_ICONS=false"