diff --git a/packages/stream_chat_flutter/example/lib/debug/actions/ban_user.dart b/packages/stream_chat_flutter/example/lib/debug/actions/ban_user.dart new file mode 100644 index 00000000..62cec6dc --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/actions/ban_user.dart @@ -0,0 +1,41 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'package:stream_chat_flutter_example/debug/error_dialog.dart'; + +class DebugBanUser extends StatelessWidget { + const DebugBanUser({ + super.key, + required this.client, + }); + + final StreamChatClient client; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8), + child: TextField( + decoration: const InputDecoration( + labelText: 'Ban User', + hintText: 'User Id', + isDense: true, + border: OutlineInputBorder(), + ), + onSubmitted: (value) async { + final userId = value.trim(); + try { + debugPrint('[banUser] userId: $userId'); + final result = await client.banUser(userId); + debugPrint('[banUser] completed: $result'); + } catch (e) { + debugPrint('[banUser] failed: $e'); + showErrorDialog(context, e, 'Ban User'); + } + }, + ), + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/debug/actions/mute_user.dart b/packages/stream_chat_flutter/example/lib/debug/actions/mute_user.dart new file mode 100644 index 00000000..5253669e --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/actions/mute_user.dart @@ -0,0 +1,41 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'package:stream_chat_flutter_example/debug/error_dialog.dart'; + +class DebugMuteUser extends StatelessWidget { + const DebugMuteUser({ + super.key, + required this.client, + }); + + final StreamChatClient client; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8), + child: TextField( + decoration: const InputDecoration( + labelText: 'Mute User', + hintText: 'User Id', + isDense: true, + border: OutlineInputBorder(), + ), + onSubmitted: (value) async { + final userId = value.trim(); + try { + debugPrint('[muteUser] userId: $userId'); + final result = await client.muteUser(userId); + debugPrint('[muteUser] completed: $result'); + } catch (e) { + debugPrint('[muteUser] failed: $e'); + showErrorDialog(context, e, 'Mute User'); + } + }, + ), + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/debug/actions/remove_shadow_ban.dart b/packages/stream_chat_flutter/example/lib/debug/actions/remove_shadow_ban.dart new file mode 100644 index 00000000..5ab29797 --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/actions/remove_shadow_ban.dart @@ -0,0 +1,41 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'package:stream_chat_flutter_example/debug/error_dialog.dart'; + +class DebugRemoveShadowBan extends StatelessWidget { + const DebugRemoveShadowBan({ + super.key, + required this.client, + }); + + final StreamChatClient client; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8), + child: TextField( + decoration: const InputDecoration( + labelText: 'Remove Shadow Ban', + hintText: 'User Id', + isDense: true, + border: OutlineInputBorder(), + ), + onSubmitted: (value) async { + final userId = value.trim(); + try { + debugPrint('[removeShadowBan] userId: $userId'); + final result = await client.removeShadowBan(userId); + debugPrint('[removeShadowBan] result: $result'); + } catch (e) { + debugPrint('[removeShadowBan] failed: $e'); + showErrorDialog(context, e, 'Remove Shadow Ban'); + } + }, + ), + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/debug/actions/shadow_ban.dart b/packages/stream_chat_flutter/example/lib/debug/actions/shadow_ban.dart new file mode 100644 index 00000000..9e5c5553 --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/actions/shadow_ban.dart @@ -0,0 +1,41 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'package:stream_chat_flutter_example/debug/error_dialog.dart'; + +class DebugShadowBan extends StatelessWidget { + const DebugShadowBan({ + super.key, + required this.client, + }); + + final StreamChatClient client; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8), + child: TextField( + decoration: const InputDecoration( + labelText: 'Shadow Ban', + hintText: 'User Id', + isDense: true, + border: OutlineInputBorder(), + ), + onSubmitted: (value) async { + final userId = value.trim(); + try { + debugPrint('[shadowBan] userId: $userId'); + final result = await client.shadowBan(userId); + debugPrint('[shadowBan] completed: $result'); + } catch (e) { + debugPrint('[shadowBan] failed: $e'); + showErrorDialog(context, e, 'Shadow Ban'); + } + }, + ), + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/debug/actions/unban_user.dart b/packages/stream_chat_flutter/example/lib/debug/actions/unban_user.dart new file mode 100644 index 00000000..5a9ac755 --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/actions/unban_user.dart @@ -0,0 +1,41 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'package:stream_chat_flutter_example/debug/error_dialog.dart'; + +class DebugUnbanUser extends StatelessWidget { + const DebugUnbanUser({ + super.key, + required this.client, + }); + + final StreamChatClient client; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8), + child: TextField( + decoration: const InputDecoration( + labelText: 'Unban User', + hintText: 'User Id', + isDense: true, + border: OutlineInputBorder(), + ), + onSubmitted: (value) async { + final userId = value.trim(); + try { + debugPrint('[unbanUser] userId: $userId'); + final result = await client.unbanUser(userId); + debugPrint('[unbanUser] completed: $result'); + } catch (e) { + debugPrint('[unbanUser] failed: $e'); + showErrorDialog(context, e, 'Unban User'); + } + }, + ), + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/debug/actions/unmute_user.dart b/packages/stream_chat_flutter/example/lib/debug/actions/unmute_user.dart new file mode 100644 index 00000000..359ae341 --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/actions/unmute_user.dart @@ -0,0 +1,41 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +import 'package:stream_chat_flutter_example/debug/error_dialog.dart'; + +class DebugUnmuteUser extends StatelessWidget { + const DebugUnmuteUser({ + super.key, + required this.client, + }); + + final StreamChatClient client; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8), + child: TextField( + decoration: const InputDecoration( + labelText: 'Unmute User', + hintText: 'User Id', + isDense: true, + border: OutlineInputBorder(), + ), + onSubmitted: (value) async { + final userId = value.trim(); + try { + debugPrint('[unmuteUser] userId: $userId'); + final result = await client.unmuteUser(userId); + debugPrint('[unmuteUser] completed: $result'); + } catch (e) { + debugPrint('[unmuteUser] failed: $e'); + showErrorDialog(context, e, 'Unmute User'); + } + }, + ), + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/debug/channel_page.dart b/packages/stream_chat_flutter/example/lib/debug/channel_page.dart new file mode 100644 index 00000000..b5e93cf5 --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/channel_page.dart @@ -0,0 +1,126 @@ +// ignore_for_file: public_member_api_docs + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_example/debug/actions/ban_user.dart'; +import 'package:stream_chat_flutter_example/debug/actions/mute_user.dart'; +import 'package:stream_chat_flutter_example/debug/actions/remove_shadow_ban.dart'; +import 'package:stream_chat_flutter_example/debug/actions/shadow_ban.dart'; +import 'package:stream_chat_flutter_example/debug/actions/unban_user.dart'; +import 'package:stream_chat_flutter_example/debug/actions/unmute_user.dart'; +import 'package:stream_chat_flutter_example/debug/members.dart'; +import 'package:stream_chat_flutter_example/debug/mutes.dart'; + +class DebugChannelPage extends StatefulWidget { + const DebugChannelPage({super.key}); + + @override + State createState() { + return _DebugChannelPageState(); + } +} + +class _DebugChannelPageState extends State { + late final Channel _channel = StreamChannel.of(context).channel; + + StreamSubscription? _channelSubscription; + StreamSubscription? _ownUserSubscription; + + ChannelState? _channelState; + OwnUser? _ownUser; + + @override + void initState() { + super.initState(); + _channelSubscription = _channel.state!.channelStateStream.listen((state) { + setState(() => _channelState = state); + }); + _ownUserSubscription = + _channel.client.state.currentUserStream.listen((ownUser) { + setState(() => _ownUser = ownUser); + }); + } + + @override + void dispose() { + super.dispose(); + _channelSubscription?.cancel(); + _ownUserSubscription?.cancel(); + } + + @override + Widget build(BuildContext context) { + final members = + _channelState?.members ?? _channel.state?.members ?? const []; + final mutes = + _ownUser?.mutes ?? _channel.client.state.currentUser?.mutes ?? const []; + //SingleChildScrollView + return Scaffold( + appBar: AppBar( + title: Text(_channel.name ?? _channel.cid ?? '?'), + ), + body: SingleChildScrollView( + padding: const EdgeInsets.only(bottom: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + DebugMe(client: _channel.client), + DebugMembers(members: members), + const SizedBox(height: 8), + DebugMutes(mutes: mutes), + const SizedBox(height: 16), + DebugMuteUser(client: _channel.client), + const SizedBox(height: 8), + DebugUnmuteUser(client: _channel.client), + const SizedBox(height: 8), + DebugBanUser(client: _channel.client), + const SizedBox(height: 8), + DebugUnbanUser(client: _channel.client), + const SizedBox(height: 8), + DebugShadowBan(client: _channel.client), + const SizedBox(height: 8), + DebugRemoveShadowBan(client: _channel.client), + ], + ), + ), + ); + } +} + +class DebugMe extends StatelessWidget { + const DebugMe({ + super.key, + required this.client, + }); + + final StreamChatClient client; + + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 12), + child: Row( + children: [ + const Text( + 'Me: ', + style: TextStyle( + color: Colors.red, + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + Text( + client.state.currentUser?.id ?? '?', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/debug/error_dialog.dart b/packages/stream_chat_flutter/example/lib/debug/error_dialog.dart new file mode 100644 index 00000000..6e7fb750 --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/error_dialog.dart @@ -0,0 +1,28 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; + +Future showErrorDialog( + BuildContext context, + Object e, + String operation, +) async { + return showDialog( + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: Text('$operation Failed'), + content: SingleChildScrollView(child: Text('$e')), + actions: [ + TextButton( + child: const Text('Close'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); +} diff --git a/packages/stream_chat_flutter/example/lib/debug/members.dart b/packages/stream_chat_flutter/example/lib/debug/members.dart new file mode 100644 index 00000000..d0214e00 --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/members.dart @@ -0,0 +1,57 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class DebugMembers extends StatelessWidget { + const DebugMembers({ + super.key, + required this.members, + }); + + final List members; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + color: Colors.orange, + padding: const EdgeInsets.all(8), + child: const Text('Members'), + ), + Container( + color: Colors.orange, + height: 100, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: members.length, + itemBuilder: (BuildContext context, int index) { + final member = members[index]; + return Padding( + padding: const EdgeInsets.all(8), + child: ColoredBox( + color: Colors.yellow, + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text(member.user?.name ?? '?'), + Text('ID: ${member.user?.id ?? '?'}'), + Text('Ban: ${member.banned ? 'T' : 'F'}'), + Text('ShBan: ${member.shadowBanned ? 'T' : 'F'}'), + ], + ), + ), + ), + ); + }, + ), + ), + ], + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/debug/mutes.dart b/packages/stream_chat_flutter/example/lib/debug/mutes.dart new file mode 100644 index 00000000..fe54b06e --- /dev/null +++ b/packages/stream_chat_flutter/example/lib/debug/mutes.dart @@ -0,0 +1,55 @@ +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class DebugMutes extends StatelessWidget { + const DebugMutes({super.key, required this.mutes}); + + final List mutes; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + color: Colors.lightBlueAccent, + padding: const EdgeInsets.all(8), + child: const Text('Mutes'), + ), + Container( + color: Colors.lightBlueAccent, + height: 80, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: mutes.length, + itemBuilder: (BuildContext context, int index) { + final mute = mutes[index]; + return Padding( + padding: const EdgeInsets.all(8), + child: ColoredBox( + color: Colors.yellow, + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text('By: ${mute.user.name} (${mute.user.id})'), + Text( + 'Who: ${mute.target.name} (${mute.target.id})', + ), + Text('Exp: ${mute.expires}'), + ], + ), + ), + ), + ); + }, + ), + ), + ], + ); + } +} diff --git a/packages/stream_chat_flutter/example/lib/main.dart b/packages/stream_chat_flutter/example/lib/main.dart index e4f291fe..f0acc0fa 100644 --- a/packages/stream_chat_flutter/example/lib/main.dart +++ b/packages/stream_chat_flutter/example/lib/main.dart @@ -1,8 +1,11 @@ // ignore_for_file: public_member_api_docs +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'package:stream_chat_flutter_example/debug/channel_page.dart'; import 'package:stream_chat_localizations/stream_chat_localizations.dart'; Future main() async { @@ -255,6 +258,19 @@ class _ChannelPageState extends State { widget.onBackPressed!(context); } : null, + onImageTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return StreamChannel( + channel: StreamChannel.of(context).channel, + child: const DebugChannelPage(), + ); + }, + ), + ); + }, showBackButton: widget.showBackButton, ), body: Column(