Skip to content

feat: better lists#34

Merged
mikebarkmin merged 3 commits intomainfrom
better-lists
Apr 28, 2026
Merged

feat: better lists#34
mikebarkmin merged 3 commits intomainfrom
better-lists

Conversation

@mikebarkmin
Copy link
Copy Markdown
Member

No description provided.

@mikebarkmin
Copy link
Copy Markdown
Member Author

/build android

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

Adds richer checklist/list functionality across the app by introducing global lists (no group), multi-student linking per item, and improved list/item creation & editing UX, backed by Drift schema/migration updates.

Changes:

  • Make ListsTable.groupId nullable to support global lists, and update list creation flows to support optional “populate items from group students”.
  • Add studentIdsJson to list items + helpers/UI to link an item to multiple students (including across groups for global lists).
  • Add/adjust platform plugin registrants and expand i18n strings; add repository tests for the new list behaviors.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
windows/flutter/generated_plugins.cmake Registers local_auth_windows plugin for Windows builds.
windows/flutter/generated_plugin_registrant.cc Registers local_auth_windows plugin with Flutter registrant.
macos/Flutter/GeneratedPluginRegistrant.swift Registers local_auth_darwin and package_info_plus on macOS.
lib/core/database/tables/lists_table.dart Makes groupId nullable to support global lists.
lib/core/database/tables/list_items_table.dart Adds studentIdsJson column for multi-student links.
lib/core/database/app_database.dart Bumps schema version and migrates lists/items schema, backfills studentIdsJson.
lib/core/database/app_database.g.dart Regenerated Drift code reflecting nullable groupId and studentIdsJson.
lib/features/lists/list_repository.dart Adds createListWithOptions, multi-student item insert/update, and validation.
lib/features/lists/list_item_links.dart New helpers to normalize/encode/decode linked student IDs for items.
lib/features/lists/list_editor.dart New list editor dialog (scope + “populate from group students”).
lib/features/lists/list_item_editor.dart New item editor bottom sheet with student-linking flow.
lib/shared/widgets/student_selection_sheet.dart New reusable student selection sheet with search/sections/select-all.
lib/features/lists/lists_screen.dart Updates list creation flow and shows a “Global list” chip for global lists.
lib/features/lists/list_detail_screen.dart Updates list detail UI to show linked students, add/edit item flow.
lib/features/groups/group_detail_screen.dart Updates group list creation to use the new list editor options.
assets/translations/en.json Adds/updates strings for list scope, global list, selection actions.
assets/translations/de.json Adds/updates German strings for list scope, global list, selection actions.
test/list_repository_test.dart Adds tests for global lists, multi-student linking, validation, and population.

Comment on lines +291 to 294
subtitle: group == null
? const _GlobalListChip()
: _ListGroupChip(group: group),
trailing: PopupMenuButton<_GlobalListAction>(
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

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

Checklist.groupId is now nullable, but the group used here is obtained via a Map<int, Group> lookup with list.groupId. That lookup won’t type-check / compile unless the null case is handled (e.g., only index the map when list.groupId != null). Please adjust the lookup so global lists don’t pass a nullable key into a non-nullable map index.

Copilot uses AI. Check for mistakes.
void initState() {
super.initState();
_labelController = TextEditingController(text: widget.initialLabel);
_studentIds = {...?widget.initialStudentIds};
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

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

_studentIds is initialized directly from initialStudentIds. If an item references a student that was deleted (or otherwise not present in widget.students), saving without reopening the selection sheet can pass invalid IDs to the repository and trigger an exception. Consider intersecting the initial IDs with the provided students list (and/or dropping unknown IDs) during initialization so the editor can always save safely.

Suggested change
_studentIds = {...?widget.initialStudentIds};
final validStudentIds = {
for (final student in widget.students) student.id,
};
_studentIds = {
for (final studentId in widget.initialStudentIds ?? const <int>[])
if (validStudentIds.contains(studentId)) studentId,
};

Copilot uses AI. Check for mistakes.
void initState() {
super.initState();
_searchController = TextEditingController();
_selectedStudentIds = {...widget.selectedStudentIds};
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

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

_selectedStudentIds is seeded from the caller-provided set without filtering. If that set contains IDs not present in students (e.g., a student was deleted), those IDs will be preserved and returned on Save. Filter the initial selection to the IDs that actually exist in widget.students to avoid returning stale/invalid IDs.

Suggested change
_selectedStudentIds = {...widget.selectedStudentIds};
final validStudentIds = widget.students.map((student) => student.id).toSet();
_selectedStudentIds =
widget.selectedStudentIds.intersection(validStudentIds);

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +76

return SizedBox(
height: MediaQuery.sizeOf(context).height * 0.8,
child: Padding(
padding: const EdgeInsets.fromLTRB(24, 8, 24, 24),
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

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

This bottom sheet contains a searchable TextField, but the layout uses a fixed 80% height and a constant bottom padding. When the keyboard opens, the action row at the bottom can be obscured. Consider adding bottom padding based on MediaQuery.viewInsetsOf(context).bottom (similar to other sheets in the app) or using a scrollable sheet approach so the buttons remain accessible while typing.

Suggested change
return SizedBox(
height: MediaQuery.sizeOf(context).height * 0.8,
child: Padding(
padding: const EdgeInsets.fromLTRB(24, 8, 24, 24),
final keyboardInset = MediaQuery.viewInsetsOf(context).bottom;
return SizedBox(
height: MediaQuery.sizeOf(context).height * 0.8,
child: AnimatedPadding(
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
padding: EdgeInsets.fromLTRB(24, 8, 24, 24 + keyboardInset),

Copilot uses AI. Check for mistakes.
@mikebarkmin
Copy link
Copy Markdown
Member Author

@copilot fix the issues from the review

- Fix nullable groupId map lookup in lists_screen.dart using local variable
- Filter initial student IDs to valid ones in list_item_editor.dart
- Filter initial selected student IDs to valid ones in student_selection_sheet.dart
- Add keyboard inset padding with AnimatedPadding in student_selection_sheet.dart

Agent-Logs-Url: https://github.com/openpatch/classi/sessions/21be2dc8-b61a-400e-92ad-435465384819

Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown

📦 Android build ready

Download APK

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 28, 2026

@copilot fix the issues from the review

Fixed all four review issues in commit 947aafe:

  1. lists_screen.dart – Used a local groupId variable to enable Dart's smart-cast before indexing the Map<int, Group>, so null groupId properly yields null instead of a type error.
  2. list_item_editor.dartinitState now filters initialStudentIds against the set of valid student IDs, dropping any stale/deleted references.
  3. student_selection_sheet.dart (line 60)_selectedStudentIds is now initialized via intersection(validStudentIds) to strip any IDs not present in widget.students.
  4. student_selection_sheet.dart (lines 72–76) – Replaced Padding with AnimatedPadding that adds MediaQuery.viewInsetsOf(context).bottom to the bottom inset, so the Save/Cancel buttons stay visible when the keyboard is open.

@mikebarkmin
Copy link
Copy Markdown
Member Author

/build android

@github-actions
Copy link
Copy Markdown

📦 Android build ready

Download APK

@mikebarkmin
Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

# Conflicts:
#	assets/translations/de.json
#	assets/translations/en.json

Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 28, 2026

@copilot resolve the merge conflicts in this pull request

Resolved in commit 1b5f926. The only conflicts were in the translation JSON files — both branches had modified "empty_lists". Kept our generic wording ("No lists yet." / "Es gibt noch keine Listen.") since the PR introduces global lists (not tied to a group), and added the new "empty_student_lists" key from main that the student detail screen needs.

@mikebarkmin mikebarkmin merged commit 494d188 into main Apr 28, 2026
@mikebarkmin mikebarkmin deleted the better-lists branch April 28, 2026 12:55
Copilot stopped work on behalf of mikebarkmin due to an error April 28, 2026 12:56
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.

3 participants