/
fSultan13
/
tactic-hack
Обзор
Документация
Войти
/
fSultan13
/
tactic-hack
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
mobile/lib/main.dart
528 строк
16 KB
Sultanov Farid
.
24 янв 2025, 16:03
24 янв 2025, 16:03
36773d5
Код
Авторство
О чём код?
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:dio/dio.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_nfc_kit/flutter_nfc_kit.dart'; void main() { runApp(const MagazineApp()); } class MagazineApp extends StatelessWidget { const MagazineApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Игра', theme: ThemeData( brightness: Brightness.dark, fontFamily: 'Roboto', ), home: const RoleBasedScreen(uuid: '684241ea-b76b-4d62-94a8-6e8aa7791654'), ); } } // Экран, определяющий роль пользователя class RoleBasedScreen extends StatefulWidget { final String uuid; const RoleBasedScreen({super.key, required this.uuid}); @override State<RoleBasedScreen> createState() => _RoleBasedScreenState(); } class _RoleBasedScreenState extends State<RoleBasedScreen> { late Future<bool> isStaff; late String username = ''; @override void initState() { super.initState(); isStaff = fetchUserRole(widget.uuid); } Future<bool> fetchUserRole(String uuid) async { try { final Dio dio = Dio(); final String url = 'http://192.168.129.214:8000/users/$uuid/'; final Response response = await dio.get(url); if (response.statusCode == 200) { final Map<String, dynamic> data = response.data; username = data['username'] as String; return data['isStaff'] as bool; } else { throw Exception('Ошибка сервера: ${response.statusCode}'); } } catch (e) { debugPrint('Ошибка при запросе к серверу: $e'); rethrow; } } @override Widget build(BuildContext context) { return FutureBuilder<bool>( future: isStaff, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } else if (snapshot.hasError) { return Scaffold( body: Center( child: Text( 'Ошибка загрузки: ${snapshot.error}', style: const TextStyle(color: Colors.red), ), ), ); } final isAdmin = snapshot.data ?? false; if (isAdmin) { return const GamePage(); } else { return PersonalState(userId: '684241ea-b76b-4d62-94a8-6e8aa7791654', username: username,); } }, ); } } // Экран для администраторов class GamePage extends StatefulWidget { const GamePage({super.key}); @override State<GamePage> createState() => _GamePageState(); } class _GamePageState extends State<GamePage> { late Future<List<User>> users; List<User> userList = []; @override void initState() { super.initState(); users = fetchUsers(); } Future<List<User>> fetchUsers() async { try { final Dio dio = Dio(); final String url = 'http://192.168.129.214:8000/users/'; final Response response = await dio.get(url); if (response.statusCode == 200) { final List<dynamic> jsonData = response.data; // Фильтруем список пользователей, исключая администраторов userList = jsonData .map((json) => User.fromJson(json)) .where((user) => !user.isStaff) .toList(); return userList; } else { throw Exception('Ошибка сервера: ${response.statusCode}'); } } catch (e) { debugPrint('Ошибка загрузки: $e'); rethrow; } } Future<void> saveToJsonFile() async { // Реализация сохранения данных в JSON } @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF000000), Color(0xFF2E2E2E)], begin: Alignment.topLeft, end: Alignment.bottomCenter, ), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Организатор', style: const TextStyle( fontSize: 36, fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 20), Expanded( child: FutureBuilder<List<User>>( future: users, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { debugPrint('Ошибка FutureBuilder: ${snapshot.error}'); return Center( child: Text( 'Ошибка загрузки', style: TextStyle(color: Colors.red), ), ); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center( child: Text('Нет данных'), ); } final userList = snapshot.data!; return ListView.builder( itemCount: userList.length, itemBuilder: (context, index) { final user = userList[index]; return EditableCard( user: user, onQuantityChanged: (newQuantity) { setState(() { user.quantityBullets = newQuantity; }); }, ); }, ); }, ), ), ElevatedButton( onPressed: saveToJsonFile, style: ElevatedButton.styleFrom( backgroundColor: Colors.yellow, padding: const EdgeInsets.symmetric(vertical: 16), ), child: const Center( child: Text( 'Сохранить изменения', style: TextStyle(fontSize: 18, color: Colors.white), ), ), ), ], ), ), ), ); } } class EditableCard extends StatefulWidget { final User user; final Function(int) onQuantityChanged; const EditableCard({ super.key, required this.user, required this.onQuantityChanged, }); @override State<EditableCard> createState() => _EditableCardState(); } class _EditableCardState extends State<EditableCard> { late TextEditingController controller; @override void initState() { super.initState(); controller = TextEditingController(text: widget.user.quantityBullets.toString()); controller.addListener(() { // Слушаем изменения и передаем их только при реальном изменении текста final newValue = int.tryParse(controller.text) ?? 0; if (newValue != widget.user.quantityBullets) { widget.onQuantityChanged(newValue); } }); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.black.withOpacity(0.5), borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( widget.user.username, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), SizedBox( width: 80, child: TextField( controller: controller, keyboardType: TextInputType.number, textAlign: TextAlign.center, style: const TextStyle(color: Colors.white), decoration: const InputDecoration( border: OutlineInputBorder(), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.white), ), enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey), ), ), ), ), ], ), ); } } // Экран для обычных пользователей class PersonalState extends StatefulWidget { final String userId; final String username; const PersonalState({super.key, required this.userId, required this.username}); @override State<PersonalState> createState() => _PersonalStateState(); } class _PersonalStateState extends State<PersonalState> { late WebSocketChannel channel; late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin; int quantityBullets = 0; bool isNfcActive = false; @override void initState() { super.initState(); // Инициализация пуш-уведомлений flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); const initializationSettingsAndroid = AndroidInitializationSettings('@mipmap/ic_launcher'); const initializationSettings = InitializationSettings(android: initializationSettingsAndroid); flutterLocalNotificationsPlugin.initialize(initializationSettings); // Подключение к WebSocket channel = WebSocketChannel.connect(Uri.parse('ws://192.168.129.214:8000/ws/simple/')); channel.sink.add(jsonEncode({ "id": widget.userId, })); channel.stream.listen((message) { final data = jsonDecode(message); final newQuantityBullets = data['quantity_bullets'] as int; _showNotification(newQuantityBullets); setState(() { quantityBullets = newQuantityBullets; }); }); // Запуск NFC сессии _startNFC(); } Future<void> _showNotification(int newQuantityBullets) async { const androidDetails = AndroidNotificationDetails( 'channel_id', 'channel_name', importance: Importance.high, priority: Priority.high, ); const notificationDetails = NotificationDetails(android: androidDetails); await flutterLocalNotificationsPlugin.show( 0, 'Обновление патронов', 'Количество патронов увеличилось до $newQuantityBullets', notificationDetails, ); } Future<void> _startNFC() async { try { setState(() { isNfcActive = true; }); while (isNfcActive) { // Инициализация NFC final tag = await FlutterNfcKit.poll(); if (tag != null && (tag.ndefAvailable ?? false)) { // Пример команды для записи данных (NDEF запись может быть другой в зависимости от метки) final response = await FlutterNfcKit.transceive("00A4040007A0000002471001"); setState(() { quantityBullets = 5; // Обновляем состояние }); await _showNotification(quantityBullets); debugPrint("NFC запись выполнена, ответ: $response"); } else { debugPrint("NFC метка не поддерживает NDEF или не обнаружена"); } } } catch (e) { debugPrint("Ошибка NFC: $e"); setState(() { isNfcActive = false; }); } } @override void dispose() { isNfcActive = false; // Останавливаем NFC channel.sink.close(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Личный кабинет'), ), body: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF000000), Color(0xFF2E2E2E)], begin: Alignment.topLeft, end: Alignment.bottomCenter, ), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Привет, ${widget.username}!', style: const TextStyle( fontSize: 36, fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 20), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.black.withOpacity(0.5), borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Добро пожаловать в личный кабинет!', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 12), Text( 'Количество патронов: $quantityBullets', style: const TextStyle( fontSize: 16, color: Colors.white, ), ), const SizedBox(height: 12), ElevatedButton( onPressed: () { setState(() { isNfcActive = !isNfcActive; if (isNfcActive) { _startNFC(); } }); }, child: Text(isNfcActive ? "Остановить NFC" : "Запустить NFC"), ), ], ), ), ], ), ), ), ); } } // Модель пользователя class User { final String id; final String username; int quantityBullets; final bool isStaff; User({ required this.id, required this.username, required this.quantityBullets, required this.isStaff, }); factory User.fromJson(Map<String, dynamic> json) { return User( id: json['id'] as String, username: json['username'] as String, quantityBullets: json['quantity_bullets'] as int, isStaff: json['is_staff'] as bool, ); } Map<String, dynamic> toJson() { return { 'id': id, 'username': username, 'quantity_bullets': quantityBullets, 'is_staff': quantityBullets, }; } }