Compare commits

..

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:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:tuuli_app/api_controller.dart';
import 'package:tuuli_app/pages/checkup_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/not_found_page.dart';
@ -26,7 +25,9 @@ void main() async {
fenix: true,
);
FluConsole.run(() {
runApp(const MainApp());
});
}
class MainApp extends StatelessWidget {

View file

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

View file

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

View file

@ -47,7 +47,7 @@ class GroupACLController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
_tables.clear();
@ -56,18 +56,18 @@ class GroupACLController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to get tables",
"Ошибка запроса таблиц",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to get tables",
"Ошибка запроса таблиц",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to get tables",
"Ошибка запроса таблиц",
"$e",
);
}
@ -96,7 +96,7 @@ class GroupACLController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
if (respData.isNotEmpty) {
@ -111,18 +111,18 @@ class GroupACLController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to get tables access",
"Ошибка запроса информации доступа к таблицам",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to get tables access",
"Ошибка запроса информации доступа к таблицам",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to get tables access",
"Ошибка запроса информации доступа к таблицам",
"$e",
);
}
@ -187,7 +187,7 @@ class GroupACLController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
refreshTableAccess(table);
@ -195,18 +195,18 @@ class GroupACLController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to update tables access",
"Ошибка обновления информации доступа к таблицам",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to update tables access",
"Ошибка обновления информации доступа к таблицам",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to update tables access",
"Ошибка обновления информации доступа к таблицам",
"$e",
);
}
@ -234,7 +234,7 @@ class GroupACLController extends GetxController {
final confirm = await Get.dialog<bool>(
AlertDialog(
title: const Text("Allowed columns"),
title: const Text("Разрешённые колонки"),
content: Obx(
() => Wrap(
children: [
@ -244,7 +244,7 @@ class GroupACLController extends GetxController {
selectedColumns[column] = !selectedColumns[column]!;
}
},
child: const Text("Swap all"),
child: const Text("Перевернуть"),
),
...selectedColumns.entries.map((e) {
return CheckboxListTile(
@ -259,11 +259,11 @@ class GroupACLController extends GetxController {
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: const Text("Cancel"),
child: const Text("Отменить"),
),
TextButton(
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)) {
await Get.dialog(
AlertDialog(
title: const Text("Error"),
content: const Text("At least one column must be selected"),
title: const Text("Ошибка"),
content: const Text("Необходимо выбрать хотя бы одну колонку"),
actions: [
TextButton(
onPressed: () => Get.back(),
child: const Text("Ok"),
child: const Text("Ок"),
),
],
),
@ -306,7 +306,7 @@ class GroupACLController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
refreshTableAccess(table);
@ -314,18 +314,18 @@ class GroupACLController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to update tables access",
"Ошибка обновления информации доступа к таблицам",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to update tables access",
"Ошибка обновления информации доступа к таблицам",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to update tables access",
"Ошибка обновления информации доступа к таблицам",
"$e",
);
}
@ -338,16 +338,16 @@ class GroupACLDialog extends GetView<GroupACLController> {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Group ACL'),
title: const Text('Доступ группы'),
content: Obx(
() => DataTable2(
columns: const [
DataColumn2(label: Text('Table'), size: ColumnSize.L),
DataColumn2(label: Text('Read'), size: ColumnSize.S),
DataColumn2(label: Text('Write'), size: ColumnSize.S),
DataColumn2(label: Text('Allowed columns'), size: ColumnSize.S),
DataColumn2(label: Text('Таблица'), size: ColumnSize.L),
DataColumn2(label: Text('Чтение'), size: ColumnSize.S),
DataColumn2(label: Text('Запись'), size: ColumnSize.S),
DataColumn2(label: Text('Колонки'), size: ColumnSize.S),
],
empty: const Text("No tables"),
empty: const Text("Нет таблиц"),
rows: controller.access.entries.map((e) {
final table = controller.tables.firstWhere(
(element) => element.tableId == e.key,
@ -390,7 +390,7 @@ class GroupACLDialog extends GetView<GroupACLController> {
onPressed: () {
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:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_fast_forms/flutter_fast_forms.dart';
import 'package:get/get.dart';
import 'package:omni_datetime_picker/omni_datetime_picker.dart';
import 'package:recase/recase.dart';
@ -70,7 +69,7 @@ class OpenTableController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
_tableData.clear();
@ -79,18 +78,18 @@ class OpenTableController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to get table data",
"Ошибка получения данных таблицы",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to get table data",
"Ошибка получения данных таблицы",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to get table data",
"Ошибка получения данных таблицы",
"$e",
);
}
@ -101,7 +100,7 @@ class OpenTableController extends GetxController {
final user = await Get.dialog<UserDefinition>(
AlertDialog(
title: const Text("Select user"),
title: const Text("Выберите пользователя"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -110,7 +109,7 @@ class OpenTableController extends GetxController {
username.value = value;
},
decoration: const InputDecoration(
labelText: "Username",
labelText: "Логин",
),
),
Obx(
@ -140,7 +139,7 @@ class OpenTableController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
return respData
@ -187,7 +186,7 @@ class OpenTableController extends GetxController {
onPressed: () {
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>(
AlertDialog(
title: const Text("Select asset"),
title: const Text("Выберите ресурс"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -210,7 +209,7 @@ class OpenTableController extends GetxController {
name.value = value;
},
decoration: const InputDecoration(
labelText: "Filename",
labelText: "Имя файла",
),
),
Obx(
@ -241,7 +240,7 @@ class OpenTableController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
return respData
@ -291,7 +290,7 @@ class OpenTableController extends GetxController {
onPressed: () {
Get.back(result: null);
},
child: const Text("Cancel"),
child: const Text("Отменить"),
),
],
),
@ -309,7 +308,7 @@ class OpenTableController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
clearNewRowData();
@ -318,18 +317,18 @@ class OpenTableController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to get table data",
"Ошибка получения данных таблицы",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to get table data",
"Ошибка получения данных таблицы",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to get table data",
"Ошибка получения данных таблицы",
"$e",
);
}
@ -357,7 +356,7 @@ class OpenTableController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
refreshTableData();
@ -365,18 +364,18 @@ class OpenTableController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to update table data",
"Ошибка обновления данных таблицы",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to update table data",
"Ошибка обновления данных таблицы",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to update table data",
"Ошибка обновления данных таблицы",
"$e",
);
}
@ -408,7 +407,7 @@ class OpenTableController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
refreshTableData();
@ -416,18 +415,18 @@ class OpenTableController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to update table data",
"Ошибка удаления данных таблицы",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to update table data",
"Ошибка удаления данных таблицы",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to update table data",
"Ошибка удаления данных таблицы",
"$e",
);
}
@ -465,9 +464,9 @@ class OpenTableDialog extends GetView<OpenTableController> {
col.name.pascalCase,
),
),
const DataColumn(label: Text("Actions")),
const DataColumn(label: Text("Действия")),
],
empty: const Text("No data"),
empty: const Text("Нет данных"),
rows: [
DataRow(
cells: [
@ -699,7 +698,7 @@ class OpenTableDialog extends GetView<OpenTableController> {
final msg = () {
final dt = e[col.name];
if (dt == null) {
return "#error#";
return "###";
}
if (dt is String) {
final rdt = DateTime.parse(dt);
@ -805,7 +804,7 @@ class OpenTableDialog extends GetView<OpenTableController> {
if (ud == null ||
ud.isEmpty ||
ud.first["username"] == null) {
return "#error#";
return "###";
}
controller.putUserInCache(UserDefinition(
@ -824,9 +823,9 @@ class OpenTableDialog extends GetView<OpenTableController> {
}
return Tooltip(
message: snapshot.data ?? "#error#",
message: snapshot.data ?? "###",
child: Text(
snapshot.data ?? "#error#",
snapshot.data ?? "###",
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
@ -873,7 +872,7 @@ class OpenTableDialog extends GetView<OpenTableController> {
if (ad == null ||
ad.isEmpty ||
ad.first["name"] == null) {
return "#error#";
return "###";
}
controller.putAssetInCache(Asset(
@ -894,9 +893,9 @@ class OpenTableDialog extends GetView<OpenTableController> {
}
return Tooltip(
message: snapshot.data ?? "#error#",
message: snapshot.data ?? "###",
child: Text(
snapshot.data ?? "#error#",
snapshot.data ?? "###",
overflow: TextOverflow.ellipsis,
maxLines: 1,
),

View file

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

View file

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

View file

@ -7,7 +7,7 @@ class NonePanel extends StatelessWidget {
Widget build(BuildContext context) {
return Center(
child: Text(
'Use the menu for navigation',
"Используйте меню слева для навигации",
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: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 {
const SettingsPanel({super.key});
@ -16,21 +21,53 @@ class _SettingsPanelState extends State<SettingsPanel> {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: IntrinsicHeight(
child: _buildBody(),
),
);
}
Widget _buildBody() {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Settings',
style: Theme.of(context).textTheme.headlineSmall,
),
],
const Text("Ключ доступа пользователя:")
.textStyle(Get.textTheme.bodySmall!),
[
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;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
_tables.clear();
@ -38,18 +38,18 @@ class TablesListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to get tables",
"Ошибка получения таблиц",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to get tables",
"Ошибка получения таблиц",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to get tables",
"Ошибка получения таблиц",
"$e",
);
}
@ -68,6 +68,31 @@ class TablesListPanelController extends GetxController {
}
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 {
final resp = await ApiController.to.apiClient.dropTable(
tableName: table.tableName,
@ -75,30 +100,30 @@ class TablesListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
Get.snackbar(
"Table deleted",
"${table.tableName.pascalCase} was deleted",
"Таблица удалена",
"Таблица ${table.tableName.pascalCase} была удалена",
);
refreshData();
} on DioError catch (e) {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to delete table",
"Ошибка удаления таблицы",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to delete table",
"Ошибка удаления таблицы",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to delete table",
"Ошибка удаления таблицы",
"$e",
);
}
@ -201,7 +226,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
Row(
children: [
Text(
table.system ? "System" : "Userland",
table.system ? "Системная" : "Пользовательская",
style: const TextStyle(
fontSize: 12,
),
@ -211,7 +236,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
Row(
children: [
Text(
"${table.parsedColumns.length} column(s)",
"${table.parsedColumns.length} колонок(ки)",
style: const TextStyle(
fontSize: 11,
fontStyle: FontStyle.italic,
@ -222,7 +247,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
if (!table.system)
ElevatedButton(
onPressed: () => controller.deleteTable(table),
child: const Text("Delete"),
child: const Text("Удалить"),
).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:flutter/material.dart';
import 'package:get/get.dart';
@ -68,7 +66,7 @@ class UserListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
_users.clear();
@ -82,18 +80,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to get users",
"Ошибка получения пользователей",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to get users",
"Ошибка получения пользователей",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to get users",
"Ошибка получения пользователей",
"$e",
);
}
@ -110,7 +108,7 @@ class UserListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
_groups.clear();
@ -123,18 +121,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to get groups",
"Ошибка получения групп пользователей",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to get groups",
"Ошибка получения групп пользователей",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to get groups",
"Ошибка получения групп пользователей",
"$e",
);
}
@ -149,8 +147,8 @@ class UserListPanelController extends GetxController {
final accept = await Get.dialog<bool>(
AlertDialog(
title: user == null
? const Text("Create new user")
: const Text("Edit user"),
? const Text("Создание нового пользователя")
: const Text("Редактирование пользователя"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -159,14 +157,14 @@ class UserListPanelController extends GetxController {
? TextEditingController(text: user.username)
: null,
decoration: const InputDecoration(
labelText: "Username",
labelText: "Логин",
),
readOnly: user != null,
onChanged: (value) => username.value = value,
),
TextField(
decoration: const InputDecoration(
labelText: "Password",
labelText: "Пароль",
),
obscureText: true,
onChanged: (value) => password.value = value,
@ -176,11 +174,12 @@ class UserListPanelController extends GetxController {
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: const Text("Cancel"),
child: const Text("Отменить"),
),
TextButton(
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) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
refreshData();
@ -218,18 +217,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to create user",
"Ошибка создания пользователя",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to create user",
"Ошибка создания пользователя",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to create user",
"Ошибка создания пользователя",
"$e",
);
}
@ -240,19 +239,19 @@ class UserListPanelController extends GetxController {
final groupDescription = "".obs;
final accept = await Get.dialog<bool>(
AlertDialog(
title: const Text("Create new group"),
title: const Text("Создание группы пользователей"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: const InputDecoration(
labelText: "Group name",
labelText: "Название",
),
onChanged: (value) => groupName.value = value,
),
TextField(
decoration: const InputDecoration(
labelText: "Group description (optional)",
labelText: "Описание (опционально)",
),
onChanged: (value) => groupDescription.value = value,
),
@ -261,11 +260,11 @@ class UserListPanelController extends GetxController {
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: const Text("Cancel"),
child: const Text("Отменить"),
),
TextButton(
onPressed: () => Get.back(result: true),
child: const Text("Create"),
child: const Text("Создать"),
),
],
),
@ -284,12 +283,12 @@ class UserListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
Get.snackbar(
"Group created",
"Group $groupName created",
"Группа создана",
"Группа $groupName создана",
);
refreshData();
@ -297,18 +296,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to create group",
"Ошибка создания группы пользователей",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to create group",
"Ошибка создания группы пользователей",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to create group",
"Ошибка создания группы пользователей",
"$e",
);
}
@ -331,7 +330,7 @@ class UserListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
final data = respData
@ -356,7 +355,7 @@ class UserListPanelController extends GetxController {
final selectedUser = await Get.dialog<UserDefinition>(
AlertDialog(
title: const Text("Select user to add to group"),
title: const Text("Какого пользователя добавить в группу"),
content: SizedBox(
width: 400,
height: 400,
@ -374,7 +373,7 @@ class UserListPanelController extends GetxController {
actions: [
TextButton(
onPressed: () => Get.back(result: null),
child: const Text("Cancel"),
child: const Text("Отменить"),
),
],
),
@ -393,12 +392,12 @@ class UserListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
Get.snackbar(
"User added to group",
"User ${selectedUser.username} added to group ${group.name}",
"Пользователь добавлен в группу",
"Пользователь ${selectedUser.username} добавлен в группу ${group.name}",
);
refreshData();
@ -406,18 +405,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to add user to group",
"Ошибка добавления пользователя в группу",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to add user to group",
"Ошибка добавления пользователя в группу",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to add user to group",
"Ошибка добавления пользователя в группу",
"$e",
);
}
@ -429,17 +428,17 @@ class UserListPanelController extends GetxController {
) async {
final accept = await Get.dialog<bool>(
AlertDialog(
title: const Text("Remove user from group"),
title: const Text("Удаление пользователя из группы"),
content: const Text(
"Are you sure you want to remove this user from the group?"),
"Вы действительно хотите удалить этого пользователя из группы?"),
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: const Text("Cancel"),
child: const Text("Отменить"),
),
TextButton(
onPressed: () => Get.back(result: true),
child: const Text("Remove"),
child: const Text("Удалить"),
),
],
),
@ -466,12 +465,12 @@ class UserListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("No data in response");
throw Exception("В ответе нет данных");
}
Get.snackbar(
"User removed from group",
"User ${user.username} removed from group ${group.name}",
"Пользователь удалён из группы",
"Пользователь ${user.username} удалён из группы ${group.name}",
);
refreshData();
@ -479,18 +478,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to remove user from group",
"Ошибка удаления пользователя из группы",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to remove user from group",
"Ошибка удаления пользователя из группы",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to remove user from group",
"Ошибка удаления пользователя из группы",
"$e",
);
}
@ -499,17 +498,16 @@ class UserListPanelController extends GetxController {
Future<void> deleteGroup(GroupDefinition group) async {
final accept = await Get.dialog<bool>(
AlertDialog(
title: const Text("Delete group"),
content: const Text(
"Are you sure you want to delete this group? This action cannot be undone."),
title: const Text("Удаление группы"),
content: const Text("Вы действительно хотите удалить эту группу?"),
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: const Text("Cancel"),
child: const Text("Отменить"),
),
TextButton(
onPressed: () => Get.back(result: true),
child: const Text("Delete"),
child: const Text("Удалить"),
),
],
),
@ -530,7 +528,7 @@ class UserListPanelController extends GetxController {
);
if (resp1.data == null) {
throw Exception("Could not delete users from group");
throw Exception("Не удалось удалить пользователей из группы");
}
final resp2 = await ApiController.to.apiClient.deleteItemFromTable(
@ -545,12 +543,12 @@ class UserListPanelController extends GetxController {
);
if (resp2.data == null) {
throw Exception("Could not delete group");
throw Exception("Не удалось удалить группу пользователей");
}
Get.snackbar(
"Group deleted",
"Group ${group.name} deleted",
"Группа пользователей удалена",
"Группа ${group.name} удалена",
);
refreshData();
@ -558,18 +556,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to delete group",
"Ошибка удаления группы пользователей",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to delete group",
"Ошибка удаления группы пользователей",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to delete group",
"Ошибка удаления группы пользователей",
"$e",
);
}
@ -582,19 +580,18 @@ class UserListPanelController extends GetxController {
Future<void> deleteUser(UserDefinition user) async {
final accept = await Get.dialog<bool>(
AlertDialog(
title: const Text("Delete user"),
title: 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: [
TextButton(
onPressed: () => Get.back(result: false),
child: const Text("Cancel"),
child: const Text("Отменить"),
),
TextButton(
onPressed: () => Get.back(result: true),
child: const Text("Delete"),
child: const Text("Удалить"),
),
],
),
@ -615,7 +612,7 @@ class UserListPanelController extends GetxController {
);
if (resp1.data == null) {
throw Exception("Could not delete users from group");
throw Exception("Не удалось удалить пользователя из групп");
}
final resp2 = await ApiController.to.apiClient.removeUser(
@ -623,12 +620,12 @@ class UserListPanelController extends GetxController {
);
if (resp2.data == null) {
throw Exception("Could not delete group");
throw Exception("Не удалось удалить пользователя");
}
Get.snackbar(
"User deleted",
"User ${user.username} deleted",
"Пользователь удалён",
"Пользователь ${user.username} удалён",
);
refreshData();
@ -636,18 +633,18 @@ class UserListPanelController extends GetxController {
final respData = e.response?.data;
if (respData != null) {
Get.snackbar(
"Error trying to delete user",
"Ошибка удаления пользователя",
"${respData['error']}",
);
} else {
Get.snackbar(
"Error trying to delete user",
"Ошибка удаления пользователя",
"$e",
);
}
} catch (e) {
Get.snackbar(
"Error trying to delete user",
"Ошибка удаления пользователя",
"$e",
);
}
@ -674,11 +671,11 @@ class UsersListPanel extends GetView<UserListPanelController> {
items: const [
DropdownMenuItem(
value: UserListPanelTab.users,
child: Text("Users"),
child: Text("Пользователи"),
),
DropdownMenuItem(
value: UserListPanelTab.groups,
child: Text("Groups"),
child: Text("Группы"),
),
],
value: controller.currentTab,
@ -721,11 +718,12 @@ class UsersListPanel extends GetView<UserListPanelController> {
);
}
Widget get usersPanel => Obx(() =>
controller.users.isEmpty ? whenNoSomething("No users found") : cardList);
Widget get usersPanel => Obx(() => controller.users.isEmpty
? whenNoSomething("Пользователи не найдены")
: cardList);
Widget get groupsPanel => Obx(() => controller.groups.isEmpty
? whenNoSomething("No groups found")
? whenNoSomething("Группы не найдены")
: groupsList);
Widget whenNoSomething(message) => Center(
@ -785,7 +783,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
ElevatedButton.icon(
onPressed: () => controller.editUser(user),
icon: const Icon(Icons.edit_attributes),
label: const Text("Edit user"),
label: const Text("Редактировать"),
).paddingAll(8).expanded(),
Obx(
() {
@ -807,7 +805,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
final btn = ElevatedButton.icon(
onPressed: () => controller.deleteUser(user),
icon: const Icon(Icons.delete_forever),
label: const Text("Delete user"),
label: const Text("Удалить"),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.redAccent,
),
@ -815,7 +813,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
if (isAdmin) {
return Tooltip(
message: "Please note that this user is an admin",
message: "Данный пользователь является администратором",
child: btn,
).paddingAll(8).expanded();
}
@ -876,7 +874,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
final groupData = controller.usersInGroups[group];
if (group.id == 1) {
return const ListTile(
title: Text("No users can be added to this group"),
title: Text("В эту группу нельзя добавить пользователей"),
);
}
if (groupData == null) {
@ -886,7 +884,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
}
if (groupData.isEmpty) {
return const ListTile(
title: Text("No users in group"),
title: Text("В группе нет пользователей"),
);
}
return ListView.builder(
@ -897,7 +895,7 @@ class UsersListPanel extends GetView<UserListPanelController> {
final isYou = user.accessToken == ApiController.to.token;
return ListTile(
title: Text(user.username),
subtitle: isYou ? const Text("You") : null,
subtitle: isYou ? const Text("Вы") : null,
trailing: isYou &&
(group.id == 2 ||
group.name.toLowerCase() == "admin")

View file

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

View file

@ -15,7 +15,7 @@ class _NotFoundPageState extends State<NotFoundPage>
return Scaffold(
body: Center(
child: Text(
'Page not found',
'Страница не найдена',
style: Theme.of(context).textTheme.headlineMedium,
),
),
@ -30,14 +30,14 @@ class _NotFoundPageState extends State<NotFoundPage>
onPressed: () {
Get.back(canPop: false);
},
child: const Text('Go back'),
child: const Text('Назад'),
),
const SizedBox(width: 16),
ElevatedButton(
onPressed: () {
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),
),
),
title: const Text("Playing"),
title: const Text("Проигрывается"),
subtitle: Text(controller.title),
).card().paddingAll(16).center();
}

View file

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

View file

@ -305,6 +305,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: "direct main"
description: flutter
@ -472,6 +480,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.1"
logger:
dependency: transitive
description:
name: logger
sha256: db2ff852ed77090ba9f62d3611e4208a3d11dfa35991a81ae724c113fcb3e3f7
url: "https://pub.dev"
source: hosted
version: "1.3.0"
logging:
dependency: transitive
description:

View file

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

View file

@ -7,12 +7,15 @@
#include "generated_plugin_registrant.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 <super_native_extensions/super_native_extensions_plugin_c_api.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
FluConsolePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FluConsolePluginCApi"));
IrondashEngineContextPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi"));
SuperNativeExtensionsPluginCApiRegisterWithRegistrar(

View file

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