Files
fuckKomet/lib/screens/settings/settings_screen.dart
2025-11-19 18:45:44 +03:00

611 lines
19 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:gwid/models/profile.dart';
import 'package:gwid/api/api_service.dart';
import 'package:gwid/manage_account_screen.dart';
import 'package:gwid/screens/settings/appearance_settings_screen.dart';
import 'package:gwid/screens/settings/notification_settings_screen.dart';
import 'package:gwid/screens/settings/privacy_security_screen.dart';
import 'package:gwid/screens/settings/storage_screen.dart';
import 'package:gwid/screens/settings/network_settings_screen.dart';
import 'package:gwid/screens/settings/bypass_screen.dart';
import 'package:gwid/screens/settings/about_screen.dart';
import 'package:gwid/debug_screen.dart';
import 'package:gwid/screens/settings/komet_misc_screen.dart';
import 'package:gwid/theme_provider.dart';
import 'package:provider/provider.dart';
class SettingsScreen extends StatefulWidget {
final bool showBackToChats;
final VoidCallback? onBackToChats;
final Profile? myProfile;
final bool isModal;
const SettingsScreen({
super.key,
this.showBackToChats = false,
this.onBackToChats,
this.myProfile,
this.isModal = false,
});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
Profile? _myProfile;
bool _isProfileLoading = true;
int _versionTapCount = 0;
DateTime? _lastTapTime;
bool _isReconnecting = false;
String _currentModalScreen = 'main';
@override
void initState() {
super.initState();
if (widget.myProfile != null) {
_myProfile = widget.myProfile;
_isProfileLoading = false;
} else {
_loadMyProfile();
}
}
Future<void> _loadMyProfile() async {
if (!mounted) return;
setState(() => _isProfileLoading = true);
final cachedProfileData = ApiService.instance.lastChatsPayload?['profile'];
if (cachedProfileData != null && mounted) {
setState(() {
_myProfile = Profile.fromJson(cachedProfileData);
_isProfileLoading = false;
});
return; // Нашли в кеше, выходим
}
try {
final result = await ApiService.instance.getChatsAndContacts(force: true);
if (mounted) {
final profileJson = result['profile'];
if (profileJson != null) {
setState(() {
_myProfile = Profile.fromJson(profileJson);
_isProfileLoading = false;
});
} else {
setState(() => _isProfileLoading = false);
}
}
} catch (e) {
if (mounted) {
setState(() => _isProfileLoading = false);
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text("Ошибка загрузки профиля: $e")));
}
}
}
Future<void> _handleReconnection() async {
if (_isReconnecting) return;
setState(() {
_isReconnecting = true;
});
try {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Переподключение...'),
duration: Duration(seconds: 2),
),
);
}
await ApiService.instance.performFullReconnection();
await _loadMyProfile();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Переподключение выполнено успешно'),
backgroundColor: Colors.green,
duration: Duration(seconds: 2),
),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Ошибка переподключения: $e'),
backgroundColor: Colors.red,
duration: Duration(seconds: 3),
),
);
}
} finally {
if (mounted) {
setState(() {
_isReconnecting = false;
});
}
}
}
Widget _buildReconnectionButton() {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
leading: Icon(
Icons.sync,
color: _isReconnecting
? Colors.grey
: Theme.of(context).colorScheme.primary,
),
title: const Text(
"Переподключиться к серверу",
style: TextStyle(fontWeight: FontWeight.w500),
),
subtitle: const Text("Сбросить соединение и переподключиться"),
trailing: _isReconnecting
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 2),
)
: Icon(
Icons.chevron_right_rounded,
color: Theme.of(context).colorScheme.primary,
),
onTap: _isReconnecting ? null : _handleReconnection,
),
);
}
void _handleVersionTap() {
final now = DateTime.now();
if (_lastTapTime != null && now.difference(_lastTapTime!).inSeconds > 2) {
_versionTapCount = 0;
}
_lastTapTime = now;
_versionTapCount++;
if (_versionTapCount >= 7) {
_versionTapCount = 0;
Navigator.of(
context,
).push(MaterialPageRoute(builder: (context) => const DebugScreen()));
}
}
@override
Widget build(BuildContext context) {
final themeProvider = context.watch<ThemeProvider>();
final isDesktop = themeProvider.useDesktopLayout;
if (widget.isModal || isDesktop) {
return _buildModalSettings(context);
}
return Scaffold(
appBar: AppBar(
title: const Text("Настройки"),
leading: widget.showBackToChats
? IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: widget.onBackToChats,
)
: null,
),
body: _buildSettingsContent(),
);
}
Widget _buildModalSettings(BuildContext context) {
final colors = Theme.of(context).colorScheme;
final screenSize = MediaQuery.of(context).size;
final screenWidth = screenSize.width;
final screenHeight = screenSize.height;
final isSmallScreen = screenWidth < 600 || screenHeight < 800;
return Scaffold(
backgroundColor: Colors.transparent,
body: Stack(
children: [
GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: Container(
width: double.infinity,
height: double.infinity,
color: Colors.black.withValues(alpha: 0.3),
),
),
Center(
child: isSmallScreen
? Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(color: colors.surface),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(color: colors.surface),
child: Row(
children: [
if (_currentModalScreen != 'main')
IconButton(
onPressed: () {
setState(() {
_currentModalScreen = 'main';
});
},
icon: const Icon(Icons.arrow_back),
tooltip: 'Назад',
),
Expanded(
child: Text(
_getModalTitle(),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(Icons.close),
tooltip: 'Закрыть',
),
],
),
),
Expanded(child: _buildModalContent()),
],
),
)
: Container(
width: 400,
height: 900,
margin: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: colors.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: colors.surface,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
child: Row(
children: [
if (_currentModalScreen != 'main')
IconButton(
onPressed: () {
setState(() {
_currentModalScreen = 'main';
});
},
icon: const Icon(Icons.arrow_back),
tooltip: 'Назад',
),
Expanded(
child: Text(
_getModalTitle(),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(Icons.close),
tooltip: 'Закрыть',
),
],
),
),
Expanded(child: _buildModalContent()),
],
),
),
),
],
),
);
}
String _getModalTitle() {
switch (_currentModalScreen) {
case 'notifications':
return 'Уведомления';
case 'appearance':
return 'Внешний вид';
case 'privacy':
return 'Приватность и безопасность';
case 'storage':
return 'Хранилище';
case 'network':
return 'Сеть';
case 'bypass':
return 'Bypass';
case 'about':
return 'О приложении';
case 'komet':
return 'Komet Misc';
default:
return 'Настройки';
}
}
Widget _buildModalContent() {
switch (_currentModalScreen) {
case 'notifications':
return const NotificationSettingsScreen(isModal: true);
case 'appearance':
return const AppearanceSettingsScreen(isModal: true);
case 'privacy':
return const PrivacySecurityScreen(isModal: true);
case 'storage':
return const StorageScreen(isModal: true);
case 'network':
return const NetworkSettingsScreen(isModal: true);
case 'bypass':
return const BypassScreen(isModal: true);
case 'about':
return const AboutScreen(isModal: true);
case 'komet':
return const KometMiscScreen(isModal: true);
default:
return _buildSettingsContent();
}
}
Widget _buildSettingsContent() {
return ListView(
padding: const EdgeInsets.all(16.0),
children: [
_buildProfileSection(),
const SizedBox(height: 16),
_buildReconnectionButton(),
const SizedBox(height: 16),
_buildSettingsCategory(
context,
icon: Icons.rocket_launch_outlined,
title: "Komet Misc",
subtitle: "Дополнительные настройки",
screen: KometMiscScreen(isModal: widget.isModal),
),
_buildSettingsCategory(
context,
icon: Icons.palette_outlined,
title: "Внешний вид",
subtitle: "Темы, анимации, производительность",
screen: AppearanceSettingsScreen(isModal: widget.isModal),
),
_buildSettingsCategory(
context,
icon: Icons.notifications_outlined,
title: "Уведомления",
subtitle: "Звуки, чаты, звонки",
screen: NotificationSettingsScreen(isModal: widget.isModal),
),
_buildSettingsCategory(
context,
icon: Icons.security_outlined,
title: "Приватность и безопасность",
subtitle: "Статус, сессии, пароль, блокировки",
screen: PrivacySecurityScreen(isModal: widget.isModal),
),
_buildSettingsCategory(
context,
icon: Icons.storage_outlined,
title: "Данные и хранилище",
subtitle: "Использование хранилища, очистка кэша",
screen: StorageScreen(isModal: widget.isModal),
),
_buildSettingsCategory(
context,
icon: Icons.wifi_outlined,
title: "Сеть",
subtitle: "Прокси, мониторинг, логи",
screen: NetworkSettingsScreen(isModal: widget.isModal),
),
_buildSettingsCategory(
context,
icon: Icons.psychology_outlined,
title: "Специальные возможности",
subtitle: "Обход ограничений",
screen: const BypassScreen(),
),
_buildSettingsCategory(
context,
icon: Icons.info_outline,
title: "О приложении",
subtitle: "Команда, соглашение",
screen: const AboutScreen(),
),
GestureDetector(
onTap: _handleVersionTap,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
child: Text(
'v0.3.0-beta.1',
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(
context,
).colorScheme.onSurface.withValues(alpha: 0.4),
fontSize: 12,
),
),
),
),
],
);
}
Widget _buildProfileSection() {
if (_isProfileLoading) {
return const Card(
child: ListTile(
leading: CircleAvatar(radius: 28),
title: Text("Загрузка профиля..."),
subtitle: Text("Пожалуйста, подождите"),
),
);
}
if (_myProfile == null) {
return Card(
child: ListTile(
leading: const CircleAvatar(
radius: 28,
child: Icon(Icons.error_outline),
),
title: const Text("Не удалось загрузить профиль"),
trailing: IconButton(
icon: const Icon(Icons.refresh),
onPressed: _loadMyProfile,
),
),
);
}
return Card(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
leading: CircleAvatar(
radius: 28,
backgroundImage: _myProfile!.photoBaseUrl != null
? NetworkImage(_myProfile!.photoBaseUrl!)
: null,
child: _myProfile!.photoBaseUrl == null
? Text(
_myProfile!.displayName.isNotEmpty
? _myProfile!.displayName[0].toUpperCase()
: '',
style: const TextStyle(fontSize: 24),
)
: null,
),
title: Text(
_myProfile!.displayName,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_myProfile!.formattedPhone),
const SizedBox(height: 2),
Text(
'ID: ${_myProfile!.id}',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ManageAccountScreen(myProfile: _myProfile!),
),
);
},
),
);
}
Widget _buildSettingsCategory(
BuildContext context, {
required IconData icon,
required String title,
required String subtitle,
required Widget screen,
}) {
return Card(
margin: const EdgeInsets.only(bottom: 10),
child: ListTile(
leading: Icon(icon, color: Theme.of(context).colorScheme.primary),
title: Text(title),
subtitle: Text(subtitle),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () {
if (widget.isModal) {
String screenKey = '';
if (screen is NotificationSettingsScreen)
screenKey = 'notifications';
else if (screen is AppearanceSettingsScreen)
screenKey = 'appearance';
else if (screen is PrivacySecurityScreen)
screenKey = 'privacy';
else if (screen is StorageScreen)
screenKey = 'storage';
else if (screen is NetworkSettingsScreen)
screenKey = 'network';
else if (screen is BypassScreen)
screenKey = 'bypass';
else if (screen is AboutScreen)
screenKey = 'about';
else if (screen is KometMiscScreen)
screenKey = 'komet';
setState(() {
_currentModalScreen = screenKey;
});
} else {
Navigator.of(
context,
).push(MaterialPageRoute(builder: (context) => screen));
}
},
),
);
}
}