mirror of
https://github.com/block/buzz.git
synced 2026-10-31 22:41:12 +00:00
fix(mobile): tighten avatar shape guard and iOS agent fallback
The iOS Add members fallback tile drew agents as a 30% rounded rect while their loaded avatar was a squircle. It now draws the same squircle. The geometry test now rejects the old rounded rect, and the source guard also flags the old 30%/60% agent radius idiom. Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz> Signed-off-by: Tom Brow <tomb@squareup.com>
This commit is contained in:
@@ -281,8 +281,8 @@ final class NativeAddMembersViewController: UITableViewController, UISearchResul
|
||||
let size = CGSize(width: 40, height: 40)
|
||||
return UIGraphicsImageRenderer(size: size).image { _ in
|
||||
(Self.color(user["avatarBackground"]) ?? .tertiarySystemFill).setFill()
|
||||
UIBezierPath(roundedRect: CGRect(origin: .zero, size: size),
|
||||
cornerRadius: user["agent"] as? Bool == true ? 12 : 20).fill()
|
||||
let rect = CGRect(origin: .zero, size: size)
|
||||
(user["agent"] as? Bool == true ? Self.agentSquircle(rect) : UIBezierPath(ovalIn: rect)).fill()
|
||||
let text = (user["initial"] as? String ?? "?") as NSString
|
||||
let attributes: [NSAttributedString.Key: Any] = [
|
||||
.font: UIFont.systemFont(ofSize: 18, weight: .medium),
|
||||
@@ -293,6 +293,21 @@ final class NativeAddMembersViewController: UITableViewController, UISearchResul
|
||||
}.withRenderingMode(.alwaysOriginal)
|
||||
}
|
||||
|
||||
/// Mirrors avatar_shape.dart and desktop's avatar-squircle.svg.
|
||||
private static func agentSquircle(_ rect: CGRect) -> UIBezierPath {
|
||||
func at(_ x: CGFloat, _ y: CGFloat) -> CGPoint {
|
||||
CGPoint(x: rect.minX + rect.width * x, y: rect.minY + rect.height * y)
|
||||
}
|
||||
let path = UIBezierPath()
|
||||
path.move(to: at(0.5, 0))
|
||||
path.addCurve(to: at(1, 0.5), controlPoint1: at(0.93, 0), controlPoint2: at(1, 0.07))
|
||||
path.addCurve(to: at(0.5, 1), controlPoint1: at(1, 0.93), controlPoint2: at(0.93, 1))
|
||||
path.addCurve(to: at(0, 0.5), controlPoint1: at(0.07, 1), controlPoint2: at(0, 0.93))
|
||||
path.addCurve(to: at(0.5, 0), controlPoint1: at(0, 0.07), controlPoint2: at(0.07, 0))
|
||||
path.close()
|
||||
return path
|
||||
}
|
||||
|
||||
private static func color(_ value: Any?) -> UIColor? {
|
||||
guard let number = value as? NSNumber else { return nil }
|
||||
let argb = number.uint32Value
|
||||
|
||||
@@ -20,6 +20,9 @@ void main() {
|
||||
(const Offset(92, 8), false),
|
||||
(const Offset(92, 92), false),
|
||||
(const Offset(8, 92), false),
|
||||
// Inside the old 30% rounded rect, outside the squircle.
|
||||
(const Offset(1.9, 22), false),
|
||||
(const Offset(98.1, 78), false),
|
||||
]) {
|
||||
expect(path.contains(point), inside, reason: '$point');
|
||||
}
|
||||
@@ -33,7 +36,9 @@ void main() {
|
||||
test('avatar shapes come only from avatarShape', () {
|
||||
// Agent avatars drifted into circles and 30% rounded rects because each
|
||||
// surface picked its own shape. Shape decisions keyed on agent identity,
|
||||
// and person shapes on agent-only surfaces, must use avatar_shape.dart.
|
||||
// the old agent radius idiom, and person shapes on agent-only surfaces
|
||||
// must use avatar_shape.dart. Best effort: it matches the patterns that
|
||||
// produced past drift, not every possible spelling.
|
||||
final inlineAgentShape = RegExp(
|
||||
r'\b(isAgent|isBot|agent)\b\s*\?\s*(const\s+)?'
|
||||
r'(BoxShape|BorderRadius|Radius|CircleBorder|RoundedRectangleBorder|'
|
||||
@@ -43,6 +48,10 @@ void main() {
|
||||
r'if\s*\(\s*!?\s*(isAgent|isBot|agent)\s*\)\s*return\s+'
|
||||
r'(ClipOval|ClipRRect|CircleAvatar)\b',
|
||||
);
|
||||
// The old hand-rolled agent radius: 30% of a size, or 60% of a radius.
|
||||
final agentRadius = RegExp(
|
||||
r'Radius\.circular\(\s*[\w.()+\s]*\*\s*0\.[36]\s*,?\s*\)',
|
||||
);
|
||||
final personShape = RegExp(r'\b(ClipOval|CircleAvatar|BoxShape\.circle)\b');
|
||||
final violations = <String>[];
|
||||
for (final file in Directory('lib').listSync(recursive: true)) {
|
||||
@@ -53,6 +62,7 @@ void main() {
|
||||
for (final match in [
|
||||
...inlineAgentShape.allMatches(source),
|
||||
...inlineAgentClip.allMatches(source),
|
||||
...agentRadius.allMatches(source),
|
||||
if (path.startsWith('lib/features/agents/'))
|
||||
...personShape.allMatches(source),
|
||||
]) {
|
||||
|
||||
Reference in New Issue
Block a user