332 lines
15 KiB
Dart
332 lines
15 KiB
Dart
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!,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|