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
+178
View File
@@ -0,0 +1,178 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../services/connection_service.dart';
import '../services/theme_service.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
@override
Widget build(BuildContext context) {
final conn = context.watch<ConnectionService>();
return Scaffold(
backgroundColor: ThemeService.backgroundPrimary,
appBar: AppBar(
title: const Text('Settings'),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildSection('Account'),
_buildTile(
icon: Icons.person,
title: 'Username',
subtitle: conn.username ?? 'Not set',
onTap: () {},
),
_buildTile(
icon: Icons.link,
title: 'Connected to',
subtitle: conn.serverUrl,
onTap: () {},
),
_buildTile(
icon: conn.isConnected ? Icons.cloud_done : Icons.cloud_off,
title: 'Status',
subtitle: conn.isConnected ? 'Connected' : 'Disconnected',
trailing: Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: conn.isConnected
? ThemeService.success
: ThemeService.danger,
shape: BoxShape.circle,
),
),
),
const SizedBox(height: 24),
_buildSection('Appearance'),
_buildTile(
icon: Icons.palette,
title: 'Theme',
subtitle: 'Dark (JAM Default)',
onTap: () {},
),
_buildTile(
icon: Icons.font_download,
title: 'Font Size',
subtitle: 'Default',
onTap: () {},
),
const SizedBox(height: 24),
_buildSection('Privacy & Security'),
_buildTile(
icon: Icons.lock,
title: 'Encryption',
subtitle: 'XChaCha20-Poly1305',
onTap: () {},
),
_buildTile(
icon: Icons.timer,
title: 'Self-destructing messages',
subtitle: 'Off',
onTap: () {},
),
_buildTile(
icon: Icons.visibility_off,
title: 'Secret Chats',
subtitle: 'End-to-end encrypted',
onTap: () {},
),
const SizedBox(height: 24),
_buildSection('Storage & Data'),
_buildTile(
icon: Icons.storage,
title: 'Cache',
subtitle: 'Clear cached data',
onTap: () {},
),
_buildTile(
icon: Icons.download,
title: 'Auto-download',
subtitle: 'Wi-Fi only',
onTap: () {},
),
const SizedBox(height: 24),
_buildSection('About'),
_buildTile(
icon: Icons.info,
title: 'Version',
subtitle: '0.1.0',
onTap: () {},
),
const SizedBox(height: 32),
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: () {
conn.disconnect();
Navigator.pushReplacementNamed(context, '/login');
},
icon: const Icon(Icons.logout, color: ThemeService.danger),
label: const Text(
'Disconnect',
style: TextStyle(color: ThemeService.danger),
),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: ThemeService.danger),
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
const SizedBox(height: 32),
],
),
);
}
Widget _buildSection(String title) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
title.toUpperCase(),
style: const TextStyle(
color: ThemeService.textMuted,
fontSize: 12,
fontWeight: FontWeight.w700,
letterSpacing: 0.5,
),
),
);
}
Widget _buildTile({
required IconData icon,
required String title,
required String subtitle,
Widget? trailing,
VoidCallback? onTap,
}) {
return ListTile(
leading: Icon(icon, color: ThemeService.textSecondary, size: 22),
title: Text(
title,
style: const TextStyle(
color: ThemeService.textPrimary,
fontSize: 15,
),
),
subtitle: Text(
subtitle,
style: const TextStyle(
color: ThemeService.textSecondary,
fontSize: 13,
),
),
trailing: trailing ?? const Icon(Icons.chevron_right,
color: ThemeService.textMuted, size: 20),
onTap: onTap,
contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
);
}
}