Files
buzz/mobile/lib/shared/profile/user_profile.dart
klopez4212 a567dfc2df Unify mobile channel details (#6113)
## Summary

- combine channel identity, actions, member previews, and lifecycle
controls in one navigable mobile details page
- add compact member management and desktop-aligned channel editing
- smooth the profile entrance transition and standardize settings-group
spacing
- align Huddle lifecycle rows with regular message author and body
spacing

## Testing

- `just mobile-check`
- `just mobile-test` — 1,477 tests
- Pixel 10 debug build, install, and interaction review

## Snapshots

### Channel header

![Channel header with channel name and member
count](https://raw.githubusercontent.com/block/buzz/c61c64a8db0f69fc71e0ac344d64384a85ad02b5/pr-6113--01-channel-header.png)

### Combined channel details

![Combined channel details with actions and member
preview](https://raw.githubusercontent.com/block/buzz/c61c64a8db0f69fc71e0ac344d64384a85ad02b5/pr-6113--02-channel-details-members.png)

### Manage channel

![Manage channel editing
controls](https://raw.githubusercontent.com/block/buzz/c61c64a8db0f69fc71e0ac344d64384a85ad02b5/pr-6113--03-manage-channel.png)

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Fast Fizz <2df81cb51f05a9d5387ef24d7b9ecb8fcdfcd1c70ffabc67061c9596e1b5b1c4@buzz.block.builderlab.xyz>
Co-authored-by: Fast Fizz <2df81cb51f05a9d5387ef24d7b9ecb8fcdfcd1c70ffabc67061c9596e1b5b1c4@buzz.block.builderlab.xyz>
2026-08-19 17:48:09 +01:00

49 lines
1.4 KiB
Dart

import 'package:flutter/foundation.dart';
@immutable
class UserProfile {
final String pubkey;
final String? displayName;
final String? avatarUrl;
final String? about;
final String? nip05Handle;
/// NIP-OA verified owner pubkey from the profile's `auth` tag; non-null
/// means this identity is an agent (mirrors desktop's `ownerPubkey`).
final String? ownerPubkey;
const UserProfile({
required this.pubkey,
this.displayName,
this.avatarUrl,
this.about,
this.nip05Handle,
this.ownerPubkey,
});
factory UserProfile.fromJson(Map<String, dynamic> json) => UserProfile(
pubkey: json['pubkey'] as String,
displayName: json['display_name'] as String?,
avatarUrl: json['avatar_url'] as String?,
about: json['about'] as String?,
nip05Handle: json['nip05_handle'] as String?,
);
/// Short label: display name, or first 8 chars of pubkey.
String get label =>
displayName ??
'${pubkey.length >= 8 ? pubkey.substring(0, 8) : pubkey}...';
/// First letter for fallback avatar.
String get initial =>
(displayName?.isNotEmpty == true ? displayName! : pubkey)[0]
.toUpperCase();
}
/// Optional profile handle shown beside a message author's display name.
String? messageUsernameLabel(UserProfile? profile) {
final handle = profile?.nip05Handle?.trim();
if (handle != null && handle.isNotEmpty) return handle;
return null;
}