refactor(app): FeedbackPerson moves into core as PublicPerson

A second feature needs it: discussions name their writers as reports and
suggestions do, by what their public profile shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-15 23:52:31 +02:00
commit 25237b8011
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
7 changed files with 29 additions and 21 deletions

View file

@ -0,0 +1,15 @@
import 'package:equatable/equatable.dart';
/// Someone writing in public (reports, suggestions, discussions), as their
/// public profile shows them.
final class const PublicPerson({
required final String handle,
final String displayName = '',
final String? avatarUrl,
}) with Equatable {
/// How they are named: their display name, else their handle.
String get name => displayName.isEmpty ? '@$handle' : displayName;
@override
List<Object?> get props => [handle, displayName, avatarUrl];
}

View file

@ -2,6 +2,7 @@ import 'dart:developer';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:halkyon_learn_flutter/src/core/profile/public_person.dart';
import 'package:halkyon_learn_flutter/src/feature/feedback/data/feedback_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/feedback/model/feedback.dart';
@ -198,7 +199,7 @@ final class const FeedbackListEventAccepted(final FeedbackThread thread)
}
/// The author keeps [person] from writing on their studysets.
final class const FeedbackListEventBlocked(final FeedbackPerson person)
final class const FeedbackListEventBlocked(final PublicPerson person)
extends FeedbackListEvent {
@override
List<Object?> get props => [person];

View file

@ -5,6 +5,7 @@ import 'package:crypto/crypto.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/core/profile/public_person.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
@ -244,7 +245,7 @@ class FeedbackRepository(
_server.markSeen(thread.threadId);
/// Keeps [person] from writing on the person's published studysets.
Future<void> block(FeedbackPerson person) => _server.block(person.handle);
Future<void> block(PublicPerson person) => _server.block(person.handle);
/// Lets the person with [handle] write on them again.
Future<void> unblock(String handle) => _server.unblock(handle);

View file

@ -2,6 +2,7 @@ import 'dart:developer';
import 'dart:typed_data';
import 'package:halkyon_learn_client/halkyon_learn_client.dart' as protocol;
import 'package:halkyon_learn_flutter/src/core/profile/public_person.dart';
import 'package:halkyon_learn_flutter/src/feature/feedback/data/feedback_gateway.dart';
import 'package:halkyon_learn_flutter/src/feature/feedback/data/feedback_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/feedback/model/feedback.dart';
@ -105,7 +106,7 @@ class ServerpodFeedbackGateway(final protocol.Client _client)
}
}
FeedbackPerson _person(protocol.FeedbackPerson person) => FeedbackPerson(
PublicPerson _person(protocol.FeedbackPerson person) => PublicPerson(
handle: person.handle,
displayName: person.displayName,
avatarUrl: person.avatarUrl,

View file

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart';
import 'package:halkyon_learn_flutter/src/core/profile/public_person.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
/// What a thread of feedback on a published studyset is (ADR 0005, rule 6).
@ -42,19 +43,6 @@ final class const FeedbackTarget({
List<Object?> get props => [kind, item, version];
}
/// Someone in a thread, as their public profile shows them.
final class const FeedbackPerson({
required final String handle,
final String displayName = '',
final String? avatarUrl,
}) with Equatable {
/// How they are named: their display name, else their handle.
String get name => displayName.isEmpty ? '@$handle' : displayName;
@override
List<Object?> get props => [handle, displayName, avatarUrl];
}
/// A file the content a suggestion proposes names: the writer's asset row,
/// and what the author needs to take it into their own files.
final class const FeedbackFile({
@ -70,7 +58,7 @@ final class const FeedbackFile({
/// A reply in a thread: by its writer or by the studyset's author.
final class const FeedbackMessage({
required final String id,
required final FeedbackPerson by,
required final PublicPerson by,
required final bool fromAuthor,
required final String body,
required final DateTime createdAt,
@ -88,7 +76,7 @@ final class const FeedbackThread({
required final String studysetTitle,
required final String location,
required final FeedbackKind kind,
required final FeedbackPerson writer,
required final PublicPerson writer,
required final FeedbackTarget target,
required final DateTime createdAt,

View file

@ -6,6 +6,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/core/profile/public_person.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
import 'package:halkyon_learn_flutter/src/feature/feedback/data/feedback_repository.dart';
@ -148,7 +149,7 @@ void main() {
studysetTitle: 'Japanese',
location: 'halkyon.eu/@alice/japanese',
kind: FeedbackKind.suggestion,
writer: const FeedbackPerson(handle: 'bob'),
writer: const PublicPerson(handle: 'bob'),
target: FeedbackTarget(
kind: FeedbackTargetKind.card,
item: id,
@ -193,7 +194,7 @@ void main() {
studysetTitle: 'Japanese',
location: 'halkyon.eu/@alice/japanese',
kind: FeedbackKind.suggestion,
writer: const FeedbackPerson(handle: 'bob'),
writer: const PublicPerson(handle: 'bob'),
target: const FeedbackTarget(
kind: FeedbackTargetKind.note,
item: 'gone',

View file

@ -1,6 +1,7 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/core/profile/public_person.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/feature/auth/model/auth_status.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';
@ -36,7 +37,7 @@ FeedbackThread suggestion(String item, String back, {bool unseen = false}) =>
studysetTitle: 'Japanese',
location: 'halkyon.eu/@alice/japanese',
kind: FeedbackKind.suggestion,
writer: const FeedbackPerson(handle: 'bob', displayName: 'Bob'),
writer: const PublicPerson(handle: 'bob', displayName: 'Bob'),
target: FeedbackTarget(
kind: FeedbackTargetKind.card,
item: item,