1.0 shell: one window with a party strip; protocol 9 profile + avatars by hash
The shell (lib/src/shell/) replaces the Home and session screens:
- Party strip: profile, Library / Schedule / Settings tabs, Join and
Host cards (hosting no longer takes media), status-ring avatar stack
with the member list, chat & activity panel, Leave.
- The real session player is mounted once and shown full, as a
draggable corner-snapping mini player, or fullscreen (window_manager,
party and toasts overlaid); the Video is never mounted twice.
- Profile popover with inline rename, colour and a crop picker (256 px
PNG), pushed live to the session; avatar toasts; waiting pill.
- Motion kit (fastEaseInToSlowEaseOut, fade-through, popovers,
mouse-drag/wheel horizontal scrolling).
- Library = the existing picker for now (restyled next round); Schedule
= the new SchedulePage; Settings = left nav over the existing panels.
Protocol 9 (packages/core, packages/server, sync client):
- {"t":"profile"} renames / changes the picture mid-session ("rename",
"avatar" feed actions); names are cleaned the same way at hello.
- state.members carry avatarHash; pictures are served once from
/a/<sid>/<token>/<hash> (PNG/JPEG/WebP/GIF by magic bytes only) and
cached by hash in the app (AvatarCache).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f790470935
commit
d29c12e4f0
62 files changed
+5777
-3572
No files matched your search
@@ -47,7 +47,7 @@ void main() {
|
||||
final s = Session(id: 'default', secret: 'shh');
|
||||
final png = 'x' * (64 * 1024);
|
||||
expect(s.issueToken('alice', png), isNotEmpty);
|
||||
expect(s.tokens.values.single.avatar, hasLength(64 * 1024));
|
||||
expect(s.tokens, hasLength(1));
|
||||
});
|
||||
|
||||
test('names truncated to cap, blank becomes ?', () {
|
||||
@@ -80,8 +80,21 @@ void main() {
|
||||
});
|
||||
|
||||
group('core welcome + proto', () {
|
||||
test('proto 8: relayed media', () {
|
||||
expect(RelayConstants.protoVersion, 8);
|
||||
test('proto 9: avatars by hash, profile intent', () {
|
||||
expect(RelayConstants.protoVersion, 9);
|
||||
const v = MemberView(id: 'm1', name: 'a', ready: false, inSet: false, buffered: 0, stale: false);
|
||||
expect(v.toJson().containsKey('avatarHash'), isFalse);
|
||||
expect(v.toJson().containsKey('avatar'), isFalse);
|
||||
const h = MemberView(
|
||||
id: 'm1', name: 'a', avatarHash: 'abc', ready: false, inSet: false, buffered: 0, stale: false);
|
||||
expect(MemberView.fromJson(Map<String, Object?>.from(h.toJson())).avatarHash, 'abc');
|
||||
expect(const ProfileIntent(name: 'b').toJson(), {'t': 'profile', 'name': 'b'});
|
||||
final p = ProfileIntent.fromJson({'t': 'profile', 'avatar': ''});
|
||||
expect(p.name, isNull);
|
||||
expect(p.avatar, '');
|
||||
});
|
||||
|
||||
test('relayed media', () {
|
||||
const m = HelloMedia(name: 'a', size: 1, duration: 0, relay: MediaRelay(source: 'm1', live: true));
|
||||
final back = HelloMedia.fromJson(Map<String, Object?>.from(m.toJson()));
|
||||
expect(back.relay!.source, 'm1');
|
||||
|
||||
Reference in new issue
Block a user