392 lines
13 KiB
Dart
392 lines
13 KiB
Dart
import 'package:chepuhagram/presentation/screens/account_settings_screen.dart';
|
||
import 'package:chepuhagram/presentation/screens/login_screen.dart';
|
||
import 'package:chepuhagram/presentation/screens/privacy_settings_menu_screen.dart';
|
||
import 'package:chepuhagram/presentation/screens/appearance_settings_screen.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:provider/provider.dart';
|
||
import '/logic/auth_provider.dart';
|
||
import 'package:package_info_plus/package_info_plus.dart';
|
||
import 'package:image_picker/image_picker.dart';
|
||
import 'dart:io';
|
||
import 'admin_panel_screen.dart';
|
||
|
||
class SettingsScreen extends StatefulWidget {
|
||
final bool isFromList;
|
||
const SettingsScreen({super.key, this.isFromList = true});
|
||
|
||
@override
|
||
State<SettingsScreen> createState() => _SettingsScreenState();
|
||
}
|
||
|
||
class _SettingsScreenState extends State<SettingsScreen> {
|
||
String? versionCode;
|
||
final ImagePicker _picker = ImagePicker();
|
||
bool _isAvatarExpanded = false;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_loadVersion();
|
||
}
|
||
|
||
void _loadVersion() async {
|
||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||
if (mounted) {
|
||
setState(() {
|
||
versionCode = packageInfo.version;
|
||
});
|
||
}
|
||
}
|
||
|
||
Future<void> _pickAvatar() async {
|
||
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
|
||
if (image != null) {
|
||
final success = await context.read<AuthProvider>().updateAvatar(
|
||
image.path,
|
||
);
|
||
if (!success && mounted) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(content: Text('Ошибка загрузки аватарки')),
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final authProv = context.watch<AuthProvider>();
|
||
final colorScheme = Theme.of(context).colorScheme;
|
||
final screenWidth = MediaQuery.of(context).size.width;
|
||
|
||
String platformName = Platform.isAndroid
|
||
? 'Android'
|
||
: Platform.isIOS
|
||
? 'iOS'
|
||
: Platform.isWindows
|
||
? 'Windows'
|
||
: Platform.isLinux
|
||
? 'Linux'
|
||
: Platform.isMacOS
|
||
? 'macOS'
|
||
: 'Unknown';
|
||
|
||
final String fullName =
|
||
'${authProv.firstName ?? ''} ${authProv.lastName ?? ''}'.trim();
|
||
final String username = authProv.username ?? '';
|
||
|
||
ImageProvider? avatarImage;
|
||
if (authProv.avatarUrl != null) {
|
||
avatarImage = NetworkImage(authProv.avatarUrl!);
|
||
} else if (authProv.avatarPath != null) {
|
||
avatarImage = FileImage(File(authProv.avatarPath!));
|
||
}
|
||
|
||
final initials =
|
||
(authProv.displayName.isNotEmpty
|
||
? authProv.displayName
|
||
: (username.isNotEmpty ? username : 'U'))
|
||
.trim()
|
||
.split(RegExp(r'\s+'))
|
||
.where((p) => p.isNotEmpty)
|
||
.take(2)
|
||
.map((p) => p[0].toUpperCase())
|
||
.join();
|
||
|
||
return Scaffold(
|
||
backgroundColor: colorScheme.background,
|
||
appBar: (Platform.isWindows || !widget.isFromList)
|
||
? AppBar(
|
||
title: const Text(
|
||
'Настройки',
|
||
style: TextStyle(fontWeight: FontWeight.bold),
|
||
),
|
||
elevation: 0,
|
||
backgroundColor: Colors.transparent,
|
||
)
|
||
: null,
|
||
body: ListView(
|
||
physics: const BouncingScrollPhysics(),
|
||
padding: EdgeInsets.zero,
|
||
children: [
|
||
// Анимированный интерактивный аватар как в MyProfileScreen
|
||
GestureDetector(
|
||
onTap: () => setState(() => _isAvatarExpanded = !_isAvatarExpanded),
|
||
child: AnimatedContainer(
|
||
duration: const Duration(milliseconds: 350),
|
||
curve: Curves.fastOutSlowIn,
|
||
width: _isAvatarExpanded ? screenWidth : 130.0,
|
||
height: _isAvatarExpanded ? screenWidth : 130.0,
|
||
margin: _isAvatarExpanded
|
||
? EdgeInsets.zero
|
||
: const EdgeInsets.only(top: 16, bottom: 8),
|
||
decoration: BoxDecoration(
|
||
shape: _isAvatarExpanded ? BoxShape.rectangle : BoxShape.circle,
|
||
color: colorScheme.primaryContainer.withOpacity(0.4),
|
||
boxShadow: _isAvatarExpanded
|
||
? []
|
||
: [
|
||
BoxShadow(
|
||
color: Colors.black.withOpacity(0.1),
|
||
blurRadius: 20,
|
||
offset: const Offset(0, 10),
|
||
),
|
||
],
|
||
image: avatarImage != null
|
||
? DecorationImage(image: avatarImage, fit: BoxFit.cover)
|
||
: null,
|
||
),
|
||
child: avatarImage == null
|
||
? Center(
|
||
child: Text(
|
||
initials.isEmpty ? 'U' : initials,
|
||
style: TextStyle(
|
||
fontSize: _isAvatarExpanded ? 80 : 38,
|
||
fontWeight: FontWeight.w700,
|
||
color: colorScheme.onPrimaryContainer,
|
||
),
|
||
),
|
||
)
|
||
: null,
|
||
),
|
||
),
|
||
|
||
// Имя пользователя
|
||
Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||
child: Text(
|
||
fullName.isNotEmpty
|
||
? fullName
|
||
: (authProv.displayName.isNotEmpty
|
||
? authProv.displayName
|
||
: 'Имя не указано'),
|
||
style: const TextStyle(
|
||
fontSize: 26,
|
||
fontWeight: FontWeight.bold,
|
||
letterSpacing: -0.5,
|
||
),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
),
|
||
if (username.isNotEmpty)
|
||
Padding(
|
||
padding: const EdgeInsets.only(top: 4, bottom: 24),
|
||
child: Text(
|
||
'@$username',
|
||
style: TextStyle(
|
||
color: colorScheme.primary,
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
textAlign: TextAlign.center,
|
||
),
|
||
)
|
||
else
|
||
const SizedBox(height: 24),
|
||
|
||
// Секция навигации меню (Сгруппированный контейнер)
|
||
Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: colorScheme.surfaceVariant.withOpacity(0.2),
|
||
borderRadius: BorderRadius.circular(24),
|
||
border: Border.all(
|
||
color: colorScheme.outlineVariant.withOpacity(0.1),
|
||
),
|
||
),
|
||
child: Column(
|
||
children: [
|
||
_buildMenuTile(
|
||
context,
|
||
Icons.person_outline_rounded,
|
||
'Аккаунт',
|
||
'Имя, телефон, почта, о себе',
|
||
() => Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (_) => const AccountSettingsScreen(),
|
||
),
|
||
),
|
||
),
|
||
_buildDivider(context),
|
||
_buildMenuTile(
|
||
context,
|
||
Icons.shield_outlined,
|
||
'Конфиденциальность',
|
||
'Безопасность и видимость данных',
|
||
() => Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (_) => const PrivacySettingsMenuScreen(),
|
||
),
|
||
),
|
||
),
|
||
_buildDivider(context),
|
||
_buildMenuTile(
|
||
context,
|
||
Icons.palette_outlined,
|
||
'Оформление',
|
||
'Тема, цвета, обои чата',
|
||
() => Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (_) => const AppearanceSettingsScreen(),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
|
||
if (authProv.currentUserId == 1) ...[
|
||
const SizedBox(height: 16),
|
||
Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: colorScheme.primary.withOpacity(0.1),
|
||
borderRadius: BorderRadius.circular(24),
|
||
border: Border.all(
|
||
color: colorScheme.primary.withOpacity(0.2),
|
||
),
|
||
),
|
||
child: ListTile(
|
||
contentPadding: const EdgeInsets.symmetric(
|
||
horizontal: 20,
|
||
vertical: 4,
|
||
),
|
||
leading: Icon(
|
||
Icons.admin_panel_settings_rounded,
|
||
color: colorScheme.primary,
|
||
),
|
||
title: Text(
|
||
"Админ-панель",
|
||
style: TextStyle(
|
||
color: colorScheme.primary,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
subtitle: const Text("Управление пользователями системы"),
|
||
trailing: Icon(
|
||
Icons.chevron_right_rounded,
|
||
color: colorScheme.primary,
|
||
),
|
||
onTap: () {
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (_) => const AdminPanelScreen(),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
),
|
||
),
|
||
],
|
||
|
||
const SizedBox(height: 16),
|
||
|
||
// Кнопка выхода из аккаунта
|
||
Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: colorScheme.errorContainer.withOpacity(0.15),
|
||
borderRadius: BorderRadius.circular(24),
|
||
border: Border.all(
|
||
color: colorScheme.errorContainer.withOpacity(0.2),
|
||
),
|
||
),
|
||
child: ListTile(
|
||
contentPadding: const EdgeInsets.symmetric(
|
||
horizontal: 20,
|
||
vertical: 4,
|
||
),
|
||
leading: Icon(Icons.logout_rounded, color: colorScheme.error),
|
||
title: Text(
|
||
"Выйти из аккаунта",
|
||
style: TextStyle(
|
||
color: colorScheme.error,
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
trailing: Icon(
|
||
Icons.chevron_right_rounded,
|
||
color: colorScheme.error,
|
||
),
|
||
onTap: () async {
|
||
await authProv.logout();
|
||
if (context.mounted) {
|
||
Navigator.pushAndRemoveUntil(
|
||
context,
|
||
MaterialPageRoute(builder: (_) => const LoginScreen()),
|
||
(r) => false,
|
||
);
|
||
}
|
||
},
|
||
),
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 40),
|
||
Center(
|
||
child: Text(
|
||
"Chepuhagram for $platformName v${versionCode ?? '1.0.0'}",
|
||
style: TextStyle(color: colorScheme.outline, fontSize: 12),
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Center(
|
||
child: Text(
|
||
"Made by ArturKarasevich",
|
||
style: TextStyle(
|
||
color: colorScheme.outline.withOpacity(0.6),
|
||
fontSize: 11,
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 40),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildMenuTile(
|
||
BuildContext context,
|
||
IconData icon,
|
||
String title,
|
||
String subtitle,
|
||
VoidCallback onTap,
|
||
) {
|
||
final colorScheme = Theme.of(context).colorScheme;
|
||
return ListTile(
|
||
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 6),
|
||
leading: Container(
|
||
padding: const EdgeInsets.all(8),
|
||
decoration: BoxDecoration(
|
||
color: colorScheme.primary.withOpacity(0.08),
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
child: Icon(icon, color: colorScheme.primary, size: 22),
|
||
),
|
||
title: Text(
|
||
title,
|
||
style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
|
||
),
|
||
subtitle: Text(
|
||
subtitle,
|
||
style: TextStyle(color: colorScheme.outline, fontSize: 13),
|
||
),
|
||
trailing: Icon(Icons.chevron_right_rounded, color: colorScheme.outline),
|
||
onTap: onTap,
|
||
);
|
||
}
|
||
|
||
Widget _buildDivider(BuildContext context) => Divider(
|
||
height: 1,
|
||
indent: 68,
|
||
color: Theme.of(context).colorScheme.outlineVariant.withOpacity(0.15),
|
||
);
|
||
}
|