fix(learn): a tab whose material is in its topics says so in the middle, as an empty tab does
The tab saying that its material is in the studyset's topics stood at the top of the room below the tabs, while an empty tab's message stands in its middle (SliverCentered), so switching between them moved the message up and down (the developer's review, 9 Nov 2026). It stands in the middle too now. Whats-New: A studyset's tab whose material is in its topics now says so in the middle, as empty tabs do. Whats-New-De: Ein Tab eines Lernsets, dessen Material in seinen Themen liegt, sagt das jetzt in der Mitte, wie leere Tabs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
cc7511f060
commit
f47f6b23b5
2 changed files with 65 additions and 56 deletions
|
|
@ -645,6 +645,8 @@ class const _SliverSectionLoading() extends StatelessWidget {
|
|||
/// tabs): that it is in them, each topic holding some with how much,
|
||||
/// everything inside it counted, opening it; with [onBrowse] (flashcards)
|
||||
/// all of them in one list; and, quieter, how to add some here after all.
|
||||
/// In the middle of the room left, as an empty tab says it (the
|
||||
/// developer's review, 9 Nov 2026).
|
||||
class const _SliverInTopics({
|
||||
required final String parentId,
|
||||
required final List<({Studyset topic, int count})> topics,
|
||||
|
|
@ -665,69 +667,67 @@ class const _SliverInTopics({
|
|||
}
|
||||
}
|
||||
|
||||
return SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 24, 16, 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Icon(icon, size: 40, color: muted),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
for (final (index, (:topic, :count)) in topics.indexed) ...[
|
||||
if (index > 0) const Divider(height: 1),
|
||||
ListTile(
|
||||
title: Text(
|
||||
topic.content.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'$count',
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: muted,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(LucideIcons.chevronRight, size: 18, color: muted),
|
||||
],
|
||||
),
|
||||
onTap: () => unawaited(open(topic)),
|
||||
return SliverCentered(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 24, 16, 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Icon(icon, size: 40, color: muted),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
for (final (index, (:topic, :count)) in topics.indexed) ...[
|
||||
if (index > 0) const Divider(height: 1),
|
||||
ListTile(
|
||||
title: Text(
|
||||
topic.content.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
if (onBrowse case final browse?) ...[
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: FilledButton.tonalIcon(
|
||||
onPressed: browse,
|
||||
icon: const Icon(LucideIcons.layoutGrid, size: 18),
|
||||
label: Text(
|
||||
l10n.studysetBrowseAllFlashcards(
|
||||
topics.fold(0, (sum, held) => sum + held.count),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'$count',
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: muted,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(LucideIcons.chevronRight, size: 18, color: muted),
|
||||
],
|
||||
),
|
||||
onTap: () => unawaited(open(topic)),
|
||||
),
|
||||
],
|
||||
if (onBrowse case final browse?) ...[
|
||||
const SizedBox(height: 16),
|
||||
Center(
|
||||
child: FilledButton.tonalIcon(
|
||||
onPressed: browse,
|
||||
icon: const Icon(LucideIcons.layoutGrid, size: 18),
|
||||
label: Text(
|
||||
l10n.studysetBrowseAllFlashcards(
|
||||
topics.fold(0, (sum, held) => sum + held.count),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
hint,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodySmall?.copyWith(color: muted),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
hint,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodySmall?.copyWith(color: muted),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -203,6 +203,15 @@ void main() {
|
|||
|
||||
expect(find.text('The flashcards are in its topics'), findsOneWidget);
|
||||
expect(find.text('No flashcards yet'), findsNothing);
|
||||
// In the middle of the room below the tabs, as an empty tab says it
|
||||
// (the developer's review, 9 Nov 2026).
|
||||
expect(
|
||||
find.ancestor(
|
||||
of: find.text('The flashcards are in its topics'),
|
||||
matching: find.byType(SliverCentered),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
final kana = find.ancestor(
|
||||
of: find.text('Kana').last,
|
||||
matching: find.byType(ListTile),
|
||||
|
|
|
|||
Loading…
Reference in a new issue