Compare commits

..

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

21 changed files with 305 additions and 377 deletions

View file

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

View file

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

View file

@ -1,10 +1,11 @@
import 'package:flu_console/flu_console.dart';
import 'package:flutter/material.dart';
import 'package: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';
@ -25,9 +26,7 @@ void main() async {
fenix: true,
);
FluConsole.run(() {
runApp(const MainApp());
});
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: "Текст",
BooleanColumnDefinition: "Логическое значение",
TimestampColumnDefinition: "Дата/Время",
DoubleColumnDefinition: "Число с плавающей точкой",
IntegerColumnDefinition: "Целое число",
UserRefColumnDefinition: "Ссылка на пользователя",
AssetRefColumnDefinition: "Ссылка на ресурс",
TextColumnDefinition: "Text",
BooleanColumnDefinition: "Boolean",
TimestampColumnDefinition: "Date/Time",
DoubleColumnDefinition: "Double",
IntegerColumnDefinition: "Integer",
UserRefColumnDefinition: "User reference",
AssetRefColumnDefinition: "Asset reference",
};
class CreateTableController extends GetxController {
@ -35,7 +35,7 @@ class CreateTableController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("В ответе нет данных");
throw Exception("No data in response");
}
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("Создать новую колонку"),
title: const Text("Create new column"),
content: Wrap(
runSpacing: 16,
children: [
FastTextField(
name: "ColumnName",
decoration: const InputDecoration(
labelText: "Название",
labelText: "Column name",
border: OutlineInputBorder(),
),
initialValue: columnName.value,
@ -82,7 +82,7 @@ class CreateTableController extends GetxController {
),
FastDropdown(
name: "ColumnTypes",
hint: const Text("Тип"),
hint: const Text("Select column type"),
items: typeToNameMatcher.keys.toList(growable: false),
itemsBuilder: (items, field) => items
.map(
@ -97,7 +97,7 @@ class CreateTableController extends GetxController {
),
FastCheckbox(
name: "ColumnIsUnique",
titleText: "Уникальное значение?",
titleText: "Is Unique",
initialValue: false,
onChanged: (value) => columnIsUnique.value = value!,
),
@ -108,13 +108,13 @@ class CreateTableController extends GetxController {
onPressed: () {
Get.back(result: false);
},
child: const Text("Отменить"),
child: const Text('Close'),
),
TextButton(
onPressed: () {
Get.back(result: true);
},
child: const Text("Создать"),
child: const Text('Create'),
),
],
),
@ -129,42 +129,42 @@ class CreateTableController extends GetxController {
columnName: columnName.value,
);
break;
case "Текст":
case "Text":
ct = TextColumnDefinition(
columnName: columnName.value,
isUnique: columnIsUnique.value,
);
break;
case "Логическое значение":
case "Boolean":
ct = BooleanColumnDefinition(
columnName: columnName.value,
isUnique: columnIsUnique.value,
);
break;
case "Дата/Время":
case "Date/Time":
ct = TimestampColumnDefinition(
columnName: columnName.value,
isUnique: columnIsUnique.value,
);
break;
case "Число с плавающей точкой":
case "Double":
ct = DoubleColumnDefinition(
columnName: columnName.value,
isUnique: columnIsUnique.value,
);
break;
case "Целое число":
case "Integer":
ct = IntegerColumnDefinition(
columnName: columnName.value,
isUnique: columnIsUnique.value,
);
break;
case "Ссылка на пользователя":
case "User reference":
ct = UserRefColumnDefinition(
columnName: columnName.value,
);
break;
case "Ссылка на ресурс":
case "Asset reference":
ct = AssetRefColumnDefinition(
columnName: columnName.value,
);
@ -185,12 +185,12 @@ class CreateTableDialog extends GetView<CreateTableController> {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text("Создать новую таблицу"),
title: const Text('Creating new table'),
content: Column(
children: [
TextField(
decoration: const InputDecoration(
labelText: "Название",
labelText: "Table name",
border: OutlineInputBorder(),
),
onChanged: (value) => controller.tableName = value,
@ -216,7 +216,7 @@ class CreateTableDialog extends GetView<CreateTableController> {
[
ElevatedButton(
onPressed: () => controller.createNewColumn(),
child: const Text("Создать колонку"),
child: const Text("Create column"),
).expanded()
].toRow(),
],
@ -226,14 +226,14 @@ class CreateTableDialog extends GetView<CreateTableController> {
onPressed: () {
Get.back();
},
child: const Text("Закрыть"),
child: const Text('Close'),
),
Obx(
() => TextButton(
onPressed: controller.columnsDefinition.isEmpty
? null
: () => controller.createTable(),
child: const Text("Создать"),
child: const Text('Create'),
),
),
],

View file

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

View file

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

View file

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

View file

@ -52,7 +52,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("В ответе нет данных");
throw Exception("No data in response");
}
_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("В ответе нет данных");
throw Exception("No data in response");
}
_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("Ошибка", value.toString());
Get.snackbar("Error", value.toString());
},
);
},
child: const Text("Перенесите файл сюда")
child: const Text("Drop file here")
.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("Отменить"),
child: const Text("Cancel"),
)
],
),
@ -195,7 +195,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("В ответе нет данных");
throw Exception("No data in response");
}
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("Изменение ресурса"),
title: const Text("Edit asset"),
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: "Описание",
labelText: "Description",
),
),
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: "Теги",
labelText: "Tags",
),
),
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)).paddingAll(2))
.map((tag) => Chip(label: Text(tag)))
.toList(growable: false),
).paddingAll(8).card(color: Colors.blueGrey.shade200).expanded(),
),
ElevatedButton(
onPressed: () => previewAsset(e),
child: const Text("Предпросмотр")),
child: const Text("View asset")),
],
).constrained(width: Get.width * 0.5, height: Get.width * 0.5),
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: const Text("Отменить"),
child: const Text("Cancel"),
),
TextButton(
onPressed: () => Get.back(result: true),
child: const Text("Подтвердить"),
child: const Text("Confirm"),
),
],
),
@ -287,7 +287,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("В ответе нет данных");
throw Exception("No data in response");
}
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,24 +318,23 @@ class AssetsPagePanelController extends GetxController {
final confirm = await Get.dialog<bool>(
AlertDialog(
title: const Text("Удаление ресурса"),
title: const Text("Remove asset"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"Вы планируете удалить ресурс. Это действие нельзя отменить."),
const Text("You are about to remove an asset."),
Obx(
() => CheckboxListTile(
value: checkReferences.value,
onChanged: (value) => checkReferences.value = value ?? false,
title: const Text("Проверить ссылки"),
title: const Text("Check references"),
),
),
Obx(
() => CheckboxListTile(
value: deleteReferencing.value,
onChanged: (value) => deleteReferencing.value = value ?? false,
title: const Text("Удалить ссылающиеся сущности"),
title: const Text("Delete referencing"),
),
),
],
@ -343,11 +342,11 @@ class AssetsPagePanelController extends GetxController {
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: const Text("Отменить"),
child: const Text("Cancel"),
),
TextButton(
onPressed: () => Get.back(result: true),
child: const Text("Удалить"),
child: const Text("Remove"),
),
],
),
@ -364,7 +363,7 @@ class AssetsPagePanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("В ответе нет данных");
throw Exception("No data in response");
}
refreshData();
@ -372,18 +371,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",
);
}
@ -405,7 +404,7 @@ class AssetsPagePanelController extends GetxController {
url: "${ApiController.to.endPoint}/assets/${e.fid}",
)
else
const Text("На данный момент этот тип не поддерживает предпросмотр")
const Text("Unsupported media type")
.fontSize(16)
.paddingAll(8)
.card()
@ -440,7 +439,7 @@ class AssetsPagePanel extends GetView<AssetsPagePanelController> {
elevation: 0,
title: Row(
children: [
const Text("Теги:"),
const Text("Tags:"),
Obx(
() => FastChipsInput(
name: "FastChipsInput",
@ -497,13 +496,13 @@ class AssetsPagePanel extends GetView<AssetsPagePanelController> {
horizontalScrollController: controller.scrollController,
columns: const [
DataColumn2(label: Text(""), fixedWidth: 16),
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("Действия")),
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")),
],
empty: const Text("Ресурсы не найдены"),
empty: const Text("No assets found"),
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,10 +1,5 @@
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});
@ -21,53 +16,21 @@ 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: [
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(),
Text(
'Settings',
style: Theme.of(context).textTheme.headlineSmall,
),
],
).paddingAll(8);
);
}
}

View file

@ -29,7 +29,7 @@ class TablesListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("В ответе нет данных");
throw Exception("No data in response");
}
_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,31 +68,6 @@ 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,
@ -100,30 +75,30 @@ class TablesListPanelController extends GetxController {
final respData = resp.data;
if (respData == null) {
throw Exception("В ответе нет данных");
throw Exception("No data in response");
}
Get.snackbar(
"Таблица удалена",
"Таблица ${table.tableName.pascalCase} была удалена",
"Table deleted",
"${table.tableName.pascalCase} was deleted",
);
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",
);
}
@ -226,7 +201,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
Row(
children: [
Text(
table.system ? "Системная" : "Пользовательская",
table.system ? "System" : "Userland",
style: const TextStyle(
fontSize: 12,
),
@ -236,7 +211,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
Row(
children: [
Text(
"${table.parsedColumns.length} колонок(ки)",
"${table.parsedColumns.length} column(s)",
style: const TextStyle(
fontSize: 11,
fontStyle: FontStyle.italic,
@ -247,7 +222,7 @@ class TablesListPanel extends GetView<TablesListPanelController> {
if (!table.system)
ElevatedButton(
onPressed: () => controller.deleteTable(table),
child: const Text("Удалить"),
child: const Text("Delete"),
).paddingOnly(top: 8)
],
),

View file

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

View file

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

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

View file

@ -53,7 +53,7 @@ class AudioPlayerWidget extends GetView<AudioPlayerWidgetController> {
icon: const Icon(Icons.play_arrow),
),
),
title: const Text("Проигрывается"),
title: const Text("Playing"),
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("Введите строку"),
title: const Text("Enter a string"),
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("Отменить"),
child: const Text("Cancel"),
),
TextButton(
onPressed: () {
Get.back(result: strVal.value);
},
child: const Text("Ок"),
child: const Text("OK"),
),
],
),
@ -35,7 +35,7 @@ Future<double?> showDoubleInputDialog({double? originalValue}) async {
final strVal = (originalValue?.toString() ?? "").obs;
return await Get.dialog<double>(
AlertDialog(
title: const Text("Введите плавающее число"),
title: const Text("Enter a number"),
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 "Пожалуйста, введите плавающее число";
return "Please enter a number";
}
final parsed = double.tryParse(value);
if (parsed == null) {
return "Пожалуйста, введите настоящее плавающее число";
return "Please enter a valid number";
}
return null;
},
@ -60,7 +60,7 @@ Future<double?> showDoubleInputDialog({double? originalValue}) async {
onPressed: () {
Get.back(result: null);
},
child: const Text("Отменить"),
child: const Text("Cancel"),
),
TextButton(
onPressed: () {
@ -71,7 +71,7 @@ Future<double?> showDoubleInputDialog({double? originalValue}) async {
Get.back(result: null);
}
},
child: const Text("Ок"),
child: const Text("OK"),
),
],
),
@ -82,7 +82,7 @@ Future<int?> showIntInputDialog({int? originalValue}) async {
final strVal = (originalValue?.toString() ?? "").obs;
return await Get.dialog<int>(
AlertDialog(
title: const Text("Введите целое число"),
title: const Text("Enter a number"),
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 "Пожалуйста, введите целое число";
return "Please enter a number";
}
final parsed = int.tryParse(value);
if (parsed == null) {
return "Пожалуйста, введите настоящее целое число";
return "Please enter a valid number";
}
return null;
},
@ -107,7 +107,7 @@ Future<int?> showIntInputDialog({int? originalValue}) async {
onPressed: () {
Get.back(result: null);
},
child: const Text("Отменить"),
child: const Text("Cancel"),
),
TextButton(
onPressed: () {
@ -118,7 +118,7 @@ Future<int?> showIntInputDialog({int? originalValue}) async {
Get.back(result: null);
}
},
child: const Text("Ок"),
child: const Text("OK"),
),
],
),

View file

@ -305,14 +305,6 @@ 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
@ -480,14 +472,6 @@ 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,7 +17,6 @@ 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,15 +7,12 @@
#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,7 +4,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows
flu_console
irondash_engine_context
super_native_extensions
)