Initial commit: JustAMessenger v0.1.0

Серверная часть (Go):
- WebSocket сервер с бинарным протоколом
- XChaCha20-Poly1305 шифрование
- zstd сжатие с дедупликацией (64KB чанки)
- SQLite хранилище (WAL режим)
- Управление гильдиями, каналами, ролями
- Федерация между серверами (ed25519)
- REST API + WebSocket endpoints

Клиентская часть (Flutter):
- Material Design 3 тёмная тема (Discord-like)
- WebSocket соединение с сервером
- Экраны: сплэш, логин, домашний, гильдии, чат
- Модели: пользователи, гильдии, каналы, сообщения, роли
- Сервисы: соединение, API, криптография, тема
- Виджеты: иконки гильдий, сообщения, ввод чата
- Web сборка (PWA)

Документация:
- AGENTS.md — контекст для ИИ ассистентов
- docs/protocol.md — спецификация протокола
This commit is contained in:
SashegDev
2026-06-06 22:39:14 +00:00
commit 096c4d0a2d
40 changed files with 5054 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import '../services/theme_service.dart';
class GuildIcon extends StatelessWidget {
final String name;
final String? icon;
final bool selected;
final double size;
const GuildIcon({
super.key,
required this.name,
this.icon,
this.selected = false,
this.size = 48,
});
@override
Widget build(BuildContext context) {
final borderRadius = selected ? 14.0 : 24.0;
return Stack(
children: [
if (selected)
Positioned(
left: -8,
top: 0,
bottom: 0,
child: Container(
width: 4,
height: size * 0.4,
decoration: BoxDecoration(
color: ThemeService.textPrimary,
borderRadius: BorderRadius.circular(2),
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: size * 0.25),
child: Container(
width: size,
height: size,
decoration: BoxDecoration(
color: selected
? ThemeService.primary
: ThemeService.surfacePrimary,
borderRadius: BorderRadius.circular(borderRadius),
),
child: Center(
child: icon != null
? ClipRRect(
borderRadius: BorderRadius.circular(borderRadius),
child: Image.network(
icon!,
width: size,
height: size,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => _buildInitial(),
),
)
: _buildInitial(),
),
),
),
],
);
}
Widget _buildInitial() {
return Text(
name.isNotEmpty ? name[0].toUpperCase() : '?',
style: TextStyle(
color: selected ? Colors.white : ThemeService.textSecondary,
fontSize: size * 0.4,
fontWeight: FontWeight.w700,
),
);
}
}