Scale two bullet columns independently

A two-bullet-column slide sized both columns with the smaller of the two fit
scales, so a sparse column (e.g. 8 items) was shrunk to a crowded one's size
(e.g. 19 items), leaving the text tiny with empty space below it.

Each column now scales to fill its own height; the column headings keep a
shared size so the layout stays tidy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Brenno de Winter 2026-06-08 22:30:46 +02:00
parent 839474fa19
commit 196cd8adb1
3 changed files with 32 additions and 3 deletions

View file

@ -47,6 +47,8 @@ and the project aims to follow [Semantic Versioning](https://semver.org/).
separate from the slide title.
- Slide text auto-sizing now measures with the deck's own font, so text grows to
use the available space more accurately instead of staying smaller than needed.
- The two bullet columns now scale **independently**, so a column with few items
is no longer shrunk down to the size of a crowded one beside it.
- Slide transitions in the presenter no longer flash a black frame (neighbour
images are precached and `gaplessPlayback` is enabled) — important for
recording.

View file

@ -1050,7 +1050,6 @@ class _TwoBulletsPreview extends StatelessWidget {
font: font,
maxScale: _kBulletsMaxScale,
);
final scale = leftScale < rightScale ? leftScale : rightScale;
return Container(
color: _hexColor(profile.slideBackgroundColor),
@ -1089,6 +1088,8 @@ class _TwoBulletsPreview extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Each column scales to fill its own height, so a sparse
// column is not shrunk down to a crowded one's size.
_bulletColumn(
context,
title: col1Title,
@ -1099,7 +1100,7 @@ class _TwoBulletsPreview extends StatelessWidget {
headingGap: headingGap,
bulletSize: bulletSize,
bulletGap: bulletGap,
scale: scale,
scale: leftScale,
),
SizedBox(width: columnGap),
_bulletColumn(
@ -1112,7 +1113,7 @@ class _TwoBulletsPreview extends StatelessWidget {
headingGap: headingGap,
bulletSize: bulletSize,
bulletGap: bulletGap,
scale: scale,
scale: rightScale,
),
],
),

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:ocideck/models/slide.dart';
import 'package:ocideck/widgets/slides/inline_markdown.dart';
import 'package:ocideck/widgets/slides/slide_preview.dart';
Widget _host(Slide slide) {
@ -58,6 +59,31 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('two-bullet columns scale independently (sparse stays large)', (
tester,
) async {
final slide = Slide.create(SlideType.twoBullets).copyWith(
bullets: const ['Solo'],
bullets2: List.generate(14, (i) => 'Item $i'),
);
await tester.pumpWidget(_host(slide));
await tester.pump();
double sizeOf(String text) => tester
.widget<InlineMarkdownText>(
find.byWidgetPredicate(
(x) => x is InlineMarkdownText && x.text == text,
),
)
.style
.fontSize!;
// The single-bullet column is not shrunk to the 14-bullet column's size.
expect(sizeOf('Solo'), greaterThan(sizeOf('Item 0') * 1.3));
expect(tester.takeException(), isNull);
});
testWidgets('bullets slide renders an optional subheading below the title', (
tester,
) async {