lint
This commit is contained in:
@@ -67,6 +67,7 @@ class AttachmentError extends StatelessWidget {
|
|||||||
this.size,
|
this.size,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
/// Size of error
|
||||||
final Size? size;
|
final Size? size;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
|||||||
import 'package:stream_chat_flutter/src/utils.dart';
|
import 'package:stream_chat_flutter/src/utils.dart';
|
||||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/upload_progress_indicator.dart';
|
||||||
|
|
||||||
import '../upload_progress_indicator.dart';
|
// ignore: always_use_package_imports
|
||||||
import 'attachment_widget.dart';
|
import 'attachment_widget.dart';
|
||||||
|
|
||||||
|
/// Widget for displaying file attachments
|
||||||
class FileAttachment extends AttachmentWidget {
|
class FileAttachment extends AttachmentWidget {
|
||||||
/// Constructor for creating a widget when attachment is of type 'file'
|
/// Constructor for creating a widget when attachment is of type 'file'
|
||||||
const FileAttachment({
|
const FileAttachment({
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import '../stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'extension.dart';
|
|
||||||
|
|
||||||
/// Callback to download an attachment asset
|
/// Callback to download an attachment asset
|
||||||
typedef AttachmentDownloader = Future<String> Function(
|
typedef AttachmentDownloader = Future<String> Function(
|
||||||
@@ -17,6 +16,16 @@ typedef AttachmentDownloader = Future<String> Function(
|
|||||||
|
|
||||||
/// Widget that shows the options in the gallery view
|
/// Widget that shows the options in the gallery view
|
||||||
class AttachmentActionsModal extends StatelessWidget {
|
class AttachmentActionsModal extends StatelessWidget {
|
||||||
|
/// Returns a new [AttachmentActionsModal]
|
||||||
|
const AttachmentActionsModal({
|
||||||
|
Key? key,
|
||||||
|
required this.currentIndex,
|
||||||
|
required this.message,
|
||||||
|
this.onShowMessage,
|
||||||
|
this.imageDownloader,
|
||||||
|
this.fileDownloader,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
/// The message containing the attachments
|
/// The message containing the attachments
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
@@ -32,15 +41,6 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
/// Callback to provide download files
|
/// Callback to provide download files
|
||||||
final AttachmentDownloader? fileDownloader;
|
final AttachmentDownloader? fileDownloader;
|
||||||
|
|
||||||
/// Returns a new [AttachmentActionsModal]
|
|
||||||
const AttachmentActionsModal({
|
|
||||||
required this.currentIndex,
|
|
||||||
required this.message,
|
|
||||||
this.onShowMessage,
|
|
||||||
this.imageDownloader,
|
|
||||||
this.fileDownloader,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => GestureDetector(
|
Widget build(BuildContext context) => GestureDetector(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.translucent,
|
||||||
@@ -62,7 +62,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: SizedBox(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@@ -89,6 +89,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
_buildButton(
|
_buildButton(
|
||||||
context,
|
context,
|
||||||
|
// ignore: lines_longer_than_80_chars
|
||||||
'Save ${message.attachments[currentIndex].type == 'video' ? 'Video' : 'Image'}',
|
'Save ${message.attachments[currentIndex].type == 'video' ? 'Video' : 'Image'}',
|
||||||
StreamSvgIcon.iconSave(
|
StreamSvgIcon.iconSave(
|
||||||
size: 24,
|
size: 24,
|
||||||
@@ -203,7 +204,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
icon,
|
icon,
|
||||||
SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
@@ -253,7 +254,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: progress.toProgressIndicatorValue == 1.0
|
: progress.toProgressIndicatorValue == 1.0
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
key: Key('completedIcon'),
|
key: const Key('completedIcon'),
|
||||||
height: 160,
|
height: 160,
|
||||||
width: 160,
|
width: 160,
|
||||||
child: StreamSvgIcon.check(
|
child: StreamSvgIcon.check(
|
||||||
@@ -314,14 +315,13 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _DownloadProgress {
|
class _DownloadProgress {
|
||||||
final int total;
|
|
||||||
final int received;
|
|
||||||
|
|
||||||
const _DownloadProgress(this.total, this.received);
|
const _DownloadProgress(this.total, this.received);
|
||||||
|
|
||||||
factory _DownloadProgress.initial() {
|
factory _DownloadProgress.initial() =>
|
||||||
return _DownloadProgress(double.maxFinite.toInt(), 0);
|
_DownloadProgress(double.maxFinite.toInt(), 0);
|
||||||
}
|
|
||||||
|
final int total;
|
||||||
|
final int received;
|
||||||
|
|
||||||
double get toProgressIndicatorValue => received / total;
|
double get toProgressIndicatorValue => received / total;
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ class ChannelImage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
child = ClipRRect(
|
child = ClipRRect(
|
||||||
key: Key('selectedImage'),
|
key: const Key('selectedImage'),
|
||||||
borderRadius: (borderRadius ??
|
borderRadius: (borderRadius ??
|
||||||
StreamChatTheme.of(context)
|
StreamChatTheme.of(context)
|
||||||
.ownMessageTheme
|
.ownMessageTheme
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'connection_status_builder.dart';
|
/// Widget which shows channel info
|
||||||
|
|
||||||
class ChannelInfo extends StatelessWidget {
|
class ChannelInfo extends StatelessWidget {
|
||||||
|
/// Constructor which creates a [ChannelInfo] widget
|
||||||
const ChannelInfo({
|
const ChannelInfo({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
/// This widget is used for showing user tiles for mentions
|
/// This widget is used for showing user tiles for mentions
|
||||||
/// Use [title], [subtitle], [leading], [trailing] for
|
/// Use [title], [subtitle], [leading], [trailing] for
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import 'package:flutter_markdown/flutter_markdown.dart';
|
|||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import '../stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
/// Text widget to display in message
|
/// Text widget to display in message
|
||||||
class MessageText extends StatelessWidget {
|
class MessageText extends StatelessWidget {
|
||||||
/// Constructor for creating a [MessageText] widget
|
/// Constructor for creating a [MessageText] widget
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
import 'user_item.dart';
|
|
||||||
|
|
||||||
/// Callback called when tapping on a user
|
/// Callback called when tapping on a user
|
||||||
typedef UserTapCallback = void Function(User, Widget?);
|
typedef UserTapCallback = void Function(User, Widget?);
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ import 'dart:math';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import '../stream_chat_flutter.dart';
|
/// Launch URL
|
||||||
import 'stream_svg_icon.dart';
|
|
||||||
|
|
||||||
Future<void> launchURL(BuildContext context, String? url) async {
|
Future<void> launchURL(BuildContext context, String? url) async {
|
||||||
if (url != null && await canLaunch(url)) {
|
if (url != null && await canLaunch(url)) {
|
||||||
await launch(url);
|
await launch(url);
|
||||||
@@ -20,6 +19,7 @@ Future<void> launchURL(BuildContext context, String? url) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows confirmation dialog
|
||||||
Future<bool?> showConfirmationDialog(
|
Future<bool?> showConfirmationDialog(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required String title,
|
required String title,
|
||||||
|
|||||||
@@ -60,6 +60,6 @@ class IVideoService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: non_constant_identifier_names
|
|
||||||
/// Get instance of [IVideoService]
|
/// Get instance of [IVideoService]
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
IVideoService get VideoService => IVideoService.instance;
|
IVideoService get VideoService => IVideoService.instance;
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
stream_chat_flutter_core: ^2.0.0-nullsafety.0
|
stream_chat_flutter_core: ^2.0.0-nullsafety.0
|
||||||
photo_view: ^0.11.1
|
|
||||||
rxdart: ^0.26.0
|
rxdart: ^0.26.0
|
||||||
scrollable_positioned_list: ^0.2.0-nullsafety.0
|
scrollable_positioned_list: ^0.2.0-nullsafety.0
|
||||||
jiffy: ^4.1.0
|
jiffy: ^4.1.0
|
||||||
|
photo_view: ^0.11.1
|
||||||
flutter_svg: ^0.22.0
|
flutter_svg: ^0.22.0
|
||||||
flutter_portal: ^0.4.0
|
flutter_portal: ^0.4.0
|
||||||
cached_network_image: ^3.0.0
|
cached_network_image: ^3.0.0
|
||||||
@@ -57,6 +57,6 @@ dev_dependencies:
|
|||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
mocktail: ^0.1.2
|
mocktail: ^0.1.2
|
||||||
pedantic: ^1.11.0
|
|
||||||
golden_toolkit: ^0.9.0
|
golden_toolkit: ^0.9.0
|
||||||
|
pedantic: ^1.11.0
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ class MockAttachmentDownloader extends Mock {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
setUpAll(() {
|
setUpAll(() {
|
||||||
registerFallbackValue(MaterialPageRoute(builder: (context) => SizedBox()));
|
registerFallbackValue(
|
||||||
|
MaterialPageRoute(builder: (context) => const SizedBox()));
|
||||||
registerFallbackValue(Message());
|
registerFallbackValue(Message());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -461,9 +462,9 @@ void main() {
|
|||||||
MaterialApp(
|
MaterialApp(
|
||||||
builder: (context, child) => StreamChat(
|
builder: (context, child) => StreamChat(
|
||||||
client: client,
|
client: client,
|
||||||
child: child!,
|
child: child,
|
||||||
),
|
),
|
||||||
home: Container(
|
home: SizedBox(
|
||||||
child: AttachmentActionsModal(
|
child: AttachmentActionsModal(
|
||||||
fileDownloader: fileDownloader,
|
fileDownloader: fileDownloader,
|
||||||
message: Message(
|
message: Message(
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ void main() {
|
|||||||
child: Center(
|
child: Center(
|
||||||
child: StreamChatTheme(
|
child: StreamChatTheme(
|
||||||
data: StreamChatThemeData.fromTheme(theme),
|
data: StreamChatThemeData.fromTheme(theme),
|
||||||
child: StreamBackButton(),
|
child: const StreamBackButton(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
surfaceSize: Size(100, 100),
|
surfaceSize: const Size(100, 100),
|
||||||
);
|
);
|
||||||
await screenMatchesGolden(tester, 'reaction_bubble_0');
|
await screenMatchesGolden(tester, 'reaction_bubble_0');
|
||||||
},
|
},
|
||||||
@@ -47,7 +47,7 @@ void main() {
|
|||||||
StreamChat(
|
StreamChat(
|
||||||
client: client,
|
client: client,
|
||||||
streamChatThemeData: theme,
|
streamChatThemeData: theme,
|
||||||
child: Container(
|
child: SizedBox(
|
||||||
child: ReactionBubble(
|
child: ReactionBubble(
|
||||||
reactions: [
|
reactions: [
|
||||||
Reaction(
|
Reaction(
|
||||||
@@ -61,7 +61,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
surfaceSize: Size(100, 100),
|
surfaceSize: const Size(100, 100),
|
||||||
);
|
);
|
||||||
await screenMatchesGolden(tester, 'reaction_bubble_like_light');
|
await screenMatchesGolden(tester, 'reaction_bubble_like_light');
|
||||||
},
|
},
|
||||||
@@ -97,7 +97,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
surfaceSize: Size(100, 100),
|
surfaceSize: const Size(100, 100),
|
||||||
);
|
);
|
||||||
await screenMatchesGolden(tester, 'reaction_bubble_like_dark');
|
await screenMatchesGolden(tester, 'reaction_bubble_like_dark');
|
||||||
},
|
},
|
||||||
@@ -141,7 +141,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
surfaceSize: Size(140, 140),
|
surfaceSize: const Size(140, 140),
|
||||||
);
|
);
|
||||||
await screenMatchesGolden(tester, 'reaction_bubble_3_light');
|
await screenMatchesGolden(tester, 'reaction_bubble_3_light');
|
||||||
},
|
},
|
||||||
@@ -185,7 +185,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
surfaceSize: Size(140, 140),
|
surfaceSize: const Size(140, 140),
|
||||||
);
|
);
|
||||||
await screenMatchesGolden(tester, 'reaction_bubble_3_dark');
|
await screenMatchesGolden(tester, 'reaction_bubble_3_dark');
|
||||||
},
|
},
|
||||||
@@ -205,7 +205,7 @@ void main() {
|
|||||||
StreamChat(
|
StreamChat(
|
||||||
client: client,
|
client: client,
|
||||||
streamChatThemeData: StreamChatThemeData.fromTheme(themeData),
|
streamChatThemeData: StreamChatThemeData.fromTheme(themeData),
|
||||||
child: Container(
|
child: SizedBox(
|
||||||
child: ReactionBubble(
|
child: ReactionBubble(
|
||||||
reactions: [
|
reactions: [
|
||||||
Reaction(
|
Reaction(
|
||||||
@@ -230,7 +230,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
surfaceSize: Size(200, 200),
|
surfaceSize: const Size(200, 200),
|
||||||
);
|
);
|
||||||
|
|
||||||
await screenMatchesGolden(tester, 'reaction_bubble_2');
|
await screenMatchesGolden(tester, 'reaction_bubble_2');
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class SimpleFrame extends StatelessWidget {
|
class SimpleFrame extends StatelessWidget {
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
const SimpleFrame({Key? key, required this.child}) : super(key: key);
|
const SimpleFrame({Key? key, required this.child}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) => Container(
|
||||||
return Container(
|
padding: const EdgeInsets.all(4),
|
||||||
padding: const EdgeInsets.all(4),
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
color: const Color(0xFFFFFFFF),
|
||||||
color: const Color(0xFFFFFFFF),
|
border: Border.all(color: const Color(0xFF9E9E9E)),
|
||||||
border: Border.all(color: const Color(0xFF9E9E9E)),
|
),
|
||||||
),
|
child: child,
|
||||||
child: child,
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
surfaceSize: Size.square(200),
|
surfaceSize: const Size.square(200),
|
||||||
);
|
);
|
||||||
|
|
||||||
await screenMatchesGolden(tester, 'system_message_light');
|
await screenMatchesGolden(tester, 'system_message_light');
|
||||||
@@ -153,7 +153,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
surfaceSize: Size.square(200),
|
surfaceSize: const Size.square(200),
|
||||||
);
|
);
|
||||||
|
|
||||||
await screenMatchesGolden(tester, 'system_message_dark');
|
await screenMatchesGolden(tester, 'system_message_dark');
|
||||||
|
|||||||
@@ -117,13 +117,13 @@ void main() {
|
|||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: ThreadHeader(
|
body: ThreadHeader(
|
||||||
parent: Message(),
|
parent: Message(),
|
||||||
subtitle: Text('subtitle'),
|
subtitle: const Text('subtitle'),
|
||||||
leading: Text('leading'),
|
leading: const Text('leading'),
|
||||||
title: Text('title'),
|
title: const Text('title'),
|
||||||
onTitleTap: () {
|
onTitleTap: () {
|
||||||
tapped = true;
|
tapped = true;
|
||||||
},
|
},
|
||||||
actions: [
|
actions: const [
|
||||||
Text('action'),
|
Text('action'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -67,14 +67,14 @@ void main() {
|
|||||||
client: client,
|
client: client,
|
||||||
child: StreamChannel(
|
child: StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: Scaffold(
|
child: const Scaffold(
|
||||||
body: TypingIndicator(),
|
body: TypingIndicator(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
expect(find.byKey(Key('typings')), findsOneWidget);
|
expect(find.byKey(const Key('typings')), findsOneWidget);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ void main() {
|
|||||||
client: client,
|
client: client,
|
||||||
child: StreamChannel(
|
child: StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: Scaffold(
|
child: const Scaffold(
|
||||||
body: UnreadIndicator(),
|
body: UnreadIndicator(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user