Compare commits

...
Sign in to create a new pull request.

19 commits

Author SHA1 Message Date
30f15dc40c Мелкие правки по переводу 2023-05-18 12:20:31 +07:00
159a88f006 Почистил импорты 2023-05-17 21:06:09 +07:00
1051ac57e0 Перевёл виджеты ввода 2023-05-17 21:05:19 +07:00
10ac93eeb6 Перевёл виджет аудиоплеера 2023-05-17 21:03:37 +07:00
0a37ce249e Перевёл 404 2023-05-17 21:02:53 +07:00
d9e0f9bdfd Перевёл страницу входа 2023-05-17 21:02:20 +07:00
35712844c8 Перевёл домашнюю страницу 2023-05-17 21:00:36 +07:00
31190a78a7 Перевёл страницу проверки токена 2023-05-17 20:59:05 +07:00
89bd7cbfcb Перевёл панель пользователей 2023-05-17 20:58:26 +07:00
93b599137b Перевёл список таблиц 2023-05-17 20:49:12 +07:00
1eccf30c10 Перевёл настройки 2023-05-17 20:47:07 +07:00
374196699a Перевёл пустую страницу 2023-05-17 20:44:38 +07:00
8a3030addf Перевёл ассеты 2023-05-17 20:44:12 +07:00
7f7bbd9441 Перевёл диалог таблицы 2023-05-17 20:38:02 +07:00
badbf6c986 Перевёл управление доступом 2023-05-17 20:34:21 +07:00
40bb982c74 Перевёл создание таблиц 2023-05-17 20:29:00 +07:00
53320d9d0f Login page content 2023-05-08 14:04:30 +07:00
12ff1e953a Added confirmation before table deletion 2023-05-08 13:04:05 +07:00
a01a66c88d Merge branch 'revolution' into 'master'
Revolution

See merge request nuark/tuuli_app!1
2023-05-08 12:50:15 +07:00
21 changed files with 377 additions and 305 deletions

View file

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

View file

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

View file

@ -1,11 +1,10 @@
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';
@ -26,7 +25,9 @@ void main() async {
fenix: true, fenix: true,
); );
runApp(const MainApp()); FluConsole.run(() {
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: "Text", TextColumnDefinition: "Текст",
BooleanColumnDefinition: "Boolean", BooleanColumnDefinition: "Логическое значение",
TimestampColumnDefinition: "Date/Time", TimestampColumnDefinition: "Дата/Время",
DoubleColumnDefinition: "Double", DoubleColumnDefinition: "Число с плавающей точкой",
IntegerColumnDefinition: "Integer", IntegerColumnDefinition: "Целое число",
UserRefColumnDefinition: "User reference", UserRefColumnDefinition: "Ссылка на пользователя",
AssetRefColumnDefinition: "Asset reference", AssetRefColumnDefinition: "Ссылка на ресурс",
}; };
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("No data in response"); throw Exception("В ответе нет данных");
} }
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("Create new column"), title: const Text("Создать новую колонку"),
content: Wrap( content: Wrap(
runSpacing: 16, runSpacing: 16,
children: [ children: [
FastTextField( FastTextField(
name: "ColumnName", name: "ColumnName",
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Column name", labelText: "Название",
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("Select column type"), hint: const Text("Тип"),
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: "Is Unique", titleText: "Уникальное значение?",
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('Close'), child: const Text("Отменить"),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
Get.back(result: true); Get.back(result: true);
}, },
child: const Text('Create'), child: const Text("Создать"),
), ),
], ],
), ),
@ -129,42 +129,42 @@ class CreateTableController extends GetxController {
columnName: columnName.value, columnName: columnName.value,
); );
break; break;
case "Text": case "Текст":
ct = TextColumnDefinition( ct = TextColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Boolean": case "Логическое значение":
ct = BooleanColumnDefinition( ct = BooleanColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Date/Time": case "Дата/Время":
ct = TimestampColumnDefinition( ct = TimestampColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Double": case "Число с плавающей точкой":
ct = DoubleColumnDefinition( ct = DoubleColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "Integer": case "Целое число":
ct = IntegerColumnDefinition( ct = IntegerColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
isUnique: columnIsUnique.value, isUnique: columnIsUnique.value,
); );
break; break;
case "User reference": case "Ссылка на пользователя":
ct = UserRefColumnDefinition( ct = UserRefColumnDefinition(
columnName: columnName.value, columnName: columnName.value,
); );
break; break;
case "Asset reference": case "Ссылка на ресурс":
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('Creating new table'), title: const Text("Создать новую таблицу"),
content: Column( content: Column(
children: [ children: [
TextField( TextField(
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Table name", labelText: "Название",
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("Create column"), child: const Text("Создать колонку"),
).expanded() ).expanded()
].toRow(), ].toRow(),
], ],
@ -226,14 +226,14 @@ class CreateTableDialog extends GetView<CreateTableController> {
onPressed: () { onPressed: () {
Get.back(); Get.back();
}, },
child: const Text('Close'), child: const Text("Закрыть"),
), ),
Obx( Obx(
() => TextButton( () => TextButton(
onPressed: controller.columnsDefinition.isEmpty onPressed: controller.columnsDefinition.isEmpty
? null ? null
: () => controller.createTable(), : () => controller.createTable(),
child: const Text('Create'), child: const Text("Создать"),
), ),
), ),
], ],

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("No data in response"); throw Exception("В ответе нет данных");
} }
_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("No data in response"); throw Exception("В ответе нет данных");
} }
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("No data in response"); throw Exception("В ответе нет данных");
} }
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("Allowed columns"), title: const Text("Разрешённые колонки"),
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("Swap all"), child: const Text("Перевернуть"),
), ),
...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("Cancel"), child: const Text("Отменить"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Ok"), child: const Text("Ок"),
), ),
], ],
), ),
@ -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("Error"), title: const Text("Ошибка"),
content: const Text("At least one column must be selected"), content: const Text("Необходимо выбрать хотя бы одну колонку"),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(), onPressed: () => Get.back(),
child: const Text("Ok"), child: const Text("Ок"),
), ),
], ],
), ),
@ -306,7 +306,7 @@ class GroupACLController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("No data in response"); throw Exception("В ответе нет данных");
} }
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('Group ACL'), title: const Text('Доступ группы'),
content: Obx( content: Obx(
() => DataTable2( () => DataTable2(
columns: const [ columns: const [
DataColumn2(label: Text('Table'), size: ColumnSize.L), DataColumn2(label: Text('Таблица'), size: ColumnSize.L),
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), DataColumn2(label: Text('Колонки'), size: ColumnSize.S),
], ],
empty: const Text("No tables"), empty: const Text("Нет таблиц"),
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('Close'), child: const Text("Закрыть"),
), ),
], ],
); );

View file

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

View file

@ -1,6 +1,5 @@
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';
@ -25,11 +24,11 @@ class HomePageController extends GetxController {
String get currentPageName => pageNames[currentPage]!; String get currentPageName => pageNames[currentPage]!;
final pageNames = { final pageNames = {
PageType.none: "Home", PageType.none: "Домашняя",
PageType.tables: "Tables", PageType.tables: "Таблицы",
PageType.users: "Users", PageType.users: "Пользователи",
PageType.assets: "Assets", PageType.assets: "Ресурсы",
PageType.settings: "Settings", PageType.settings: "Настройки",
}; };
@override @override
@ -91,7 +90,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("Tables"), title: const Text("Таблицы"),
onTap: () { onTap: () {
controller.currentPage = PageType.tables; controller.currentPage = PageType.tables;
}, },
@ -101,7 +100,7 @@ class HomePage extends GetView<HomePageController> {
Obx( Obx(
() => ListTile( () => ListTile(
leading: const Icon(Icons.person), leading: const Icon(Icons.person),
title: const Text("Users"), title: const Text("Пользователи"),
onTap: () { onTap: () {
controller.currentPage = PageType.users; controller.currentPage = PageType.users;
}, },
@ -111,7 +110,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("Assets"), title: const Text("Ресурсы"),
onTap: () { onTap: () {
controller.currentPage = PageType.assets; controller.currentPage = PageType.assets;
}, },
@ -121,7 +120,7 @@ class HomePage extends GetView<HomePageController> {
Obx( Obx(
() => ListTile( () => ListTile(
leading: const Icon(Icons.settings), leading: const Icon(Icons.settings),
title: const Text("Settings"), title: const Text("Настройки"),
onTap: () { onTap: () {
controller.currentPage = PageType.settings; controller.currentPage = PageType.settings;
}, },
@ -131,7 +130,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("Logout"), title: const Text("Выйти"),
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("No data in response"); throw Exception("В ответе нет данных");
} }
_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("No data in response"); throw Exception("В ответе нет данных");
} }
_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("Error", value.toString()); Get.snackbar("Ошибка", value.toString());
}, },
); );
}, },
child: const Text("Drop file here") child: const Text("Перенесите файл сюда")
.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("Cancel"), child: const Text("Отменить"),
) )
], ],
), ),
@ -195,7 +195,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("No data in response"); throw Exception("В ответе нет данных");
} }
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("Edit asset"), title: const Text("Изменение ресурса"),
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: "Description", labelText: "Описание",
), ),
), ),
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: "Tags", labelText: "Теги",
), ),
), ),
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))) .map((tag) => Chip(label: Text(tag)).paddingAll(2))
.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("View asset")), child: const Text("Предпросмотр")),
], ],
).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("Cancel"), child: const Text("Отменить"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Confirm"), child: const Text("Подтвердить"),
), ),
], ],
), ),
@ -287,7 +287,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("No data in response"); throw Exception("В ответе нет данных");
} }
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,23 +318,24 @@ class AssetsPagePanelController extends GetxController {
final confirm = await Get.dialog<bool>( final confirm = await Get.dialog<bool>(
AlertDialog( AlertDialog(
title: const Text("Remove asset"), title: const Text("Удаление ресурса"),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Text("You are about to remove an asset."), const Text(
"Вы планируете удалить ресурс. Это действие нельзя отменить."),
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("Check references"), title: const Text("Проверить ссылки"),
), ),
), ),
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("Delete referencing"), title: const Text("Удалить ссылающиеся сущности"),
), ),
), ),
], ],
@ -342,11 +343,11 @@ class AssetsPagePanelController extends GetxController {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Get.back(result: false), onPressed: () => Get.back(result: false),
child: const Text("Cancel"), child: const Text("Отменить"),
), ),
TextButton( TextButton(
onPressed: () => Get.back(result: true), onPressed: () => Get.back(result: true),
child: const Text("Remove"), child: const Text("Удалить"),
), ),
], ],
), ),
@ -363,7 +364,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("No data in response"); throw Exception("В ответе нет данных");
} }
refreshData(); refreshData();
@ -371,18 +372,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",
); );
} }
@ -404,7 +405,7 @@ class AssetsPagePanelController extends GetxController {
url: "${ApiController.to.endPoint}/assets/${e.fid}", url: "${ApiController.to.endPoint}/assets/${e.fid}",
) )
else else
const Text("Unsupported media type") const Text("На данный момент этот тип не поддерживает предпросмотр")
.fontSize(16) .fontSize(16)
.paddingAll(8) .paddingAll(8)
.card() .card()
@ -439,7 +440,7 @@ class AssetsPagePanel extends GetView<AssetsPagePanelController> {
elevation: 0, elevation: 0,
title: Row( title: Row(
children: [ children: [
const Text("Tags:"), const Text("Теги:"),
Obx( Obx(
() => FastChipsInput( () => FastChipsInput(
name: "FastChipsInput", name: "FastChipsInput",
@ -496,13 +497,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("Filename"), size: ColumnSize.M), DataColumn2(label: Text("Имя файла"), size: ColumnSize.M),
DataColumn2(label: Text("Description"), size: ColumnSize.L), DataColumn2(label: Text("Описание"), size: ColumnSize.L),
DataColumn2(label: Text("File ID"), size: ColumnSize.M), DataColumn2(label: Text("ID файла"), size: ColumnSize.M),
DataColumn2(label: Text("Tags"), size: ColumnSize.L), DataColumn2(label: Text("Теги"), size: ColumnSize.L),
DataColumn2(label: Text("Actions")), DataColumn2(label: Text("Действия")),
], ],
empty: const Text("No assets found"), empty: const Text("Ресурсы не найдены"),
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,5 +1,10 @@
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});
@ -16,21 +21,53 @@ 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: [
Text( const Text("Ключ доступа пользователя:")
'Settings', .textStyle(Get.textTheme.bodySmall!),
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("No data in response"); throw Exception("В ответе нет данных");
} }
_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,6 +68,31 @@ 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,
@ -75,30 +100,30 @@ class TablesListPanelController extends GetxController {
final respData = resp.data; final respData = resp.data;
if (respData == null) { if (respData == null) {
throw Exception("No data in response"); throw Exception("В ответе нет данных");
} }
Get.snackbar( Get.snackbar(
"Table deleted", "Таблица удалена",
"${table.tableName.pascalCase} was deleted", "Таблица ${table.tableName.pascalCase} была удалена",
); );
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",
); );
} }
@ -201,7 +226,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
Row( Row(
children: [ children: [
Text( Text(
table.system ? "System" : "Userland", table.system ? "Системная" : "Пользовательская",
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
), ),
@ -211,7 +236,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
Row( Row(
children: [ children: [
Text( Text(
"${table.parsedColumns.length} column(s)", "${table.parsedColumns.length} колонок(ки)",
style: const TextStyle( style: const TextStyle(
fontSize: 11, fontSize: 11,
fontStyle: FontStyle.italic, fontStyle: FontStyle.italic,
@ -222,7 +247,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("Delete"), child: const Text("Удалить"),
).paddingOnly(top: 8) ).paddingOnly(top: 8)
], ],
), ),

View file

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

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('Go back'), child: const Text('Назад'),
), ),
const SizedBox(width: 16), const SizedBox(width: 16),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
Get.offAllNamed("/"); Get.offAllNamed("/");
}, },
child: const Text('Go home'), child: const Text('Домой'),
), ),
], ],
), ),

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("Playing"), title: const Text("Проигрывается"),
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("Enter a string"), title: const Text("Введите строку"),
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("Cancel"), child: const Text("Отменить"),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
Get.back(result: strVal.value); Get.back(result: strVal.value);
}, },
child: const Text("OK"), child: const Text("Ок"),
), ),
], ],
), ),
@ -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("Enter a number"), title: const Text("Введите плавающее число"),
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 "Please enter a number"; return "Пожалуйста, введите плавающее число";
} }
final parsed = double.tryParse(value); final parsed = double.tryParse(value);
if (parsed == null) { if (parsed == null) {
return "Please enter a valid number"; return "Пожалуйста, введите настоящее плавающее число";
} }
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("Cancel"), child: const Text("Отменить"),
), ),
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("OK"), child: const Text("Ок"),
), ),
], ],
), ),
@ -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("Enter a number"), title: const Text("Введите целое число"),
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 "Please enter a number"; return "Пожалуйста, введите целое число";
} }
final parsed = int.tryParse(value); final parsed = int.tryParse(value);
if (parsed == null) { if (parsed == null) {
return "Please enter a valid number"; return "Пожалуйста, введите настоящее целое число";
} }
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("Cancel"), child: const Text("Отменить"),
), ),
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("OK"), child: const Text("Ок"),
), ),
], ],
), ),

View file

@ -305,6 +305,14 @@ 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
@ -472,6 +480,14 @@ 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,6 +17,7 @@ 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,12 +7,15 @@
#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,6 +4,7 @@
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
) )