Compare commits

..

No commits in common. "master" and "revolution" have entirely different histories.

21 changed files with 305 additions and 377 deletions

View file

@ -0,0 +1,3 @@
extension TryCastExtension<T> on Object {
T? tryCast<T>() => this is T ? this as T : null;
}

View file

@ -0,0 +1,6 @@
import 'package:flutter/material.dart';
class AppbarProviderInterface {
AppBar get appBar =>
throw UnimplementedError("appBar getter not implemented");
}

View file

@ -1,10 +1,11 @@
import 'package:flu_console/flu_console.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'package:tuuli_app/api_controller.dart'; import 'package:tuuli_app/api_controller.dart';
import 'package:tuuli_app/pages/checkup_page.dart'; import 'package:tuuli_app/pages/checkup_page.dart';
import 'package:tuuli_app/pages/home_page.dart'; import 'package:tuuli_app/pages/home_page.dart';
import 'package:tuuli_app/pages/home_panels/tables_list_panel.dart';
import 'package:tuuli_app/pages/home_panels/users_list_panel.dart';
import 'package:tuuli_app/pages/login_page.dart'; import 'package:tuuli_app/pages/login_page.dart';
import 'package:tuuli_app/pages/not_found_page.dart'; import 'package:tuuli_app/pages/not_found_page.dart';
@ -25,9 +26,7 @@ void main() async {
fenix: true, fenix: true,
); );
FluConsole.run(() { runApp(const MainApp());
runApp(const MainApp());
});
} }
class MainApp extends StatelessWidget { class MainApp extends StatelessWidget {

View file

@ -40,7 +40,7 @@ class CheckupPage extends GetView<CheckupPageController> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
'Проверяем ключ доступа...', 'Checking credentials...',
style: Theme.of(context).textTheme.headlineMedium, style: Theme.of(context).textTheme.headlineMedium,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),

View file

@ -8,13 +8,13 @@ import 'package:tuuli_app/models/table_column_definition.dart';
const typeToNameMatcher = { const typeToNameMatcher = {
SerialPrimaryColumnDefinition: "Serial ID", SerialPrimaryColumnDefinition: "Serial ID",
TextColumnDefinition: "Текст", TextColumnDefinition: "Text",
BooleanColumnDefinition: "Логическое значение", BooleanColumnDefinition: "Boolean",
TimestampColumnDefinition: "Дата/Время", TimestampColumnDefinition: "Date/Time",
DoubleColumnDefinition: "Число с плавающей точкой", DoubleColumnDefinition: "Double",
IntegerColumnDefinition: "Целое число", IntegerColumnDefinition: "Integer",
UserRefColumnDefinition: "Ссылка на пользователя", UserRefColumnDefinition: "User reference",
AssetRefColumnDefinition: "Ссылка на ресурс", AssetRefColumnDefinition: "Asset reference",
}; };
class CreateTableController extends GetxController { class CreateTableController extends GetxController {
@ -35,7 +35,7 @@ class CreateTableController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
Get.back(result: true); Get.back(result: true);
@ -43,18 +43,18 @@ class CreateTableController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка обновления доступа к таблице", "Error trying to update tables access",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка обновления доступа к таблице", "Error trying to update tables access",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка обновления доступа к таблице", "Error trying to update tables access",
"$e", "$e",
); );
} }
@ -67,14 +67,14 @@ class CreateTableController extends GetxController {
final confirm = await Get.dialog<bool>( final confirm = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Создать новую колонку"), title: const Text("Create new column"),
content: Wrap( content: Wrap(
runSpacing: 16, runSpacing: 16,
children: [ children: [
FastTextField( FastTextField(
name: "ColumnName", name: "ColumnName",
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Название", labelText: "Column name",
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
initialValue: columnName.value, initialValue: columnName.value,
@ -82,7 +82,7 @@ class CreateTableController extends GetxController {
), ),
FastDropdown( FastDropdown(
name: "ColumnTypes", name: "ColumnTypes",
hint: const Text("Тип"), hint: const Text("Select column type"),
items: typeToNameMatcher.keys.toList(growable: false), items: typeToNameMatcher.keys.toList(growable: false),
itemsBuilder: (items, field) => items itemsBuilder: (items, field) => items
.map( .map(
@ -97,7 +97,7 @@ class CreateTableController extends GetxController {
), ),
FastCheckbox( FastCheckbox(
name: "ColumnIsUnique", name: "ColumnIsUnique",
titleText: "Уникальное значение?", titleText: "Is Unique",
initialValue: false, initialValue: false,
onChanged: (value) => columnIsUnique.value = value!, onChanged: (value) => columnIsUnique.value = value!,
), ),
@ -108,13 +108,13 @@ class CreateTableController extends GetxController {
onPressed: () { onPressed: () {
Get.back(result: false); Get.back(result: false);
}, },
child: const Text("Отменить"), child: const Text('Close'),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
Get.back(result: true); Get.back(result: true);
}, },
child: const Text("Создать"), child: const Text('Create'),
), ),
], ],
), ),
@ -129,42 +129,42 @@ class CreateTableController extends GetxController {
columnName: columnName.value, columnName: columnName.value,
); );
break; break;
case "Текст": case "Text":
ct = TextColumnDefinition( ct = TextColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Логическое значение": case "Boolean":
ct = BooleanColumnDefinition( ct = BooleanColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Дата/Время": case "Date/Time":
ct = TimestampColumnDefinition( ct = TimestampColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Число с плавающей точкой": case "Double":
ct = DoubleColumnDefinition( ct = DoubleColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Целое число": case "Integer":
ct = IntegerColumnDefinition( ct = IntegerColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Ссылка на пользователя": case "User reference":
ct = UserRefColumnDefinition( ct = UserRefColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
); );
break; break;
case "Ссылка на ресурс": case "Asset reference":
ct = AssetRefColumnDefinition( ct = AssetRefColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
); );
@ -185,12 +185,12 @@ class CreateTableDialog extends GetView<CreateTableController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
title: const Text("Создать новую таблицу"), title: const Text('Creating new table'),
content: Column( content: Column(
children: [ children: [
TextField( TextField(
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Название", labelText: "Table name",
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
onChanged: (value) => controller.tableName = value, onChanged: (value) => controller.tableName = value,
@ -216,7 +216,7 @@ class CreateTableDialog extends GetView<CreateTableController> {
[ [
ElevatedButton( ElevatedButton(
onPressed: () => controller.createNewColumn(), onPressed: () => controller.createNewColumn(),
child: const Text("Создать колонку"), child: const Text("Create column"),
).expanded() ).expanded()
].toRow(), ].toRow(),
], ],
@ -226,14 +226,14 @@ class CreateTableDialog extends GetView<CreateTableController> {
onPressed: () { onPressed: () {
Get.back(); Get.back();
}, },
child: const Text("Закрыть"), child: const Text('Close'),
), ),
Obx( Obx(
() => TextButton( () => TextButton(
onPressed: controller.columnsDefinition.isEmpty onPressed: controller.columnsDefinition.isEmpty
? null ? null
: () => controller.createTable(), : () => controller.createTable(),
child: const Text("Создать"), child: const Text('Create'),
), ),
), ),
], ],

View file

@ -47,7 +47,7 @@ class GroupACLController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
_tables.clear(); _tables.clear();
@ -56,18 +56,18 @@ class GroupACLController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка запроса таблиц", "Error trying to get tables",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка запроса таблиц", "Error trying to get tables",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка запроса таблиц", "Error trying to get tables",
"$e", "$e",
); );
} }
@ -96,7 +96,7 @@ class GroupACLController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
if (respData.isNotEmpty) { if (respData.isNotEmpty) {
@ -111,18 +111,18 @@ class GroupACLController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка запроса информации доступа к таблицам", "Error trying to get tables access",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка запроса информации доступа к таблицам", "Error trying to get tables access",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка запроса информации доступа к таблицам", "Error trying to get tables access",
"$e", "$e",
); );
} }
@ -187,7 +187,7 @@ class GroupACLController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
refreshTableAccess(table); refreshTableAccess(table);
@ -195,18 +195,18 @@ class GroupACLController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка обновления информации доступа к таблицам", "Error trying to update tables access",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка обновления информации доступа к таблицам", "Error trying to update tables access",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка обновления информации доступа к таблицам", "Error trying to update tables access",
"$e", "$e",
); );
} }
@ -234,7 +234,7 @@ class GroupACLController extends GetxController {
final confirm = await Get.dialog<bool>( final confirm = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Разрешённые колонки"), title: const Text("Allowed columns"),
content: Obx( content: Obx(
() => Wrap( () => Wrap(
children: [ children: [
@ -244,7 +244,7 @@ class GroupACLController extends GetxController {
selectedColumns[column] = !selectedColumns[column]!; selectedColumns[column] = !selectedColumns[column]!;
} }
}, },
child: const Text("Перевернуть"), child: const Text("Swap all"),
), ),
...selectedColumns.entries.map((e) { ...selectedColumns.entries.map((e) {
return CheckboxListTile( return CheckboxListTile(
@ -259,11 +259,11 @@ class GroupACLController extends GetxController {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Ок"), child: const Text("Ok"),
), ),
], ],
), ),
@ -274,12 +274,12 @@ class GroupACLController extends GetxController {
if (selectedColumns.values.every((e) => !e)) { if (selectedColumns.values.every((e) => !e)) {
await Get.dialog( await Get.dialog(
AlertDialog( AlertDialog(
title: const Text("Ошибка"), title: const Text("Error"),
content: const Text("Необходимо выбрать хотя бы одну колонку"), content: const Text("At least one column must be selected"),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(), onPressed: () => Get.back(),
child: const Text("Ок"), child: const Text("Ok"),
), ),
], ],
), ),
@ -306,7 +306,7 @@ class GroupACLController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
refreshTableAccess(table); refreshTableAccess(table);
@ -314,18 +314,18 @@ class GroupACLController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка обновления информации доступа к таблицам", "Error trying to update tables access",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка обновления информации доступа к таблицам", "Error trying to update tables access",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка обновления информации доступа к таблицам", "Error trying to update tables access",
"$e", "$e",
); );
} }
@ -338,16 +338,16 @@ class GroupACLDialog extends GetView<GroupACLController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
title: const Text('Доступ группы'), title: const Text('Group ACL'),
content: Obx( content: Obx(
() => DataTable2( () => DataTable2(
columns: const [ columns: const [
DataColumn2(label: Text('Таблица'), size: ColumnSize.L), DataColumn2(label: Text('Table'), size: ColumnSize.L),
DataColumn2(label: Text('Чтение'), size: ColumnSize.S), DataColumn2(label: Text('Read'), size: ColumnSize.S),
DataColumn2(label: Text('Запись'), size: ColumnSize.S), DataColumn2(label: Text('Write'), size: ColumnSize.S),
DataColumn2(label: Text('Колонки'), size: ColumnSize.S), DataColumn2(label: Text('Allowed columns'), size: ColumnSize.S),
], ],
empty: const Text("Нет таблиц"), empty: const Text("No tables"),
rows: controller.access.entries.map((e) { rows: controller.access.entries.map((e) {
final table = controller.tables.firstWhere( final table = controller.tables.firstWhere(
(element) => element.tableId == e.key, (element) => element.tableId == e.key,
@ -390,7 +390,7 @@ class GroupACLDialog extends GetView<GroupACLController> {
onPressed: () { onPressed: () {
Get.back(); Get.back();
}, },
child: const Text("Закрыть"), child: const Text('Close'),
), ),
], ],
); );

View file

@ -1,6 +1,7 @@
import 'package:data_table_2/data_table_2.dart'; import 'package:data_table_2/data_table_2.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_fast_forms/flutter_fast_forms.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:omni_datetime_picker/omni_datetime_picker.dart'; import 'package:omni_datetime_picker/omni_datetime_picker.dart';
import 'package:recase/recase.dart'; import 'package:recase/recase.dart';
@ -69,7 +70,7 @@ class OpenTableController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
_tableData.clear(); _tableData.clear();
@ -78,18 +79,18 @@ class OpenTableController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка получения данных таблицы", "Error trying to get table data",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка получения данных таблицы", "Error trying to get table data",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка получения данных таблицы", "Error trying to get table data",
"$e", "$e",
); );
} }
@ -100,7 +101,7 @@ class OpenTableController extends GetxController {
final user = await Get.dialog<UserDefinition>( final user = await Get.dialog<UserDefinition>(
AlertDialog( AlertDialog(
title: const Text("Выберите пользователя"), title: const Text("Select user"),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -109,7 +110,7 @@ class OpenTableController extends GetxController {
username.value = value; username.value = value;
}, },
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Логин", labelText: "Username",
), ),
), ),
Obx( Obx(
@ -139,7 +140,7 @@ class OpenTableController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
return respData return respData
@ -186,7 +187,7 @@ class OpenTableController extends GetxController {
onPressed: () { onPressed: () {
Get.back(result: false); Get.back(result: false);
}, },
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
], ],
), ),
@ -200,7 +201,7 @@ class OpenTableController extends GetxController {
final asset = await Get.dialog<Asset>( final asset = await Get.dialog<Asset>(
AlertDialog( AlertDialog(
title: const Text("Выберите ресурс"), title: const Text("Select asset"),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -209,7 +210,7 @@ class OpenTableController extends GetxController {
name.value = value; name.value = value;
}, },
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Имя файла", labelText: "Filename",
), ),
), ),
Obx( Obx(
@ -240,7 +241,7 @@ class OpenTableController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
return respData return respData
@ -290,7 +291,7 @@ class OpenTableController extends GetxController {
onPressed: () { onPressed: () {
Get.back(result: null); Get.back(result: null);
}, },
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
], ],
), ),
@ -308,7 +309,7 @@ class OpenTableController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
clearNewRowData(); clearNewRowData();
@ -317,18 +318,18 @@ class OpenTableController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка получения данных таблицы", "Error trying to get table data",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка получения данных таблицы", "Error trying to get table data",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка получения данных таблицы", "Error trying to get table data",
"$e", "$e",
); );
} }
@ -356,7 +357,7 @@ class OpenTableController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
refreshTableData(); refreshTableData();
@ -364,18 +365,18 @@ class OpenTableController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка обновления данных таблицы", "Error trying to update table data",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка обновления данных таблицы", "Error trying to update table data",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка обновления данных таблицы", "Error trying to update table data",
"$e", "$e",
); );
} }
@ -407,7 +408,7 @@ class OpenTableController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
refreshTableData(); refreshTableData();
@ -415,18 +416,18 @@ class OpenTableController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка удаления данных таблицы", "Error trying to update table data",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка удаления данных таблицы", "Error trying to update table data",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка удаления данных таблицы", "Error trying to update table data",
"$e", "$e",
); );
} }
@ -464,9 +465,9 @@ class OpenTableDialog extends GetView<OpenTableController> {
col.name.pascalCase, col.name.pascalCase,
), ),
), ),
const DataColumn(label: Text("Действия")), const DataColumn(label: Text("Actions")),
], ],
empty: const Text("Нет данных"), empty: const Text("No data"),
rows: [ rows: [
DataRow( DataRow(
cells: [ cells: [
@ -698,7 +699,7 @@ class OpenTableDialog extends GetView<OpenTableController> {
final msg = () { final msg = () {
final dt = e[col.name]; final dt = e[col.name];
if (dt == null) { if (dt == null) {
return "###"; return "#error#";
} }
if (dt is String) { if (dt is String) {
final rdt = DateTime.parse(dt); final rdt = DateTime.parse(dt);
@ -804,7 +805,7 @@ class OpenTableDialog extends GetView<OpenTableController> {
if (ud == null || if (ud == null ||
ud.isEmpty || ud.isEmpty ||
ud.first["username"] == null) { ud.first["username"] == null) {
return "###"; return "#error#";
} }
controller.putUserInCache(UserDefinition( controller.putUserInCache(UserDefinition(
@ -823,9 +824,9 @@ class OpenTableDialog extends GetView<OpenTableController> {
} }
return Tooltip( return Tooltip(
message: snapshot.data ?? "###", message: snapshot.data ?? "#error#",
child: Text( child: Text(
snapshot.data ?? "###", snapshot.data ?? "#error#",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
), ),
@ -872,7 +873,7 @@ class OpenTableDialog extends GetView<OpenTableController> {
if (ad == null || if (ad == null ||
ad.isEmpty || ad.isEmpty ||
ad.first["name"] == null) { ad.first["name"] == null) {
return "###"; return "#error#";
} }
controller.putAssetInCache(Asset( controller.putAssetInCache(Asset(
@ -893,9 +894,9 @@ class OpenTableDialog extends GetView<OpenTableController> {
} }
return Tooltip( return Tooltip(
message: snapshot.data ?? "###", message: snapshot.data ?? "#error#",
child: Text( child: Text(
snapshot.data ?? "###", snapshot.data ?? "#error#",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
), ),

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:tuuli_app/api_controller.dart'; import 'package:tuuli_app/api_controller.dart';
import 'package:tuuli_app/c.dart'; import 'package:tuuli_app/c.dart';
import 'package:tuuli_app/pages/home_panels/assets_panel.dart'; import 'package:tuuli_app/pages/home_panels/assets_panel.dart';
@ -24,11 +25,11 @@ class HomePageController extends GetxController {
String get currentPageName => pageNames[currentPage]!; String get currentPageName => pageNames[currentPage]!;
final pageNames = { final pageNames = {
PageType.none: "Домашняя", PageType.none: "Home",
PageType.tables: "Таблицы", PageType.tables: "Tables",
PageType.users: "Пользователи", PageType.users: "Users",
PageType.assets: "Ресурсы", PageType.assets: "Assets",
PageType.settings: "Настройки", PageType.settings: "Settings",
}; };
@override @override
@ -90,7 +91,7 @@ class HomePage extends GetView<HomePageController> {
Obx( Obx(
() => ListTile( () => ListTile(
leading: const Icon(Icons.table_chart), leading: const Icon(Icons.table_chart),
title: const Text("Таблицы"), title: const Text("Tables"),
onTap: () { onTap: () {
controller.currentPage = PageType.tables; controller.currentPage = PageType.tables;
}, },
@ -100,7 +101,7 @@ class HomePage extends GetView<HomePageController> {
Obx( Obx(
() => ListTile( () => ListTile(
leading: const Icon(Icons.person), leading: const Icon(Icons.person),
title: const Text("Пользователи"), title: const Text("Users"),
onTap: () { onTap: () {
controller.currentPage = PageType.users; controller.currentPage = PageType.users;
}, },
@ -110,7 +111,7 @@ class HomePage extends GetView<HomePageController> {
Obx( Obx(
() => ListTile( () => ListTile(
leading: const Icon(Icons.dataset_outlined), leading: const Icon(Icons.dataset_outlined),
title: const Text("Ресурсы"), title: const Text("Assets"),
onTap: () { onTap: () {
controller.currentPage = PageType.assets; controller.currentPage = PageType.assets;
}, },
@ -120,7 +121,7 @@ class HomePage extends GetView<HomePageController> {
Obx( Obx(
() => ListTile( () => ListTile(
leading: const Icon(Icons.settings), leading: const Icon(Icons.settings),
title: const Text("Настройки"), title: const Text("Settings"),
onTap: () { onTap: () {
controller.currentPage = PageType.settings; controller.currentPage = PageType.settings;
}, },
@ -130,7 +131,7 @@ class HomePage extends GetView<HomePageController> {
const Divider(), const Divider(),
ListTile( ListTile(
leading: const Icon(Icons.logout), leading: const Icon(Icons.logout),
title: const Text("Выйти"), title: const Text("Logout"),
onTap: () => controller.logout(), onTap: () => controller.logout(),
), ),
], ],

View file

@ -52,7 +52,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
_assetsList.clear(); _assetsList.clear();
@ -61,18 +61,18 @@ class AssetsPagePanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка получения ресурсов", "Error trying to get assets",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка получения ресурсов", "Error trying to get assets",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка получения ресурсов", "Error trying to get assets",
"$e", "$e",
); );
} }
@ -84,7 +84,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
_tagsList.clear(); _tagsList.clear();
@ -93,18 +93,18 @@ class AssetsPagePanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка получения тегов", "Error trying to get tags",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка получения тегов", "Error trying to get tags",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка получения тегов", "Error trying to get tags",
"$e", "$e",
); );
} }
@ -145,11 +145,11 @@ class AssetsPagePanelController extends GetxController {
Get.back(result: file); Get.back(result: file);
}, },
onError: (value) { onError: (value) {
Get.snackbar("Ошибка", value.toString()); Get.snackbar("Error", value.toString());
}, },
); );
}, },
child: const Text("Перенесите файл сюда") child: const Text("Drop file here")
.paddingAll(8) .paddingAll(8)
.fittedBox() .fittedBox()
.constrained(height: 200, width: 200), .constrained(height: 200, width: 200),
@ -157,7 +157,7 @@ class AssetsPagePanelController extends GetxController {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: null), onPressed: () => Get.back(result: null),
child: const Text("Отменить"), child: const Text("Cancel"),
) )
], ],
), ),
@ -195,7 +195,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
refreshData(); refreshData();
@ -203,18 +203,18 @@ class AssetsPagePanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка загрузки ресурса", "Error trying to put asset",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка загрузки ресурса", "Error trying to put asset",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка загрузки ресурса", "Error trying to put asset",
"$e", "$e",
); );
} finally { } finally {
@ -228,7 +228,7 @@ class AssetsPagePanelController extends GetxController {
final confirm = await Get.dialog<bool>( final confirm = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Изменение ресурса"), title: const Text("Edit asset"),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
@ -237,7 +237,7 @@ class AssetsPagePanelController extends GetxController {
controller: TextEditingController(text: description.value), controller: TextEditingController(text: description.value),
onChanged: (value) => description.value = value, onChanged: (value) => description.value = value,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Описание", labelText: "Description",
), ),
), ),
TextField( TextField(
@ -245,7 +245,7 @@ class AssetsPagePanelController extends GetxController {
onChanged: (value) => tags.value = onChanged: (value) => tags.value =
value.split(",").map((e) => e.trim()).toList(growable: false), value.split(",").map((e) => e.trim()).toList(growable: false),
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Теги", labelText: "Tags",
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
@ -253,23 +253,23 @@ class AssetsPagePanelController extends GetxController {
() => Wrap( () => Wrap(
children: tags children: tags
.where((p0) => p0.isNotEmpty) .where((p0) => p0.isNotEmpty)
.map((tag) => Chip(label: Text(tag)).paddingAll(2)) .map((tag) => Chip(label: Text(tag)))
.toList(growable: false), .toList(growable: false),
).paddingAll(8).card(color: Colors.blueGrey.shade200).expanded(), ).paddingAll(8).card(color: Colors.blueGrey.shade200).expanded(),
), ),
ElevatedButton( ElevatedButton(
onPressed: () => previewAsset(e), onPressed: () => previewAsset(e),
child: const Text("Предпросмотр")), child: const Text("View asset")),
], ],
).constrained(width: Get.width * 0.5, height: Get.width * 0.5), ).constrained(width: Get.width * 0.5, height: Get.width * 0.5),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Подтвердить"), child: const Text("Confirm"),
), ),
], ],
), ),
@ -287,7 +287,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
refreshData(); refreshData();
@ -295,18 +295,18 @@ class AssetsPagePanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка изменения ресурса", "Error trying to edit asset",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка изменения ресурса", "Error trying to edit asset",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка изменения ресурса", "Error trying to edit asset",
"$e", "$e",
); );
} }
@ -318,24 +318,23 @@ class AssetsPagePanelController extends GetxController {
final confirm = await Get.dialog<bool>( final confirm = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Удаление ресурса"), title: const Text("Remove asset"),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Text( const Text("You are about to remove an asset."),
"Вы планируете удалить ресурс. Это действие нельзя отменить."),
Obx( Obx(
() => CheckboxListTile( () => CheckboxListTile(
value: checkReferences.value, value: checkReferences.value,
onChanged: (value) => checkReferences.value = value ?? false, onChanged: (value) => checkReferences.value = value ?? false,
title: const Text("Проверить ссылки"), title: const Text("Check references"),
), ),
), ),
Obx( Obx(
() => CheckboxListTile( () => CheckboxListTile(
value: deleteReferencing.value, value: deleteReferencing.value,
onChanged: (value) => deleteReferencing.value = value ?? false, onChanged: (value) => deleteReferencing.value = value ?? false,
title: const Text("Удалить ссылающиеся сущности"), title: const Text("Delete referencing"),
), ),
), ),
], ],
@ -343,11 +342,11 @@ class AssetsPagePanelController extends GetxController {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Удалить"), child: const Text("Remove"),
), ),
], ],
), ),
@ -364,7 +363,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
refreshData(); refreshData();
@ -372,18 +371,18 @@ class AssetsPagePanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка удаления ресурса", "Error trying to remove asset",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка удаления ресурса", "Error trying to remove asset",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка удаления ресурса", "Error trying to remove asset",
"$e", "$e",
); );
} }
@ -405,7 +404,7 @@ class AssetsPagePanelController extends GetxController {
url: "${ApiController.to.endPoint}/assets/${e.fid}", url: "${ApiController.to.endPoint}/assets/${e.fid}",
) )
else else
const Text("На данный момент этот тип не поддерживает предпросмотр") const Text("Unsupported media type")
.fontSize(16) .fontSize(16)
.paddingAll(8) .paddingAll(8)
.card() .card()
@ -440,7 +439,7 @@ class AssetsPagePanel extends GetView<AssetsPagePanelController> {
elevation: 0, elevation: 0,
title: Row( title: Row(
children: [ children: [
const Text("Теги:"), const Text("Tags:"),
Obx( Obx(
() => FastChipsInput( () => FastChipsInput(
name: "FastChipsInput", name: "FastChipsInput",
@ -497,13 +496,13 @@ class AssetsPagePanel extends GetView<AssetsPagePanelController> {
horizontalScrollController: controller.scrollController, horizontalScrollController: controller.scrollController,
columns: const [ columns: const [
DataColumn2(label: Text(""), fixedWidth: 16), DataColumn2(label: Text(""), fixedWidth: 16),
DataColumn2(label: Text("Имя файла"), size: ColumnSize.M), DataColumn2(label: Text("Filename"), size: ColumnSize.M),
DataColumn2(label: Text("Описание"), size: ColumnSize.L), DataColumn2(label: Text("Description"), size: ColumnSize.L),
DataColumn2(label: Text("ID файла"), size: ColumnSize.M), DataColumn2(label: Text("File ID"), size: ColumnSize.M),
DataColumn2(label: Text("Теги"), size: ColumnSize.L), DataColumn2(label: Text("Tags"), size: ColumnSize.L),
DataColumn2(label: Text("Действия")), DataColumn2(label: Text("Actions")),
], ],
empty: const Text("Ресурсы не найдены"), empty: const Text("No assets found"),
rows: controller.assetsList rows: controller.assetsList
.where((element) { .where((element) {
if (controller.filterTags.isEmpty) return true; if (controller.filterTags.isEmpty) return true;

View file

@ -7,7 +7,7 @@ class NonePanel extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Center( return Center(
child: Text( child: Text(
"Используйте меню слева для навигации", 'Use the menu for navigation',
style: Theme.of(context).textTheme.headlineSmall, style: Theme.of(context).textTheme.headlineSmall,
), ),
); );

View file

@ -1,10 +1,5 @@
import 'package:flutter/services.dart';
import 'package:flu_console/flu_console.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:tuuli_app/api_controller.dart';
import 'package:tuuli_app/pages/home_page.dart';
class SettingsPanel extends StatefulWidget { class SettingsPanel extends StatefulWidget {
const SettingsPanel({super.key}); const SettingsPanel({super.key});
@ -21,53 +16,21 @@ class _SettingsPanelState extends State<SettingsPanel> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView(
child: IntrinsicHeight(
child: _buildBody(),
),
);
}
Widget _buildBody() {
return Column( return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Text("Ключ доступа пользователя:") Text(
.textStyle(Get.textTheme.bodySmall!), 'Settings',
[ style: Theme.of(context).textTheme.headlineSmall,
Text(ApiController.to.token) ),
.textStyle(Get.textTheme.titleSmall!)
.expanded(),
IconButton(
onPressed: () async {
await Clipboard.setData(
ClipboardData(text: ApiController.to.token),
);
Get.snackbar(
"Скопировано",
"Ключ скопирован в буфер обмена",
snackPosition: SnackPosition.BOTTOM,
);
},
icon: const Icon(Icons.copy),
),
].toRow(),
const SizedBox(height: 16),
[
TextFormField(
enabled: false,
decoration: const InputDecoration(
labelText: 'Адрес бэкенда',
hintText: 'Введите адрес бэкенда',
),
initialValue: ApiController.to.endPoint,
).expanded(),
ElevatedButton(
onPressed: () => Get.find<HomePageController>().logout(),
child: const Text("Выйти и изменить"),
)
].toRow(),
const SizedBox(height: 16),
[
ElevatedButton(
onPressed: () => Get.bottomSheet(const LogPrintPanel()),
child: const Text("Показать лог приложения"),
).expanded(),
].toRow(),
], ],
).paddingAll(8); );
} }
} }

View file

@ -29,7 +29,7 @@ class TablesListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
_tables.clear(); _tables.clear();
@ -38,18 +38,18 @@ class TablesListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка получения таблиц", "Error trying to get tables",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка получения таблиц", "Error trying to get tables",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка получения таблиц", "Error trying to get tables",
"$e", "$e",
); );
} }
@ -68,31 +68,6 @@ class TablesListPanelController extends GetxController {
} }
Future<void> deleteTable(TableDefinition table) async { Future<void> deleteTable(TableDefinition table) async {
final accept = await Get.dialog<bool>(
AlertDialog(
title: const Text("Удалить таблицу"),
content: Text(
"Вы действительно хотите удалить таблицу ${table.tableName.pascalCase}?",
),
actions: [
TextButton(
onPressed: () {
Get.back(result: false);
},
child: const Text("Отменить"),
),
TextButton(
onPressed: () {
Get.back(result: true);
},
child: const Text("Удалить"),
),
],
),
);
if (accept != true) return;
try { try {
final resp = await ApiController.to.apiClient.dropTable( final resp = await ApiController.to.apiClient.dropTable(
tableName: table.tableName, tableName: table.tableName,
@ -100,30 +75,30 @@ class TablesListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
Get.snackbar( Get.snackbar(
"Таблица удалена", "Table deleted",
"Таблица ${table.tableName.pascalCase} была удалена", "${table.tableName.pascalCase} was deleted",
); );
refreshData(); refreshData();
} on DioError catch (e) { } on DioError catch (e) {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка удаления таблицы", "Error trying to delete table",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка удаления таблицы", "Error trying to delete table",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка удаления таблицы", "Error trying to delete table",
"$e", "$e",
); );
} }
@ -226,7 +201,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
Row( Row(
children: [ children: [
Text( Text(
table.system ? "Системная" : "Пользовательская", table.system ? "System" : "Userland",
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
), ),
@ -236,7 +211,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
Row( Row(
children: [ children: [
Text( Text(
"${table.parsedColumns.length} колонок(ки)", "${table.parsedColumns.length} column(s)",
style: const TextStyle( style: const TextStyle(
fontSize: 11, fontSize: 11,
fontStyle: FontStyle.italic, fontStyle: FontStyle.italic,
@ -247,7 +222,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
if (!table.system) if (!table.system)
ElevatedButton( ElevatedButton(
onPressed: () => controller.deleteTable(table), onPressed: () => controller.deleteTable(table),
child: const Text("Удалить"), child: const Text("Delete"),
).paddingOnly(top: 8) ).paddingOnly(top: 8)
], ],
), ),

View file

@ -1,3 +1,5 @@
import 'package:built_collection/built_collection.dart';
import 'package:built_value/json_object.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -66,7 +68,7 @@ class UserListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
_users.clear(); _users.clear();
@ -80,18 +82,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка получения пользователей", "Error trying to get users",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка получения пользователей", "Error trying to get users",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка получения пользователей", "Error trying to get users",
"$e", "$e",
); );
} }
@ -108,7 +110,7 @@ class UserListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
_groups.clear(); _groups.clear();
@ -121,18 +123,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка получения групп пользователей", "Error trying to get groups",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка получения групп пользователей", "Error trying to get groups",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка получения групп пользователей", "Error trying to get groups",
"$e", "$e",
); );
} }
@ -147,8 +149,8 @@ class UserListPanelController extends GetxController {
final accept = await Get.dialog<bool>( final accept = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: user == null title: user == null
? const Text("Создание нового пользователя") ? const Text("Create new user")
: const Text("Редактирование пользователя"), : const Text("Edit user"),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -157,14 +159,14 @@ class UserListPanelController extends GetxController {
? TextEditingController(text: user.username) ? TextEditingController(text: user.username)
: null, : null,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Логин", labelText: "Username",
), ),
readOnly: user != null, readOnly: user != null,
onChanged: (value) => username.value = value, onChanged: (value) => username.value = value,
), ),
TextField( TextField(
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Пароль", labelText: "Password",
), ),
obscureText: true, obscureText: true,
onChanged: (value) => password.value = value, onChanged: (value) => password.value = value,
@ -174,12 +176,11 @@ class UserListPanelController extends GetxController {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: child: user == null ? const Text("Create") : const Text("Save"),
user == null ? const Text("Создать") : const Text("Сохранить"),
), ),
], ],
), ),
@ -209,7 +210,7 @@ class UserListPanelController extends GetxController {
} }
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
refreshData(); refreshData();
@ -217,18 +218,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка создания пользователя", "Error trying to create user",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка создания пользователя", "Error trying to create user",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка создания пользователя", "Error trying to create user",
"$e", "$e",
); );
} }
@ -239,19 +240,19 @@ class UserListPanelController extends GetxController {
final groupDescription = "".obs; final groupDescription = "".obs;
final accept = await Get.dialog<bool>( final accept = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Создание группы пользователей"), title: const Text("Create new group"),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
TextField( TextField(
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Название", labelText: "Group name",
), ),
onChanged: (value) => groupName.value = value, onChanged: (value) => groupName.value = value,
), ),
TextField( TextField(
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Описание (опционально)", labelText: "Group description (optional)",
), ),
onChanged: (value) => groupDescription.value = value, onChanged: (value) => groupDescription.value = value,
), ),
@ -260,11 +261,11 @@ class UserListPanelController extends GetxController {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Создать"), child: const Text("Create"),
), ),
], ],
), ),
@ -283,12 +284,12 @@ class UserListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
Get.snackbar( Get.snackbar(
"Группа создана", "Group created",
"Группа $groupName создана", "Group $groupName created",
); );
refreshData(); refreshData();
@ -296,18 +297,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка создания группы пользователей", "Error trying to create group",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка создания группы пользователей", "Error trying to create group",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка создания группы пользователей", "Error trying to create group",
"$e", "$e",
); );
} }
@ -330,7 +331,7 @@ class UserListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
final data = respData final data = respData
@ -355,7 +356,7 @@ class UserListPanelController extends GetxController {
final selectedUser = await Get.dialog<UserDefinition>( final selectedUser = await Get.dialog<UserDefinition>(
AlertDialog( AlertDialog(
title: const Text("Какого пользователя добавить в группу"), title: const Text("Select user to add to group"),
content: SizedBox( content: SizedBox(
width: 400, width: 400,
height: 400, height: 400,
@ -373,7 +374,7 @@ class UserListPanelController extends GetxController {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: null), onPressed: () => Get.back(result: null),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
], ],
), ),
@ -392,12 +393,12 @@ class UserListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
Get.snackbar( Get.snackbar(
"Пользователь добавлен в группу", "User added to group",
"Пользователь ${selectedUser.username} добавлен в группу ${group.name}", "User ${selectedUser.username} added to group ${group.name}",
); );
refreshData(); refreshData();
@ -405,18 +406,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка добавления пользователя в группу", "Error trying to add user to group",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка добавления пользователя в группу", "Error trying to add user to group",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка добавления пользователя в группу", "Error trying to add user to group",
"$e", "$e",
); );
} }
@ -428,17 +429,17 @@ class UserListPanelController extends GetxController {
) async { ) async {
final accept = await Get.dialog<bool>( final accept = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Удаление пользователя из группы"), title: const Text("Remove user from group"),
content: const Text( content: const Text(
"Вы действительно хотите удалить этого пользователя из группы?"), "Are you sure you want to remove this user from the group?"),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Удалить"), child: const Text("Remove"),
), ),
], ],
), ),
@ -465,12 +466,12 @@ class UserListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("В ответе нет данных"); throw Exception("No data in response");
} }
Get.snackbar( Get.snackbar(
"Пользователь удалён из группы", "User removed from group",
"Пользователь ${user.username} удалён из группы ${group.name}", "User ${user.username} removed from group ${group.name}",
); );
refreshData(); refreshData();
@ -478,18 +479,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка удаления пользователя из группы", "Error trying to remove user from group",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка удаления пользователя из группы", "Error trying to remove user from group",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка удаления пользователя из группы", "Error trying to remove user from group",
"$e", "$e",
); );
} }
@ -498,16 +499,17 @@ class UserListPanelController extends GetxController {
Future<void> deleteGroup(GroupDefinition group) async { Future<void> deleteGroup(GroupDefinition group) async {
final accept = await Get.dialog<bool>( final accept = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Удаление группы"), title: const Text("Delete group"),
content: const Text("Вы действительно хотите удалить эту группу?"), content: const Text(
"Are you sure you want to delete this group? This action cannot be undone."),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Удалить"), child: const Text("Delete"),
), ),
], ],
), ),
@ -528,7 +530,7 @@ class UserListPanelController extends GetxController {
); );
if (resp1.data == null) { if (resp1.data == null) {
throw Exception("Не удалось удалить пользователей из группы"); throw Exception("Could not delete users from group");
} }
final resp2 = await ApiController.to.apiClient.deleteItemFromTable( final resp2 = await ApiController.to.apiClient.deleteItemFromTable(
@ -543,12 +545,12 @@ class UserListPanelController extends GetxController {
); );
if (resp2.data == null) { if (resp2.data == null) {
throw Exception("Не удалось удалить группу пользователей"); throw Exception("Could not delete group");
} }
Get.snackbar( Get.snackbar(
"Группа пользователей удалена", "Group deleted",
"Группа ${group.name} удалена", "Group ${group.name} deleted",
); );
refreshData(); refreshData();
@ -556,18 +558,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка удаления группы пользователей", "Error trying to delete group",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка удаления группы пользователей", "Error trying to delete group",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка удаления группы пользователей", "Error trying to delete group",
"$e", "$e",
); );
} }
@ -580,18 +582,19 @@ class UserListPanelController extends GetxController {
Future<void> deleteUser(UserDefinition user) async { Future<void> deleteUser(UserDefinition user) async {
final accept = await Get.dialog<bool>( final accept = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Удалить пользователя"), title: const Text("Delete user"),
content: const Text( content: const Text(
"Вы уверены, что хотите удалить этого пользователя?", "Are you sure you want to delete this user? This action cannot be undone.\n"
"Note: This will not remove references to this user in other tables.",
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Удалить"), child: const Text("Delete"),
), ),
], ],
), ),
@ -612,7 +615,7 @@ class UserListPanelController extends GetxController {
); );
if (resp1.data == null) { if (resp1.data == null) {
throw Exception("Не удалось удалить пользователя из групп"); throw Exception("Could not delete users from group");
} }
final resp2 = await ApiController.to.apiClient.removeUser( final resp2 = await ApiController.to.apiClient.removeUser(
@ -620,12 +623,12 @@ class UserListPanelController extends GetxController {
); );
if (resp2.data == null) { if (resp2.data == null) {
throw Exception("Не удалось удалить пользователя"); throw Exception("Could not delete group");
} }
Get.snackbar( Get.snackbar(
"Пользователь удалён", "User deleted",
"Пользователь ${user.username} удалён", "User ${user.username} deleted",
); );
refreshData(); refreshData();
@ -633,18 +636,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data; final respData = e.response?.data;
if (respData != null) { if (respData != null) {
Get.snackbar( Get.snackbar(
"Ошибка удаления пользователя", "Error trying to delete user",
"${respData['error']}", "${respData['error']}",
); );
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка удаления пользователя", "Error trying to delete user",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка удаления пользователя", "Error trying to delete user",
"$e", "$e",
); );
} }
@ -671,11 +674,11 @@ class UsersListPanel extends GetView<UserListPanelController> {
items: const [ items: const [
DropdownMenuItem( DropdownMenuItem(
value: UserListPanelTab.users, value: UserListPanelTab.users,
child: Text("Пользователи"), child: Text("Users"),
), ),
DropdownMenuItem( DropdownMenuItem(
value: UserListPanelTab.groups, value: UserListPanelTab.groups,
child: Text("Группы"), child: Text("Groups"),
), ),
], ],
value: controller.currentTab, value: controller.currentTab,
@ -718,12 +721,11 @@ class UsersListPanel extends GetView<UserListPanelController> {
); );
} }
Widget get usersPanel => Obx(() => controller.users.isEmpty Widget get usersPanel => Obx(() =>
? whenNoSomething("Пользователи не найдены") controller.users.isEmpty ? whenNoSomething("No users found") : cardList);
: cardList);
Widget get groupsPanel => Obx(() => controller.groups.isEmpty Widget get groupsPanel => Obx(() => controller.groups.isEmpty
? whenNoSomething("Группы не найдены") ? whenNoSomething("No groups found")
: groupsList); : groupsList);
Widget whenNoSomething(message) => Center( Widget whenNoSomething(message) => Center(
@ -783,7 +785,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
ElevatedButton.icon( ElevatedButton.icon(
onPressed: () => controller.editUser(user), onPressed: () => controller.editUser(user),
icon: const Icon(Icons.edit_attributes), icon: const Icon(Icons.edit_attributes),
label: const Text("Редактировать"), label: const Text("Edit user"),
).paddingAll(8).expanded(), ).paddingAll(8).expanded(),
Obx( Obx(
() { () {
@ -805,7 +807,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
final btn = ElevatedButton.icon( final btn = ElevatedButton.icon(
onPressed: () => controller.deleteUser(user), onPressed: () => controller.deleteUser(user),
icon: const Icon(Icons.delete_forever), icon: const Icon(Icons.delete_forever),
label: const Text("Удалить"), label: const Text("Delete user"),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.redAccent, backgroundColor: Colors.redAccent,
), ),
@ -813,7 +815,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
if (isAdmin) { if (isAdmin) {
return Tooltip( return Tooltip(
message: "Данный пользователь является администратором", message: "Please note that this user is an admin",
child: btn, child: btn,
).paddingAll(8).expanded(); ).paddingAll(8).expanded();
} }
@ -874,7 +876,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
final groupData = controller.usersInGroups[group]; final groupData = controller.usersInGroups[group];
if (group.id == 1) { if (group.id == 1) {
return const ListTile( return const ListTile(
title: Text("В эту группу нельзя добавить пользователей"), title: Text("No users can be added to this group"),
); );
} }
if (groupData == null) { if (groupData == null) {
@ -884,7 +886,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
} }
if (groupData.isEmpty) { if (groupData.isEmpty) {
return const ListTile( return const ListTile(
title: Text("В группе нет пользователей"), title: Text("No users in group"),
); );
} }
return ListView.builder( return ListView.builder(
@ -895,7 +897,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
final isYou = user.accessToken == ApiController.to.token; final isYou = user.accessToken == ApiController.to.token;
return ListTile( return ListTile(
title: Text(user.username), title: Text(user.username),
subtitle: isYou ? const Text("Вы") : null, subtitle: isYou ? const Text("You") : null,
trailing: isYou && trailing: isYou &&
(group.id == 2 || (group.id == 2 ||
group.name.toLowerCase() == "admin") group.name.toLowerCase() == "admin")

View file

@ -47,8 +47,8 @@ class LoginPageController extends GetxController {
}); });
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка входа", "Login failed",
resp.statusMessage ?? "Неизвестная ошибка", resp.statusMessage ?? "Unknown error",
); );
} }
} on DioError catch (e) { } on DioError catch (e) {
@ -57,19 +57,19 @@ class LoginPageController extends GetxController {
final error = errorData["error"]; final error = errorData["error"];
if (error != null) { if (error != null) {
Get.snackbar( Get.snackbar(
"Ошибка входа", "Login failed",
"$error", "$error",
); );
} }
} else { } else {
Get.snackbar( Get.snackbar(
"Ошибка входа", "Login failed",
"$e", "$e",
); );
} }
} catch (e) { } catch (e) {
Get.snackbar( Get.snackbar(
"Ошибка входа", "Login failed",
"$e", "$e",
); );
} }
@ -109,14 +109,14 @@ class LoginPage extends GetView<LoginPageController> {
TextFormField( TextFormField(
enabled: !controller.submitted, enabled: !controller.submitted,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Адрес бэкенда', labelText: 'Endpoint',
hintText: 'Введите адрес бэкенда Tuuli', hintText: 'Enter Tuuli Endpoint',
), ),
initialValue: ApiController.to.endPoint, initialValue: ApiController.to.endPoint,
onChanged: (value) => controller.endpoint = value, onChanged: (value) => controller.endpoint = value,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Пожалуйста, введите адрес бэкенда Tuuli'; return 'Please enter Tuuli Endpoint';
} }
return null; return null;
}, },
@ -124,13 +124,13 @@ class LoginPage extends GetView<LoginPageController> {
TextFormField( TextFormField(
enabled: !controller.submitted, enabled: !controller.submitted,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Логин', labelText: 'Login',
hintText: 'Введите логин', hintText: 'Enter your username',
), ),
onChanged: (value) => controller.username = value, onChanged: (value) => controller.username = value,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Пожалуйста, введите логин'; return 'Please enter your Login';
} }
return null; return null;
}, },
@ -139,13 +139,13 @@ class LoginPage extends GetView<LoginPageController> {
obscureText: true, obscureText: true,
enabled: !controller.submitted, enabled: !controller.submitted,
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: 'Пароль', labelText: 'Password',
hintText: 'Введите пароль', hintText: 'Enter your password',
), ),
onChanged: (value) => controller.password = value, onChanged: (value) => controller.password = value,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Пожалуйста, введите пароль'; return 'Please enter your password';
} }
return null; return null;
}, },
@ -156,7 +156,7 @@ class LoginPage extends GetView<LoginPageController> {
!controller.isFormValid || controller.submitted !controller.isFormValid || controller.submitted
? null ? null
: () => controller.submitForm(), : () => controller.submitForm(),
child: const Text('Войти'), child: const Text('Login'),
), ),
], ],
), ),

View file

@ -15,7 +15,7 @@ class _NotFoundPageState extends State<NotFoundPage>
return Scaffold( return Scaffold(
body: Center( body: Center(
child: Text( child: Text(
'Страница не найдена', 'Page not found',
style: Theme.of(context).textTheme.headlineMedium, style: Theme.of(context).textTheme.headlineMedium,
), ),
), ),
@ -30,14 +30,14 @@ class _NotFoundPageState extends State<NotFoundPage>
onPressed: () { onPressed: () {
Get.back(canPop: false); Get.back(canPop: false);
}, },
child: const Text('Назад'), child: const Text('Go back'),
), ),
const SizedBox(width: 16), const SizedBox(width: 16),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
Get.offAllNamed("/"); Get.offAllNamed("/");
}, },
child: const Text('Домой'), child: const Text('Go home'),
), ),
], ],
), ),

View file

@ -53,7 +53,7 @@ class AudioPlayerWidget extends GetView<AudioPlayerWidgetController> {
icon: const Icon(Icons.play_arrow), icon: const Icon(Icons.play_arrow),
), ),
), ),
title: const Text("Проигрывается"), title: const Text("Playing"),
subtitle: Text(controller.title), subtitle: Text(controller.title),
).card().paddingAll(16).center(); ).card().paddingAll(16).center();
} }

View file

@ -6,7 +6,7 @@ Future<String?> showStringInputDialog({String? originalValue}) async {
final strVal = (originalValue ?? "").obs; final strVal = (originalValue ?? "").obs;
return await Get.dialog<String>( return await Get.dialog<String>(
AlertDialog( AlertDialog(
title: const Text("Введите строку"), title: const Text("Enter a string"),
content: TextField( content: TextField(
controller: TextEditingController(text: originalValue), controller: TextEditingController(text: originalValue),
onChanged: (value) { onChanged: (value) {
@ -18,13 +18,13 @@ Future<String?> showStringInputDialog({String? originalValue}) async {
onPressed: () { onPressed: () {
Get.back(result: null); Get.back(result: null);
}, },
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
Get.back(result: strVal.value); Get.back(result: strVal.value);
}, },
child: const Text("Ок"), child: const Text("OK"),
), ),
], ],
), ),
@ -35,7 +35,7 @@ Future<double?> showDoubleInputDialog({double? originalValue}) async {
final strVal = (originalValue?.toString() ?? "").obs; final strVal = (originalValue?.toString() ?? "").obs;
return await Get.dialog<double>( return await Get.dialog<double>(
AlertDialog( AlertDialog(
title: const Text("Введите плавающее число"), title: const Text("Enter a number"),
content: FastTextField( content: FastTextField(
name: "Number", name: "Number",
initialValue: originalValue?.toString(), initialValue: originalValue?.toString(),
@ -43,11 +43,11 @@ Future<double?> showDoubleInputDialog({double? originalValue}) async {
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return "Пожалуйста, введите плавающее число"; return "Please enter a number";
} }
final parsed = double.tryParse(value); final parsed = double.tryParse(value);
if (parsed == null) { if (parsed == null) {
return "Пожалуйста, введите настоящее плавающее число"; return "Please enter a valid number";
} }
return null; return null;
}, },
@ -60,7 +60,7 @@ Future<double?> showDoubleInputDialog({double? originalValue}) async {
onPressed: () { onPressed: () {
Get.back(result: null); Get.back(result: null);
}, },
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
@ -71,7 +71,7 @@ Future<double?> showDoubleInputDialog({double? originalValue}) async {
Get.back(result: null); Get.back(result: null);
} }
}, },
child: const Text("Ок"), child: const Text("OK"),
), ),
], ],
), ),
@ -82,7 +82,7 @@ Future<int?> showIntInputDialog({int? originalValue}) async {
final strVal = (originalValue?.toString() ?? "").obs; final strVal = (originalValue?.toString() ?? "").obs;
return await Get.dialog<int>( return await Get.dialog<int>(
AlertDialog( AlertDialog(
title: const Text("Введите целое число"), title: const Text("Enter a number"),
content: FastTextField( content: FastTextField(
name: "Number", name: "Number",
initialValue: originalValue?.toString(), initialValue: originalValue?.toString(),
@ -90,11 +90,11 @@ Future<int?> showIntInputDialog({int? originalValue}) async {
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return "Пожалуйста, введите целое число"; return "Please enter a number";
} }
final parsed = int.tryParse(value); final parsed = int.tryParse(value);
if (parsed == null) { if (parsed == null) {
return "Пожалуйста, введите настоящее целое число"; return "Please enter a valid number";
} }
return null; return null;
}, },
@ -107,7 +107,7 @@ Future<int?> showIntInputDialog({int? originalValue}) async {
onPressed: () { onPressed: () {
Get.back(result: null); Get.back(result: null);
}, },
child: const Text("Отменить"), child: const Text("Cancel"),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
@ -118,7 +118,7 @@ Future<int?> showIntInputDialog({int? originalValue}) async {
Get.back(result: null); Get.back(result: null);
} }
}, },
child: const Text("Ок"), child: const Text("OK"),
), ),
], ],
), ),

View file

@ -305,14 +305,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
flu_console:
dependency: "direct main"
description:
name: flu_console
sha256: a6d9c70366fffd69c69f486677f86ec290dd72ca7cb1110271d6ddeda51ca769
url: "https://pub.dev"
source: hosted
version: "0.0.1"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -480,14 +472,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
logger:
dependency: transitive
description:
name: logger
sha256: db2ff852ed77090ba9f62d3611e4208a3d11dfa35991a81ae724c113fcb3e3f7
url: "https://pub.dev"
source: hosted
version: "1.3.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:

View file

@ -17,7 +17,6 @@ dependencies:
data_table_2: ^2.4.2 data_table_2: ^2.4.2
dio: ^5.1.1 dio: ^5.1.1
file_icon: ^1.0.0 file_icon: ^1.0.0
flu_console: ^0.0.1
flutter_chips_input: ^2.0.0 flutter_chips_input: ^2.0.0
flutter_fast_forms: ^10.0.0 flutter_fast_forms: ^10.0.0
get: ^4.6.5 get: ^4.6.5

View file

@ -7,15 +7,12 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <audioplayers_windows/audioplayers_windows_plugin.h> #include <audioplayers_windows/audioplayers_windows_plugin.h>
#include <flu_console/flu_console_plugin_c_api.h>
#include <irondash_engine_context/irondash_engine_context_plugin_c_api.h> #include <irondash_engine_context/irondash_engine_context_plugin_c_api.h>
#include <super_native_extensions/super_native_extensions_plugin_c_api.h> #include <super_native_extensions/super_native_extensions_plugin_c_api.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
AudioplayersWindowsPluginRegisterWithRegistrar( AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
FluConsolePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FluConsolePluginCApi"));
IrondashEngineContextPluginCApiRegisterWithRegistrar( IrondashEngineContextPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi")); registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi"));
SuperNativeExtensionsPluginCApiRegisterWithRegistrar( SuperNativeExtensionsPluginCApiRegisterWithRegistrar(

View file

@ -4,7 +4,6 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows audioplayers_windows
flu_console
irondash_engine_context irondash_engine_context
super_native_extensions super_native_extensions
) )