Skip to content

Update book details page#4

Merged
Eoic merged 4 commits intomasterfrom
feature/book-details
Feb 6, 2026
Merged

Update book details page#4
Eoic merged 4 commits intomasterfrom
feature/book-details

Conversation

@Eoic
Copy link
Copy Markdown
Member

@Eoic Eoic commented Feb 6, 2026

Add missing form fields according to the book data model, update form layout, and show missing info in book details page.

@Eoic Eoic self-assigned this Feb 6, 2026
Copilot AI review requested due to automatic review settings February 6, 2026 15:40
@Eoic Eoic merged commit 7e01324 into master Feb 6, 2026
5 checks passed
@Eoic Eoic deleted the feature/book-details branch February 6, 2026 15:41
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Flutter client’s book details and edit experiences to better reflect the Book data model (publisher/publication date/ISBN variants/language/series/rating/physical lending info), and refreshes desktop layouts to match the book details page styling.

Changes:

  • Expanded book details display (BookInfoGrid, BookHeader) to show subtitle, combined authors, and additional metadata fields.
  • Extended the edit form (BookEditPage + BookEditProvider) with rating, publication date picker, series fields, and physical/lending fields.
  • Updated Book model fields/JSON mapping (e.g., cover_image_url, series name/number types).

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
client/lib/widgets/book_edit/cover_image_picker.dart Tweaks cover sizing/spacing in the cover picker UI.
client/lib/widgets/book_details/book_info_grid.dart Displays additional metadata (publisher/date/ISBN/language/series/rating/status/location/lending).
client/lib/widgets/book_details/book_header.dart Shows subtitle and uses combined author display (allAuthors).
client/lib/providers/book_edit_provider.dart Adds update methods + parses/sets publicationDate from fetched metadata.
client/lib/pages/book_edit_page.dart Adds new edit fields (date picker, rating, series, physical/lending) and updates desktop scaffold layout.
client/lib/pages/book_details_page.dart Aligns desktop header styling with shared app bar sizing/typography.
client/lib/models/book.dart Adds series name, changes series number to double?, and maps cover URL to cover_image_url in JSON.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 111 to +113
final String? seriesId;
final int? seriesNumber;
final String? seriesName;
final double? seriesNumber;
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seriesNumber was changed from int? to double?, but there are existing Book(...) constructions (e.g. in client/lib/data/sample_data.dart) that pass integer literals like seriesNumber: 1, which will no longer type-check and will break the build. Update those call sites to pass doubles (e.g. 1.0) or cast/convert appropriately, and consider whether 0 is still a valid sentinel value now that this is a double?.

Copilot uses AI. Check for mistakes.
Comment on lines +564 to +568
final picked = await showDatePicker(
context: context,
initialDate: currentValue ?? DateTime.now(),
firstDate: DateTime(1000),
lastDate: DateTime.now().add(const Duration(days: 365)),
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

showDatePicker requires initialDate to be within [firstDate, lastDate]. With lastDate capped at DateTime.now().add(Duration(days: 365)), opening the picker will throw if currentValue is later than that (e.g. a pre-release publication date). Clamp initialDate into range and/or ensure lastDate is at least currentValue when non-null.

Suggested change
final picked = await showDatePicker(
context: context,
initialDate: currentValue ?? DateTime.now(),
firstDate: DateTime(1000),
lastDate: DateTime.now().add(const Duration(days: 365)),
final now = DateTime.now();
final firstDate = DateTime(1000);
final defaultLastDate = now.add(const Duration(days: 365));
// Ensure the lastDate is at least as late as the current value, if any.
final effectiveLastDate = currentValue != null && currentValue.isAfter(defaultLastDate)
? currentValue
: defaultLastDate;
// Choose an initial date and clamp it into [firstDate, effectiveLastDate].
DateTime initialDate = currentValue ?? now;
if (initialDate.isBefore(firstDate)) {
initialDate = firstDate;
} else if (initialDate.isAfter(effectiveLastDate)) {
initialDate = effectiveLastDate;
}
final picked = await showDatePicker(
context: context,
initialDate: initialDate,
firstDate: firstDate,
lastDate: effectiveLastDate,

Copilot uses AI. Check for mistakes.
Comment on lines +616 to +628
return GestureDetector(
onTap: () {
_provider.updateRating(starValue == rating ? null : starValue);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: Icon(
isSelected ? Icons.star_rounded : Icons.star_outline_rounded,
color: isSelected
? colorScheme.primary
: colorScheme.onSurfaceVariant,
size: 28,
),
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rating control uses GestureDetector + Icon, which isn’t focusable and doesn’t provide an accessible label/tooltip for screen readers or keyboard users. Prefer IconButton/InkResponse with tooltip/semanticLabel (or wrap with Semantics) so the stars are discoverable and operable via accessibility services.

Suggested change
return GestureDetector(
onTap: () {
_provider.updateRating(starValue == rating ? null : starValue);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: Icon(
isSelected ? Icons.star_rounded : Icons.star_outline_rounded,
color: isSelected
? colorScheme.primary
: colorScheme.onSurfaceVariant,
size: 28,
),
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: IconButton(
onPressed: () {
_provider.updateRating(starValue == rating ? null : starValue);
},
icon: Icon(
isSelected ? Icons.star_rounded : Icons.star_outline_rounded,
color: isSelected
? colorScheme.primary
: colorScheme.onSurfaceVariant,
size: 28,
),
padding: EdgeInsets.zero,
tooltip: starValue == rating
? 'Clear rating'
: 'Set rating to $starValue ${starValue == 1 ? 'star' : 'stars'}',

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +96
String _formatSeriesNumber(double number) {
return number == number.roundToDouble()
? number.toInt().toString()
: number.toString();
}
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_formatSeriesNumber is now duplicated here and in BookInfoGrid. To avoid formatting drift, consider moving this into a shared util (or a Book/extension helper) and reusing it from both places.

Copilot uses AI. Check for mistakes.
),
),
SizedBox(width: widget.isDesktop ? Spacing.xs : Spacing.md),
SizedBox(width: widget.isDesktop ? Spacing.md : Spacing.md),
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conditional is redundant (widget.isDesktop ? Spacing.md : Spacing.md). Consider simplifying to a single value (and making the SizedBox const if possible) to reduce noise and keep layout intent clear.

Suggested change
SizedBox(width: widget.isDesktop ? Spacing.md : Spacing.md),
const SizedBox(width: Spacing.md),

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants