diff --git a/lib/src/view/tournament/tournament_screen.dart b/lib/src/view/tournament/tournament_screen.dart index 60335e36c..74747e578 100644 --- a/lib/src/view/tournament/tournament_screen.dart +++ b/lib/src/view/tournament/tournament_screen.dart @@ -4,6 +4,7 @@ import 'dart:math'; import 'package:dartchess/dartchess.dart' hide File; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_riverpod/experimental/mutation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; @@ -48,6 +49,7 @@ import 'package:lichess_mobile/src/widgets/side_indicator.dart'; import 'package:lichess_mobile/src/widgets/user.dart'; import 'package:path_provider/path_provider.dart' show getTemporaryDirectory; import 'package:share_plus/share_plus.dart'; +import 'package:url_launcher/url_launcher.dart'; class TournamentScreen extends ConsumerStatefulWidget { const TournamentScreen({required this.id}); @@ -215,6 +217,11 @@ class _Body extends ConsumerWidget { ), ), ], + if (state.tournament.description != null && + state.tournament.description!.isNotEmpty) ...[ + const SizedBox(height: 10), + _ExpandableDescription(description: state.tournament.description!), + ], ], ), ), @@ -445,6 +452,37 @@ class _TournamentHelp extends StatelessWidget { } } +class _ExpandableDescription extends ConsumerWidget { + const _ExpandableDescription({required this.description}); + + final String description; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return ExpansionTile( + leading: const Icon(Icons.info_outline), + title: Text(context.l10n.description), + tilePadding: EdgeInsets.zero, + splashColor: Colors.transparent, + shape: LinearBorder.none, + collapsedShape: LinearBorder.none, + expandedCrossAxisAlignment: .start, + expandedAlignment: .centerLeft, + children: [ + MarkdownBody( + data: description, + softLineBreak: true, + onTapLink: (text, url, title) { + if (url != null) { + launchUrl(Uri.parse(url)); + } + }, + ), + ], + ); + } +} + class _TeamStanding extends ConsumerWidget { const _TeamStanding(this.state); diff --git a/test/view/tournament/tournament_screen_test.dart b/test/view/tournament/tournament_screen_test.dart index 0f638d958..be4a128fa 100644 --- a/test/view/tournament/tournament_screen_test.dart +++ b/test/view/tournament/tournament_screen_test.dart @@ -148,6 +148,7 @@ String makeTournamentJson({ "minRatedGames": { "nb": 20 }, + "description": "This is a test tournament. Have fun playing!", "chat": { "lines": [], "writeable": true @@ -377,6 +378,15 @@ void main() { expect(find.text('>= 20 Blitz rated games'), findsOneWidget); expect(find.text('Rated <= 1300 in Blitz for the last week'), findsOneWidget); + // Description should be hidden by default, but expandable + expect(find.text('Description'), findsOneWidget); + expect(find.text('This is a test tournament. Have fun playing!'), findsNothing); + await tester.tap(find.text('Description')); + await tester.pump(); + expect(find.text('This is a test tournament. Have fun playing!'), findsOneWidget); + await tester.tap(find.text('Description')); + await tester.pump(); + expect(find.text('This is a test tournament. Have fun playing!'), findsNothing); for (var i = 0; i < 10; i++) { expect(find.text('player$i'), findsOneWidget);