feat(profile): a handle in a studyset opens its person's profile
The summary's first block now reads as a studyset's card: its secondary title, its title, then by @handle; the blocks' second heading is Material. A licence holder written as a handle of the instance (@raisondetredev) reads © raisondetredev, the © standing for the @, and is a link, apart from a name from elsewhere such as Tae Kim's; it and the author open their public profile in a sheet: avatar, name, address, bio and links, as the instance's profiles.byHandle gives them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
500ce1a25b
commit
3a328d2bb8
2 changed files with 293 additions and 24 deletions
|
|
@ -9,6 +9,7 @@ import 'package:halkyon_learn_flutter/src/feature/auth/model/auth_status.dart';
|
|||
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/explore/model/explore_studyset.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/profile/model/public_profile.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_payload.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_repository.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart';
|
||||
|
|
@ -17,6 +18,7 @@ import 'package:material_ui/material_ui.dart';
|
|||
|
||||
import '../../support/fake_auth_gateway.dart';
|
||||
import '../../support/fake_explore_gateway.dart';
|
||||
import '../../support/fake_profile_gateway.dart';
|
||||
import '../../support/fake_studyset_gateway.dart';
|
||||
import '../../support/pump_app.dart';
|
||||
import '../../support/test_dependencies.dart';
|
||||
|
|
@ -91,6 +93,7 @@ void main() {
|
|||
WidgetTester tester,
|
||||
FakeExploreGateway explore, {
|
||||
bool identified = true,
|
||||
FakeProfileGateway? profiles,
|
||||
}) async {
|
||||
tester.view.physicalSize = const Size(900, 1400);
|
||||
tester.view.devicePixelRatio = 1;
|
||||
|
|
@ -106,6 +109,7 @@ void main() {
|
|||
),
|
||||
studysetGateway: studysets,
|
||||
exploreGateway: explore,
|
||||
profileGateway: profiles,
|
||||
),
|
||||
location: RoutePaths.explore,
|
||||
);
|
||||
|
|
@ -242,6 +246,51 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
testWidgets('a licence holder of the instance is named by their handle, '
|
||||
"without the @, opening their profile; one from elsewhere isn't", (
|
||||
tester,
|
||||
) async {
|
||||
final japanese = published('Japanese');
|
||||
await showExplore(
|
||||
tester,
|
||||
FakeExploreGateway(
|
||||
published: [
|
||||
ExploreStudyset(
|
||||
publicId: japanese.publicId,
|
||||
location: japanese.location,
|
||||
handle: 'alice',
|
||||
version: 3,
|
||||
releasedAt: japanese.releasedAt,
|
||||
title: 'Japanese',
|
||||
description: japanese.description,
|
||||
license: 'CC-BY-SA-4.0',
|
||||
licenseHolder: '@alice',
|
||||
),
|
||||
],
|
||||
),
|
||||
profiles: FakeProfileGateway(
|
||||
others: {
|
||||
'alice': const PublicProfile(
|
||||
handle: 'alice',
|
||||
address: 'alice@halkyon.eu',
|
||||
displayName: 'Alice',
|
||||
bio: 'Learning Japanese.',
|
||||
),
|
||||
},
|
||||
),
|
||||
);
|
||||
await tester.tap(find.text('Japanese'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.textContaining('@alice', findRichText: true), findsWidgets);
|
||||
expect(find.text('alice'), findsOneWidget);
|
||||
await tester.tap(find.text('alice'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Learning Japanese.'), findsOneWidget);
|
||||
expect(find.text('@alice@halkyon.eu'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('a summary shows all of it, and adds it to the library as '
|
||||
'a copy, opened from there', (tester) async {
|
||||
await showExplore(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,18 @@ class FakeProfileGateway({
|
|||
|
||||
/// Handles others have.
|
||||
final Set<String> taken = const {},
|
||||
|
||||
/// Others' profiles, by their handles.
|
||||
final Map<String, PublicProfile> others = const {},
|
||||
}) implements ProfileGateway {
|
||||
@override
|
||||
Future<PublicProfile?> byHandle(String handle) async {
|
||||
if (fail case final error?) {
|
||||
throw error;
|
||||
}
|
||||
return others[handle.toLowerCase()];
|
||||
}
|
||||
|
||||
/// When set, every request fails with it.
|
||||
Exception? fail;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue