import 'dart:async'; import 'dart:convert'; import 'package:mnemo_cards/domain/router/dialogs.dart'; import 'package:universal_io/io.dart'; import 'package:flutter/material.dart'; import 'package:file_picker/file_picker.dart'; import 'package:mnemo_cards/admin/admin_api.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; import '../main.dart'; class EditCard { GameCardDto gameCardDto; AdminApi adminApi; bool imageChanged = false; EditCard(GameCardDto? cardDto, this.adminApi) : gameCardDto = cardDto ?? const GameCardDto( id: -1, image: null, mnemo: null, original: null, translation: null, transcription: null, transcriptionMnemo: null, imageBack: null, back: null, ); void _saveCard() async { final dto = imageChanged ? gameCardDto : gameCardDto.copyWith.image(null); final _progress = ValueNotifier<(int, int)>((0, 1)); final _dialogCompleter = Completer(); showInfoDialog( '', child: ValueListenableBuilder( valueListenable: _progress, builder: (c, v, _) => Text( (v.$1 == v.$2 || v.$2 < 0) ? 'Waiting for response...' : 'Uploading ${v.$1}/${v.$2}...', ), ), completer: _dialogCompleter, ); final result = await adminApi.addCard( dto, progressCallback: (a, b) => _progress.value = (a, b), ); _dialogCompleter.complete(); if (!result) { ScaffoldMessenger.of( scaffoldKey.currentContext!, ).showSnackBar(SnackBar(content: Text('ERROR'))); } else { ScaffoldMessenger.of( scaffoldKey.currentContext!, ).showSnackBar(SnackBar(content: Text('Success!!!'))); appRouter.maybePop(); } } void _deleteCard() async { final result = await adminApi.deleteCard(gameCardDto); if (!result) { ScaffoldMessenger.of( scaffoldKey.currentContext!, ).showSnackBar(SnackBar(content: Text('ERROR'))); } else { ScaffoldMessenger.of( scaffoldKey.currentContext!, ).showSnackBar(SnackBar(content: Text('Success!!!'))); appRouter.maybePop(); } } void addCard(BuildContext context) { final theme = Theme.of(context).textTheme; final TextEditingController originalController = TextEditingController( text: gameCardDto.original, ); final TextEditingController translationController = TextEditingController( text: gameCardDto.translation, ); final TextEditingController transcriptionController = TextEditingController( text: gameCardDto.transcription, ); final TextEditingController transcriptionMnemoController = TextEditingController(text: gameCardDto.transcriptionMnemo); final TextEditingController mnemoController = TextEditingController( text: gameCardDto.mnemo, ); final TextEditingController backController = TextEditingController( text: gameCardDto.back, ); showDialog( context: context, builder: (c) { return Center( child: Scaffold( body: Material( child: ListView( children: [ Header( '${gameCardDto.id}', hasPopButton: true, trail: Row( children: [ IconButton( onPressed: _saveCard, icon: Icon(Icons.save), ), if (gameCardDto.id >= 0) GestureDetector( onLongPress: _deleteCard, child: Icon(Icons.delete), ), ], ), ), StatefulBuilder( builder: (context, setState) { return Stack( alignment: Alignment.center, children: [ Padding( padding: EdgeInsets.all(8.0), child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Column( children: [ TextField( controller: originalController, onChanged: (v) { gameCardDto = gameCardDto.copyWith( original: v, ); }, decoration: InputDecoration( hintText: 'Original (cerdo)', ), maxLines: 1, style: theme.displayMedium?.copyWith( fontSize: theme.displayMedium!.fontSize!, ), ), TextField( controller: translationController, onChanged: (v) { gameCardDto = gameCardDto.copyWith( translation: v, ); }, decoration: InputDecoration( hintText: 'Translation (свинья)', ), maxLines: 1, style: theme.headlineSmall?.copyWith( color: theme.headlineSmall!.color! .withOpacity(0.5), fontSize: theme.headlineSmall!.fontSize!, ), ), Row( children: [ Flexible( child: TextField( controller: transcriptionController, onChanged: (v) { gameCardDto = gameCardDto .copyWith(transcription: v); }, decoration: InputDecoration( hintText: 'Transcription', ), maxLines: 1, style: theme.headlineSmall ?.copyWith( color: theme .headlineSmall! .color!, fontSize: theme .headlineSmall! .fontSize!, ), ), ), SizedBox(width: 4.0), Flexible( child: TextField( controller: transcriptionMnemoController, onChanged: (v) { gameCardDto = gameCardDto .copyWith( transcriptionMnemo: v, ); }, decoration: InputDecoration( hintText: 'Transcription mnemo', ), maxLines: 1, style: theme.headlineSmall ?.copyWith( color: theme .headlineSmall! .color!, fontSize: theme .headlineSmall! .fontSize!, ), ), ), ], ), ], ), SizedBox( width: MediaQuery.of(context).size.width - 20, height: MediaQuery.of(context).size.width - 20, child: GestureDetector( onTap: () async { FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null && result.files.isNotEmpty) { imageChanged = true; final file = result.files.first; final encoded = base64.normalize( base64.encode( File(file.path!).readAsBytesSync(), ), ); gameCardDto = gameCardDto.copyWith( image: encoded, ); } setState(() {}); }, child: gameCardDto.image == null ? Container( alignment: Alignment.center, color: Colors.white, child: Icon( Icons.image, color: Colors.grey, ), ) : Stack( children: [ Image( key: ValueKey(base64), image: MemoryImage( base64.decode( gameCardDto.image!, ), ), gaplessPlayback: true, fit: BoxFit.contain, ), Positioned( top: 8.0, right: 8.0, child: IconButton( onPressed: () { gameCardDto = gameCardDto .copyWith(image: null); setState(() {}); }, icon: Icon(Icons.delete), ), ), ], ), ), ), TextField( controller: mnemoController, onChanged: (v) { gameCardDto = gameCardDto.copyWith( mnemo: v, ); }, decoration: InputDecoration( hintText: 'Mnemo ([свинья] с сердечком)', ), maxLines: 1, style: theme.headlineSmall?.copyWith( fontSize: theme.headlineSmall!.fontSize!, ), ), TextField( controller: backController, onChanged: (v) { gameCardDto = gameCardDto.copyWith(back: v); }, decoration: InputDecoration( hintText: 'Задняя сторона', ), maxLines: 1, style: theme.headlineSmall?.copyWith( fontSize: theme.headlineSmall!.fontSize!, ), ), ], ), ), ], ); }, ), ], ), ), ), ); }, ); } }