Show real photos for people instead of scene art
Your avatar is your photo, picked from the device by tapping it on Home or from a new Profile photo row in Settings, shrunk to 256 px and kept on the phone (there is no upload endpoint yet). Group members show the photo the server sends in a new `photo` field, everywhere avatars appear. Without a photo, an initial on a neutral disc. Mock mode bundles free Unsplash portraits for the sample people. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KhQh614DMeYoQEH9SoMRUw
This commit is contained in:
56
frontend/lib/Grounded/designs/Portrait.dart
Normal file
56
frontend/lib/Grounded/designs/Portrait.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../about/internal/application/TextType.dart';
|
||||
import '../utils/Colors.dart';
|
||||
import 'text/Text.dart';
|
||||
|
||||
/// Where a portrait comes from. A stored `pic` is one of:
|
||||
/// - `data:image/...;base64,...` — a photo picked on this device
|
||||
/// - `http(s)://...` — a photo the server holds
|
||||
/// - `asset:assets/images/...` — a bundled sample (mock mode)
|
||||
/// Anything else, or empty, has no photo.
|
||||
ImageProvider? portraitImage(String pic) {
|
||||
if (pic.startsWith("data:image")) {
|
||||
final int comma = pic.indexOf(",");
|
||||
if (comma < 0) {
|
||||
return null;
|
||||
}
|
||||
return MemoryImage(base64Decode(pic.substring(comma + 1)));
|
||||
}
|
||||
if (pic.startsWith("http://") || pic.startsWith("https://")) {
|
||||
return NetworkImage(pic);
|
||||
}
|
||||
if (pic.startsWith("asset:")) {
|
||||
return AssetImage(pic.substring("asset:".length));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// A round photo of a person. Without a photo, their initial on a soft
|
||||
/// neutral disc — never a landscape: a person should look like a person.
|
||||
Widget portrait(String pic, String name, double size,
|
||||
{Color? border, double borderWidth = 2}) {
|
||||
final ImageProvider? image = portraitImage(pic);
|
||||
final String initial =
|
||||
name.trim().isEmpty ? "?" : name.trim().substring(0, 1).toUpperCase();
|
||||
|
||||
return Container(
|
||||
width: size,
|
||||
height: size,
|
||||
alignment: Alignment.center,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: colorMuted,
|
||||
border: Border.all(color: border ?? colorWhite, width: borderWidth),
|
||||
image: image == null
|
||||
? null
|
||||
: DecorationImage(image: image, fit: BoxFit.cover),
|
||||
),
|
||||
child: image == null
|
||||
? text(initial, size * 0.4, TextType.Medium, color: colorInkSoft)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user