Remove launcher lettering and fit IKAR mark to circular icons

This commit is contained in:
sevenhill
2026-10-07 22:22:03 +03:00
parent 1ef2b7420e
commit 64c838b8d1
48 changed files with 103 additions and 6 deletions
+6 -2
View File
@@ -28,13 +28,17 @@
Проверки: полный клиентский прогон — 1189 прошли, 3 пропущены; сервер — 150 прошли, без пропусков. Анализ `lib` и `test` не выявил ошибок и предупреждений, остались 42 информационных замечания стиля. Проверены выбор качества видео, сохранение темы, доступ к расшифрованному тексту, жесты, переключение невидимости, переподключение и сохранение публичной активности при обновлении схемы. Локальные отчёты: `artifacts/komet-full-flutter-tests.log`, `artifacts/komet-server-tests.log`, `artifacts/komet-implementation-analyze.log`. Проверки: полный клиентский прогон — 1189 прошли, 3 пропущены; сервер — 150 прошли, без пропусков. Анализ `lib` и `test` не выявил ошибок и предупреждений, остались 42 информационных замечания стиля. Проверены выбор качества видео, сохранение темы, доступ к расшифрованному тексту, жесты, переключение невидимости, переподключение и сохранение публичной активности при обновлении схемы. Локальные отчёты: `artifacts/komet-full-flutter-tests.log`, `artifacts/komet-server-tests.log`, `artifacts/komet-implementation-analyze.log`.
Эти изменения относятся к исходникам клиента и сервера. Для использования на телефоне нужны обновление сервера и сборка нового APK; текущий опубликованный выпуск их не содержит. Новый APK, развёртывание и проверка этих изменений на телефоне в этой задаче не выполнялись. Рабочий API обновлён до `releases/20261007-komet`. Проверены совпадение SHA-256 серверной сборки, целостность рабочей базы и резервной копии, новая колонка публичной активности, `/health`, отсутствие перезапусков API и сохранность соседних контейнеров. Резервная копия перед обновлением: `/mnt/data/ikar_server/backups/ikar-20261007T191617Z.tar.gz`; предыдущий выпуск сохранён для отката. Через публичный HTTPS прошли 15 общих проверок API, 8 проверок невидимости и 5 проверок видео. Они охватывают регистрацию, доставку и историю, права доступа, файлы, речь на Pi, группы, каналы, реакции, опросы, отложенную отправку и сигнализацию звонков. Невидимая сессия получает сообщения и приглашения звонка, не меняя публичное время активности. Отчёты: `artifacts/deployment-komet.json`, `artifacts/ghost-live-verification.json`, `artifacts/live-smoke.json`, `artifacts/video-live-verification.json`.
Главная иконка содержит только рисунок Икара без надписей. Размер рисунка — около 90% диаметра круглой области; адаптивный слой учитывает расширение Android с 72 до 108 dp. Исходный рисунок — `assets/ikar_mark.png`, основные ресурсы — `assets/ikar_icon.png` и `assets/ikar.png`. Пересоздание: `dart run tool/make_ikar_icons.dart`, затем `dart run flutter_launcher_icons`. Ресурсы основной иконки обновлены для Android, iOS, Windows и macOS; альтернативная иконка сохранена.
Новая иконка и клиентские изменения требуют нового APK; текущий опубликованный выпуск их не содержит. Выпуск APK и проверка этих клиентских изменений на телефоне в этой задаче не выполнялись.
## Размещение на Pi ## Размещение на Pi
Внешний диск: `/mnt/data` (`/dev/sdb1`, ext4). Корень новой установки: `/mnt/data/ikar_server`. Внешний диск: `/mnt/data` (`/dev/sdb1`, ext4). Корень новой установки: `/mnt/data/ikar_server`.
- `current` — ссылка на действующий выпуск в `releases/20261007-video`; - `current` — ссылка на действующий выпуск в `releases/20261007-komet`;
- `shared/data` — SQLite, вложения, данные устройств и публикация APK; - `shared/data` — SQLite, вложения, данные устройств и публикация APK;
- `shared/server.env`, `shared/turn.env` — закрытые настройки, доступ 0600; - `shared/server.env`, `shared/turn.env` — закрытые настройки, доступ 0600;
- `backups` — ежедневные согласованные копии SQLite и вложений, хранение 14 дней; - `backups` — ежедневные согласованные копии SQLite и вложений, хранение 14 дней;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 37 KiB

@@ -4,6 +4,6 @@
<foreground> <foreground>
<inset <inset
android:drawable="@drawable/ic_launcher_foreground" android:drawable="@drawable/ic_launcher_foreground"
android:inset="16%" /> android:inset="0%" />
</foreground> </foreground>
</adaptive-icon> </adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 17 KiB

+1 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="ic_launcher_background">#000000</color> <color name="ic_launcher_background">#FFFFFF</color>
<color name="ic_launcher_minimal_background">#000000</color> <color name="ic_launcher_minimal_background">#000000</color>
</resources> </resources>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

+8
View File
@@ -0,0 +1,8 @@
Mode: built-in image_gen imagegen tool.
Edit targets: original assets/ikar_icon.png and assets/ikar.png.
Generated source: assets/ikar_mark.png.
Use case: precise-object-edit / background-extraction. Edit target: image 1 is the existing IKAR app emblem, image 2 shows the same existing emblem with text that must be removed. Produce one clean square PNG launcher foreground with real transparent background. Keep ONLY the existing illustrated winged Icarus figure and its two chat bubbles and golden sun, exactly matching the existing shapes, pose, colors and visual identity. Remove ALL text including ИКАР, МЕССЕНДЖЕР, underlines, sparkle, and remove the near-white background and the ground/drop shadow. Do not redesign, do not add objects, do not turn chat bubbles into text. Center the complete emblem as a single composition, scale it to occupy approximately 90 percent of a circle centered in the square: entire emblem must fit fully inside a circle of radius 45 percent of canvas side, with nothing clipped. Preserve the cyan/blue wings, golden wing and sun, white bubble interiors and dotted bubble details. Output is just the cleaned icon art on genuine alpha transparency; no circle outline, no mockup, no labels, no watermark.
Launcher packaging: tool/make_ikar_icons.dart scales and centers the generated artwork for a 90 percent circular footprint. Android adaptive foreground uses a 72/108 viewport ratio and 0 percent additional XML inset. Background is white.
Android layer reference: https://developer.android.com/develop/ui/compose/system/icon_design_adaptive
Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 KiB

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 807 B

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 KiB

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 659 B

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

+3 -2
View File
@@ -140,9 +140,10 @@ flutter_launcher_icons:
android: "ic_launcher" android: "ic_launcher"
ios: true ios: true
remove_alpha_ios: true remove_alpha_ios: true
background_color_ios: "#000000" background_color_ios: "#FFFFFF"
adaptive_icon_background: "#000000" adaptive_icon_background: "#FFFFFF"
adaptive_icon_foreground: "assets/ikar.png" adaptive_icon_foreground: "assets/ikar.png"
adaptive_icon_foreground_inset: 0
windows: windows:
generate: true generate: true
image_path: "assets/ikar_icon.png" image_path: "assets/ikar_icon.png"
+84
View File
@@ -0,0 +1,84 @@
import 'dart:io';
import 'dart:math' as math;
import 'package:image/image.dart' as img;
const _size = 1024;
const _coverage = 0.90;
void main() {
final source = img.decodePng(File('assets/ikar_mark.png').readAsBytesSync())!;
var left = source.width;
var top = source.height;
var right = 0;
var bottom = 0;
for (final pixel in source) {
if (pixel.a < 128) continue;
left = math.min(left, pixel.x);
top = math.min(top, pixel.y);
right = math.max(right, pixel.x);
bottom = math.max(bottom, pixel.y);
}
final artwork = img.copyCrop(
source,
x: left,
y: top,
width: right - left + 1,
height: bottom - top + 1,
);
var radius = 0.0;
for (final pixel in artwork) {
if (pixel.a < 128) continue;
final dx = pixel.x + 0.5 - artwork.width / 2;
final dy = pixel.y + 0.5 - artwork.height / 2;
radius = math.max(radius, math.sqrt(dx * dx + dy * dy));
}
img.Image render(double viewportFraction, {required bool opaque}) {
final targetRadius = _size * viewportFraction * _coverage / 2 - 1;
final scale = targetRadius / radius;
final scaled = img.copyResize(
artwork,
width: (artwork.width * scale).round(),
height: (artwork.height * scale).round(),
interpolation: img.Interpolation.cubic,
);
final canvas = img.Image(width: _size, height: _size, numChannels: 4);
if (opaque) img.fill(canvas, color: img.ColorRgba8(255, 255, 255, 255));
img.compositeImage(
canvas,
scaled,
dstX: (_size - scaled.width) ~/ 2,
dstY: (_size - scaled.height) ~/ 2,
);
return canvas;
}
final icon = render(1, opaque: true);
final foreground = render(72 / 108, opaque: false);
File('assets/ikar_icon.png').writeAsBytesSync(img.encodePng(icon));
File('assets/ikar.png').writeAsBytesSync(img.encodePng(foreground));
Directory('artifacts').createSync(recursive: true);
final preview = img.copyResize(icon, width: 512, height: 512);
for (final pixel in preview) {
final dx = pixel.x + 0.5 - 256;
final dy = pixel.y + 0.5 - 256;
if (dx * dx + dy * dy > 256 * 256) pixel.a = 0;
}
File(
'artifacts/ikar-icon-circle.png',
).writeAsBytesSync(img.encodePng(preview));
var actualRadius = 0.0;
for (final pixel in foreground) {
if (pixel.a < 128) continue;
final dx = pixel.x + 0.5 - _size / 2;
final dy = pixel.y + 0.5 - _size / 2;
actualRadius = math.max(actualRadius, math.sqrt(dx * dx + dy * dy));
}
final actualCoverage = actualRadius / (_size * (72 / 108) / 2);
if ((actualCoverage - _coverage).abs() > 0.01) {
throw StateError('Unexpected circular coverage: $actualCoverage');
}
stdout.writeln(
'Circular artwork coverage: ${(actualCoverage * 100).toStringAsFixed(1)}%',
);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 27 KiB