diff options
author | Joas Schilling <213943+nickvergessen@users.noreply.github.com> | 2023-05-02 22:34:52 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-02 22:34:52 +0200 |
commit | bcea5d70afaed5d1b492837e294cc4a1db6520dc (patch) | |
tree | 75844c2ecbb647d363be674fc560b4904d3d3ade /lib | |
parent | c4fee5eec162fc146c9000f171ea4d4273fc70de (diff) | |
parent | 9db415f2c5caa902f9ec970c4224cc0290039724 (diff) |
Merge pull request #9424 from nextcloud/feat/8444/populate-emoji-from-roomname-as-avatar
feat(avatar): Use the first emoji of room names as avatar emoji
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Service/AvatarService.php | 92 |
1 files changed, 72 insertions, 20 deletions
diff --git a/lib/Service/AvatarService.php b/lib/Service/AvatarService.php index 0919f19f2..5dd942fc4 100644 --- a/lib/Service/AvatarService.php +++ b/lib/Service/AvatarService.php @@ -35,33 +35,22 @@ use OCP\Files\SimpleFS\InMemoryFile; use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IAvatarManager; +use OCP\IEmojiHelper; use OCP\IL10N; use OCP\IURLGenerator; use OCP\IUser; use OCP\Security\ISecureRandom; class AvatarService { - private IAppData $appData; - private IL10N $l; - private IURLGenerator $url; - private ISecureRandom $random; - private RoomService $roomService; - private IAvatarManager $avatarManager; - public function __construct( - IAppData $appData, - IL10N $l, - IURLGenerator $url, - ISecureRandom $random, - RoomService $roomService, - IAvatarManager $avatarManager, + private IAppData $appData, + private IL10N $l, + private IURLGenerator $url, + private ISecureRandom $random, + private RoomService $roomService, + private IAvatarManager $avatarManager, + private IEmojiHelper $emojiHelper, ) { - $this->appData = $appData; - $this->l = $l; - $this->url = $url; - $this->random = $random; - $this->roomService = $roomService; - $this->avatarManager = $avatarManager; } public function setAvatarFromRequest(Room $room, ?array $file): void { @@ -148,6 +137,26 @@ class AvatarService { return $avatarFolder; } + /** + * https://github.com/sebdesign/cap-height -- for 500px height + * Automated check: https://codepen.io/skjnldsv/pen/PydLBK/ + * Noto Sans cap-height is 0.715 and we want a 200px caps height size + * (0.4 letter-to-total-height ratio, 500*0.4=200), so: 200/0.715 = 280px. + * Since we start from the baseline (text-anchor) we need to + * shift the y axis by 100px (half the caps height): 500/2+100=350 + * + * Copied from @see \OC\Avatar\Avatar::$svgTemplate with some changes: + * - {font} is injected + * - size fixed to 512 + * - font-size reduced to 240 + * - font-weight and fill color are removed as they are not applicable + */ + private string $svgTemplate = '<?xml version="1.0" encoding="UTF-8" standalone="no"?> + <svg width="512" height="512" version="1.1" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg"> + <rect width="100%" height="100%" fill="#{fill}"></rect> + <text x="50%" y="330" style="font-size:240px;font-family:{font};text-anchor:middle;">{letter}</text> + </svg>'; + public function getAvatar(Room $room, ?IUser $user, bool $darkTheme = false): ISimpleFile { $token = $room->getToken(); $avatar = $room->getAvatar(); @@ -161,7 +170,6 @@ class AvatarService { } } - // Fallback if (!isset($file)) { $colorTone = $darkTheme ? 'dark' : 'bright'; @@ -174,6 +182,8 @@ class AvatarService { $file = $avatar->getFile(512, $darkTheme); } } + } elseif ($this->emojiHelper->isValidSingleEmoji(mb_substr($room->getName(), 0, 1))) { + $file = new InMemoryFile($token, $this->getEmojiAvatar($room->getName(), $darkTheme)); } elseif ($room->getType() === Room::TYPE_CHANGELOG) { $file = new InMemoryFile($token, file_get_contents(__DIR__ . '/../../img/changelog.svg')); } elseif ($room->getObjectType() === 'file') { @@ -193,6 +203,48 @@ class AvatarService { return $file; } + protected function getEmojiAvatar(string $roomName, bool $darkTheme): string { + return str_replace([ + '{letter}', + '{fill}', + '{font}', + ], [ + $this->getFirstCombinedEmoji($roomName), + $darkTheme ? '3B3B3B' : 'DBDBDB', + implode(',', [ + "'Segoe UI'", + 'Roboto', + 'Oxygen-Sans', + 'Cantarell', + 'Ubuntu', + "'Helvetica Neue'", + 'Arial', + 'sans-serif', + "'Noto Color Emoji'", + "'Apple Color Emoji'", + "'Segoe UI Emoji'", + "'Segoe UI Symbol'", + "'Noto Sans'", + ]), + ], $this->svgTemplate); + } + + /** + * Get the first combined full emoji (including gender, skin tone, job, …) + * + * @param string $roomName + * @param int $length + * @return string + */ + protected function getFirstCombinedEmoji(string $roomName, int $length = 0): string { + $attempt = mb_substr($roomName, 0, $length + 1); + if ($this->emojiHelper->isValidSingleEmoji($attempt)) { + $longerAttempt = $this->getFirstCombinedEmoji($roomName, $length + 1); + return $longerAttempt ?: $attempt; + } + return ''; + } + public function deleteAvatar(Room $room): void { try { $folder = $this->appData->getFolder('room-avatar'); |