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:
@@ -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)),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user