Multi langues + Assign plan dialog + display quotas + translator IA
This commit is contained in:
parent
634fd8d4d7
commit
0059582e9f
4
l10n.yaml
Normal file
4
l10n.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
arb-dir: lib/l10n
|
||||||
|
template-arb-file: app_fr.arb
|
||||||
|
output-localization-file: app_localizations.dart
|
||||||
|
output-class: AppLocalizations
|
||||||
@ -13,4 +13,4 @@ class CommonLoader extends StatelessWidget {
|
|||||||
child: LoaderWaveFloat(size: size),
|
child: LoaderWaveFloat(size: size),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class MultiSelectContainer extends StatelessWidget {
|
|||||||
if(label != null)
|
if(label != null)
|
||||||
Align(
|
Align(
|
||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
child: Text(label!, style: TextStyle(fontSize: 25, fontWeight: FontWeight.w300))
|
child: Text(label!, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: kPrimaryColor))
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
@ -95,7 +95,10 @@ class _MultiSelectChipState extends State<MultiSelectChip> {
|
|||||||
choices.add(Container(
|
choices.add(Container(
|
||||||
padding: const EdgeInsets.all(2.0),
|
padding: const EdgeInsets.all(2.0),
|
||||||
child: ChoiceChip(
|
child: ChoiceChip(
|
||||||
label: Text(widget.isHTMLLabel ? parse(item).documentElement!.text : item, style: TextStyle(color: kBlack)),
|
label: Text(
|
||||||
|
widget.isHTMLLabel ? parse(item).documentElement!.text : item,
|
||||||
|
style: TextStyle(color: widget.selectedValues.contains(item) ? kWhite : kPrimaryColor),
|
||||||
|
),
|
||||||
selected: widget.selectedValues.contains(item),
|
selected: widget.selectedValues.contains(item),
|
||||||
selectedColor: kPrimaryColor,
|
selectedColor: kPrimaryColor,
|
||||||
onSelected: (selected) {
|
onSelected: (selected) {
|
||||||
|
|||||||
@ -25,8 +25,10 @@ showMultiStringInputHTML (String label, String modalLabel, bool isTitle, List<Tr
|
|||||||
children: [
|
children: [
|
||||||
Center(child: Text(modalLabel, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500))),
|
Center(child: Text(modalLabel, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500))),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
SingleChildScrollView(
|
Flexible(
|
||||||
child: TranslationInputContainer(isTitle: isTitle, values: values, newValues: newValues, onGetResult: onGetResult, maxLines: maxLines, resourceTypes: resourceTypes),
|
child: SingleChildScrollView(
|
||||||
|
child: TranslationInputContainer(isTitle: isTitle, values: values, newValues: newValues, onGetResult: onGetResult, maxLines: maxLines, resourceTypes: resourceTypes),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Row(
|
Row(
|
||||||
@ -99,8 +101,10 @@ showMultiStringInputAndResourceHTML (String label, String modalLabel, bool isTit
|
|||||||
children: [
|
children: [
|
||||||
Center(child: Text(modalLabel, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500))),
|
Center(child: Text(modalLabel, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500))),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
SingleChildScrollView(
|
Flexible(
|
||||||
child: TranslationInputAndResourceContainer(isTitle: isTitle, values: values, newValues: newValues, onGetResult: onGetResult, maxLines: maxLines, resourceTypes: resourceTypes),
|
child: SingleChildScrollView(
|
||||||
|
child: TranslationInputAndResourceContainer(isTitle: isTitle, values: values, newValues: newValues, onGetResult: onGetResult, maxLines: maxLines, resourceTypes: resourceTypes),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Row(
|
Row(
|
||||||
|
|||||||
172
lib/Components/quota_bars_widget.dart
Normal file
172
lib/Components/quota_bars_widget.dart
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import '../app_context.dart';
|
||||||
|
import '../Models/managerContext.dart';
|
||||||
|
import '../constants.dart';
|
||||||
|
import '../l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class QuotaBarsWidget extends StatefulWidget {
|
||||||
|
const QuotaBarsWidget({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<QuotaBarsWidget> createState() => _QuotaBarsWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _QuotaBarsWidgetState extends State<QuotaBarsWidget> {
|
||||||
|
InstanceQuotaDTO? _quota;
|
||||||
|
bool _loading = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _fetchQuota());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchQuota() async {
|
||||||
|
final managerContext = Provider.of<AppContext>(context, listen: false).getContext() as ManagerAppContext;
|
||||||
|
final instanceId = managerContext.instanceId;
|
||||||
|
final client = managerContext.clientAPI;
|
||||||
|
|
||||||
|
if (instanceId == null || client == null) {
|
||||||
|
setState(() => _loading = false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final quota = await client.instanceApi!.instanceGetQuota(instanceId);
|
||||||
|
if (mounted) setState(() { _quota = quota; _loading = false; });
|
||||||
|
} catch (_) {
|
||||||
|
if (mounted) setState(() => _loading = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _barColor(int used, int quota) {
|
||||||
|
if (quota == 0) return kPrimaryColor;
|
||||||
|
final ratio = used / quota;
|
||||||
|
if (ratio >= 0.95) return Colors.red;
|
||||||
|
if (ratio >= 0.80) return Colors.orange;
|
||||||
|
return kPrimaryColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
double? _barValue(int used, int quota) {
|
||||||
|
if (quota == 0) return null;
|
||||||
|
return (used / quota).clamp(0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatBytes(int bytes) {
|
||||||
|
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(0)} KB';
|
||||||
|
if (bytes < 1024 * 1024 * 1024) return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
|
||||||
|
return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final managerContext = Provider.of<AppContext>(context).getContext() as ManagerAppContext;
|
||||||
|
final isAssistant = managerContext.instanceDTO?.isAssistant ?? false;
|
||||||
|
final l10n = AppLocalizations.of(context)!;
|
||||||
|
|
||||||
|
if (_loading) {
|
||||||
|
return const SizedBox(
|
||||||
|
height: 8,
|
||||||
|
child: LinearProgressIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_quota == null) return const SizedBox.shrink();
|
||||||
|
|
||||||
|
final storageUsed = _quota!.storageUsedBytes ?? 0;
|
||||||
|
final storageQuota = _quota!.storageQuotaBytes ?? 0;
|
||||||
|
final aiUsed = _quota!.aiRequestsUsed ?? 0;
|
||||||
|
final aiQuota = _quota!.aiRequestsPerMonth ?? 0;
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_QuotaBar(
|
||||||
|
icon: Icons.storage,
|
||||||
|
label: l10n.storageLabel,
|
||||||
|
value: _barValue(storageUsed, storageQuota),
|
||||||
|
color: _barColor(storageUsed, storageQuota),
|
||||||
|
subtitle: storageQuota == 0
|
||||||
|
? '${_formatBytes(storageUsed)} · ${l10n.unlimited}'
|
||||||
|
: '${_formatBytes(storageUsed)} / ${_formatBytes(storageQuota)}',
|
||||||
|
),
|
||||||
|
if (isAssistant) ...[
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
_QuotaBar(
|
||||||
|
icon: Icons.chat_bubble_outline,
|
||||||
|
label: l10n.aiThisMonthLabel,
|
||||||
|
value: _barValue(aiUsed, aiQuota),
|
||||||
|
color: _barColor(aiUsed, aiQuota),
|
||||||
|
subtitle: aiQuota == 0
|
||||||
|
? '$aiUsed ${l10n.requestsAbbr} · ${l10n.unlimited}'
|
||||||
|
: '$aiUsed / $aiQuota ${l10n.requestsAbbr}.',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _QuotaBar extends StatelessWidget {
|
||||||
|
final IconData icon;
|
||||||
|
final String label;
|
||||||
|
final double? value;
|
||||||
|
final Color color;
|
||||||
|
final String subtitle;
|
||||||
|
|
||||||
|
const _QuotaBar({
|
||||||
|
required this.icon,
|
||||||
|
required this.label,
|
||||||
|
required this.value,
|
||||||
|
required this.color,
|
||||||
|
required this.subtitle,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(icon, size: 14, color: kBodyTextColor),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
color: kBodyTextColor,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontFamily: 'Helvetica',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(2),
|
||||||
|
child: LinearProgressIndicator(
|
||||||
|
value: value,
|
||||||
|
minHeight: 5,
|
||||||
|
backgroundColor: Colors.grey.shade200,
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(color),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
subtitle,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
color: kBodyTextColor.withValues(alpha: 0.6),
|
||||||
|
fontFamily: 'Helvetica',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,9 +4,15 @@ import 'package:flutter_quill_delta_from_html/flutter_quill_delta_from_html.dart
|
|||||||
import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart';
|
import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/Components/resource_input_container.dart';
|
import 'package:manager_app/Components/resource_input_container.dart';
|
||||||
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
|
import 'package:manager_app/Models/managerContext.dart' show ManagerAppContext;
|
||||||
|
import 'package:manager_app/Services/ai_translate_service.dart';
|
||||||
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'flag_decoration.dart';
|
import 'flag_decoration.dart';
|
||||||
|
import 'message_notification.dart';
|
||||||
|
|
||||||
class TranslationInputAndResourceContainer extends StatefulWidget {
|
class TranslationInputAndResourceContainer extends StatefulWidget {
|
||||||
TranslationInputAndResourceContainer({
|
TranslationInputAndResourceContainer({
|
||||||
@ -35,6 +41,7 @@ class _TranslationInputAndResourceContainerState
|
|||||||
extends State<TranslationInputAndResourceContainer> {
|
extends State<TranslationInputAndResourceContainer> {
|
||||||
late Map<String, QuillController> _controllers;
|
late Map<String, QuillController> _controllers;
|
||||||
bool _isEnforcingLimit = false;
|
bool _isEnforcingLimit = false;
|
||||||
|
bool _isTranslating = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -92,6 +99,65 @@ class _TranslationInputAndResourceContainerState
|
|||||||
).convert();
|
).convert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _translateWithAI() async {
|
||||||
|
final appContext = context.read<AppContext>().getContext() as ManagerAppContext;
|
||||||
|
if (appContext.instanceDTO?.isAssistant != true) return;
|
||||||
|
|
||||||
|
final source = widget.newValues.firstWhere(
|
||||||
|
(t) => t.value != null && t.value!.trim().isNotEmpty && t.value!.trim() != '<p><br></p>',
|
||||||
|
orElse: () => widget.newValues.first,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (source.value == null || source.value!.trim().isEmpty) {
|
||||||
|
showNotification(kError, kWhite, 'Aucun texte source à traduire', context, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final targetLangs = widget.newValues
|
||||||
|
.where((t) => t.language != source.language)
|
||||||
|
.map((t) => t.language!)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (targetLangs.isEmpty) return;
|
||||||
|
|
||||||
|
setState(() => _isTranslating = true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final translations = await AiTranslateService.translate(
|
||||||
|
host: appContext.host!,
|
||||||
|
accessToken: appContext.accessToken!,
|
||||||
|
instanceId: appContext.instanceId!,
|
||||||
|
text: source.value!,
|
||||||
|
sourceLang: source.language!,
|
||||||
|
targetLangs: targetLangs,
|
||||||
|
);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
for (final translation in widget.newValues) {
|
||||||
|
final lang = translation.language!;
|
||||||
|
if (lang == source.language) continue;
|
||||||
|
final translated = translations[lang];
|
||||||
|
if (translated == null) continue;
|
||||||
|
// On ne touche qu'au texte, pas à la ressource liée
|
||||||
|
translation.value = translated;
|
||||||
|
_controllers[lang]?.dispose();
|
||||||
|
final controller = QuillController(
|
||||||
|
document: Document.fromJson(_htmlToDeltaJson(translated)),
|
||||||
|
selection: const TextSelection.collapsed(offset: 0),
|
||||||
|
);
|
||||||
|
_setupListener(lang, controller);
|
||||||
|
_controllers[lang] = controller;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
showNotification(kSuccess, kWhite, 'Traduction appliquée', context, null);
|
||||||
|
} catch (e) {
|
||||||
|
showNotification(kError, kWhite, 'Erreur lors de la traduction IA', context, null);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isTranslating = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
for (final c in _controllers.values) {
|
for (final c in _controllers.values) {
|
||||||
@ -104,7 +170,29 @@ class _TranslationInputAndResourceContainerState
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: widget.newValues.map((t) => _buildLanguageSection(t)).toList(),
|
children: [
|
||||||
|
...widget.newValues.map((t) => _buildLanguageSection(t)),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Builder(builder: (ctx) {
|
||||||
|
final instance = ctx.watch<AppContext>().getContext()?.instanceDTO;
|
||||||
|
if (instance?.isAssistant != true) return const SizedBox.shrink();
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 370,
|
||||||
|
height: 70,
|
||||||
|
child: _isTranslating
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: RoundedButton(
|
||||||
|
text: "Traduire via IA",
|
||||||
|
icon: Icons.auto_awesome,
|
||||||
|
color: kPrimaryColor,
|
||||||
|
press: _translateWithAI,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,10 +5,14 @@ import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart';
|
|||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/Components/resource_input_container.dart';
|
import 'package:manager_app/Components/resource_input_container.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
|
import 'package:manager_app/Models/managerContext.dart' show ManagerAppContext;
|
||||||
|
import 'package:manager_app/Services/ai_translate_service.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'flag_decoration.dart';
|
import 'flag_decoration.dart';
|
||||||
import 'message_notification.dart';
|
import 'message_notification.dart';
|
||||||
|
import 'package:manager_app/app_context.dart';
|
||||||
|
|
||||||
class TranslationInputContainer extends StatefulWidget {
|
class TranslationInputContainer extends StatefulWidget {
|
||||||
TranslationInputContainer({
|
TranslationInputContainer({
|
||||||
@ -35,6 +39,7 @@ class TranslationInputContainer extends StatefulWidget {
|
|||||||
class _TranslationInputContainerState extends State<TranslationInputContainer> {
|
class _TranslationInputContainerState extends State<TranslationInputContainer> {
|
||||||
late Map<String, QuillController> _controllers;
|
late Map<String, QuillController> _controllers;
|
||||||
bool _isEnforcingLimit = false;
|
bool _isEnforcingLimit = false;
|
||||||
|
bool _isTranslating = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -92,6 +97,64 @@ class _TranslationInputContainerState extends State<TranslationInputContainer> {
|
|||||||
).convert();
|
).convert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _translateWithAI() async {
|
||||||
|
final appContext = context.read<AppContext>().getContext() as ManagerAppContext;
|
||||||
|
if (appContext.instanceDTO?.isAssistant != true) return;
|
||||||
|
|
||||||
|
final source = widget.newValues.firstWhere(
|
||||||
|
(t) => t.value != null && t.value!.trim().isNotEmpty && t.value!.trim() != '<p><br></p>',
|
||||||
|
orElse: () => widget.newValues.first,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (source.value == null || source.value!.trim().isEmpty) {
|
||||||
|
showNotification(kError, kWhite, 'Aucun texte source à traduire', context, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final targetLangs = widget.newValues
|
||||||
|
.where((t) => t.language != source.language)
|
||||||
|
.map((t) => t.language!)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (targetLangs.isEmpty) return;
|
||||||
|
|
||||||
|
setState(() => _isTranslating = true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final translations = await AiTranslateService.translate(
|
||||||
|
host: appContext.host!,
|
||||||
|
accessToken: appContext.accessToken!,
|
||||||
|
instanceId: appContext.instanceId!,
|
||||||
|
text: source.value!,
|
||||||
|
sourceLang: source.language!,
|
||||||
|
targetLangs: targetLangs,
|
||||||
|
);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
for (final translation in widget.newValues) {
|
||||||
|
final lang = translation.language!;
|
||||||
|
if (lang == source.language) continue;
|
||||||
|
final translated = translations[lang];
|
||||||
|
if (translated == null) continue;
|
||||||
|
translation.value = translated;
|
||||||
|
_controllers[lang]?.dispose();
|
||||||
|
final controller = QuillController(
|
||||||
|
document: Document.fromJson(_htmlToDeltaJson(translated)),
|
||||||
|
selection: const TextSelection.collapsed(offset: 0),
|
||||||
|
);
|
||||||
|
_setupListener(lang, controller);
|
||||||
|
_controllers[lang] = controller;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
showNotification(kSuccess, kWhite, 'Traduction appliquée', context, null);
|
||||||
|
} catch (e) {
|
||||||
|
showNotification(kError, kWhite, 'Erreur lors de la traduction IA', context, null);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isTranslating = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _applyToAllLanguages() {
|
void _applyToAllLanguages() {
|
||||||
if (_controllers.isEmpty) return;
|
if (_controllers.isEmpty) return;
|
||||||
final firstLang = widget.newValues.first.language!;
|
final firstLang = widget.newValues.first.language!;
|
||||||
@ -130,7 +193,7 @@ class _TranslationInputContainerState extends State<TranslationInputContainer> {
|
|||||||
children: [
|
children: [
|
||||||
...widget.newValues.map((t) => _buildLanguageSection(t)),
|
...widget.newValues.map((t) => _buildLanguageSection(t)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
if (widget.resourceTypes == null)
|
if (widget.resourceTypes == null) ...[
|
||||||
Center(
|
Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 370,
|
width: 370,
|
||||||
@ -144,6 +207,26 @@ class _TranslationInputContainerState extends State<TranslationInputContainer> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Builder(builder: (ctx) {
|
||||||
|
final instance = ctx.watch<AppContext>().getContext()?.instanceDTO;
|
||||||
|
if (instance?.isAssistant != true) return const SizedBox.shrink();
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 370,
|
||||||
|
height: 70,
|
||||||
|
child: _isTranslating
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: RoundedButton(
|
||||||
|
text: "Traduire via IA",
|
||||||
|
icon: Icons.auto_awesome,
|
||||||
|
color: kPrimaryColor,
|
||||||
|
press: _translateWithAI,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
]
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ class ManagerAppContext with ChangeNotifier{
|
|||||||
SectionDTO? selectedSection;
|
SectionDTO? selectedSection;
|
||||||
bool? isLoading = false;
|
bool? isLoading = false;
|
||||||
UserRole? role;
|
UserRole? role;
|
||||||
|
Locale locale = const Locale('fr');
|
||||||
|
|
||||||
bool get canEdit => role != null && role!.value <= 2;
|
bool get canEdit => role != null && role!.value <= 2;
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,10 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -61,6 +63,7 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _showCreateDialog(BuildContext context, ManagerAppContext ctx) {
|
void _showCreateDialog(BuildContext context, ManagerAppContext ctx) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final nameCtrl = TextEditingController();
|
final nameCtrl = TextEditingController();
|
||||||
ApiKeyAppType selectedType = ApiKeyAppType.number0;
|
ApiKeyAppType selectedType = ApiKeyAppType.number0;
|
||||||
DateTime? selectedExpiration;
|
DateTime? selectedExpiration;
|
||||||
@ -69,14 +72,14 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) {
|
builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text('Créer une clé API'),
|
title: Text(l.createApiKey),
|
||||||
content: Column(mainAxisSize: MainAxisSize.min, children: [
|
content: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
TextField(controller: nameCtrl, decoration: const InputDecoration(labelText: 'Nom')),
|
TextField(controller: nameCtrl, decoration: InputDecoration(labelText: l.name)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('Type d\'application', style: TextStyle(fontSize: 12, color: Colors.grey)),
|
Text(l.appType, style: const TextStyle(fontSize: 12, color: Colors.grey)),
|
||||||
DropdownButton<ApiKeyAppType>(
|
DropdownButton<ApiKeyAppType>(
|
||||||
value: selectedType,
|
value: selectedType,
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
@ -93,8 +96,8 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
selectedExpiration == null
|
selectedExpiration == null
|
||||||
? 'Pas d\'expiration'
|
? l.noExpiration
|
||||||
: 'Expire le ${selectedExpiration!.day.toString().padLeft(2, '0')}/${selectedExpiration!.month.toString().padLeft(2, '0')}/${selectedExpiration!.year}',
|
: l.expiresOn('${selectedExpiration!.day.toString().padLeft(2, '0')}/${selectedExpiration!.month.toString().padLeft(2, '0')}/${selectedExpiration!.year}'),
|
||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -108,19 +111,19 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
);
|
);
|
||||||
if (picked != null) setLocal(() => selectedExpiration = picked);
|
if (picked != null) setLocal(() => selectedExpiration = picked);
|
||||||
},
|
},
|
||||||
child: const Text('Choisir'),
|
child: Text(l.choose),
|
||||||
),
|
),
|
||||||
if (selectedExpiration != null)
|
if (selectedExpiration != null)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.close, size: 16),
|
icon: const Icon(Icons.close, size: 16),
|
||||||
onPressed: () => setLocal(() => selectedExpiration = null),
|
onPressed: () => setLocal(() => selectedExpiration = null),
|
||||||
tooltip: 'Supprimer l\'expiration',
|
tooltip: l.removeExpiration,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: () => Navigator.of(ctx2, rootNavigator: true).pop(), child: const Text('Annuler')),
|
TextButton(onPressed: () => Navigator.of(ctx2, rootNavigator: true).pop(), child: Text(l.cancel)),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.of(ctx2, rootNavigator: true).pop();
|
Navigator.of(ctx2, rootNavigator: true).pop();
|
||||||
@ -129,7 +132,7 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
_showPlainKeyDialog(context, plainKey);
|
_showPlainKeyDialog(context, plainKey);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Text('Créer'),
|
child: Text(l.create),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -138,15 +141,16 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _showPlainKeyDialog(BuildContext context, String plainKey) {
|
void _showPlainKeyDialog(BuildContext context, String plainKey) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (_) => AlertDialog(
|
builder: (_) => AlertDialog(
|
||||||
title: const Text('Clé API créée'),
|
title: Text(l.apiKeyCreatedTitle),
|
||||||
content: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
content: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
const Text(
|
Text(
|
||||||
'Copiez cette clé maintenant — elle ne sera plus affichée.',
|
l.copyKeyWarning,
|
||||||
style: TextStyle(color: Colors.orange, fontWeight: FontWeight.w600),
|
style: const TextStyle(color: Colors.orange, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Container(
|
Container(
|
||||||
@ -160,7 +164,7 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
Expanded(child: SelectableText(plainKey, style: const TextStyle(fontFamily: 'monospace', fontSize: 13))),
|
Expanded(child: SelectableText(plainKey, style: const TextStyle(fontFamily: 'monospace', fontSize: 13))),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.copy, size: 18),
|
icon: const Icon(Icons.copy, size: 18),
|
||||||
tooltip: 'Copier',
|
tooltip: l.copy,
|
||||||
onPressed: () => Clipboard.setData(ClipboardData(text: plainKey)),
|
onPressed: () => Clipboard.setData(ClipboardData(text: plainKey)),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
@ -169,7 +173,7 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
actions: [
|
actions: [
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () => Navigator.of(context, rootNavigator: true).pop(),
|
onPressed: () => Navigator.of(context, rootNavigator: true).pop(),
|
||||||
child: const Text('J\'ai copié la clé'),
|
child: Text(l.copiedKey),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -177,20 +181,21 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _confirmRevoke(BuildContext context, ManagerAppContext ctx, Map<String, dynamic> key) {
|
void _confirmRevoke(BuildContext context, ManagerAppContext ctx, Map<String, dynamic> key) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (dialogContext) => AlertDialog(
|
builder: (dialogContext) => AlertDialog(
|
||||||
title: const Text('Révoquer la clé API'),
|
title: Text(l.revokeApiKeyTitle),
|
||||||
content: Text('Révoquer « ${key['name']} » ? Les apps utilisant cette clé perdront l\'accès.'),
|
content: Text(l.revokeApiKeyConfirm(key['name'] as String? ?? '')),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: () => Navigator.pop(dialogContext), child: const Text('Annuler')),
|
TextButton(onPressed: () => Navigator.pop(dialogContext), child: Text(l.cancel)),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.pop(dialogContext);
|
Navigator.pop(dialogContext);
|
||||||
await _revokeKey(ctx, key['id'] as String);
|
await _revokeKey(ctx, key['id'] as String);
|
||||||
},
|
},
|
||||||
child: const Text('Révoquer', style: TextStyle(color: Colors.white)),
|
child: Text(l.revoke, style: const TextStyle(color: Colors.white)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -208,6 +213,7 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final appContext = Provider.of<AppContext>(context);
|
final appContext = Provider.of<AppContext>(context);
|
||||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||||
|
|
||||||
@ -217,19 +223,19 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('Clés API', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
Text(l.apiKeysTitle, style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () => _showCreateDialog(context, managerCtx),
|
onPressed: () => _showCreateDialog(context, managerCtx),
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: const Text('Créer une clé'),
|
label: Text(l.createKeyBtn),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
if (_loading)
|
if (_loading)
|
||||||
const Center(child: CircularProgressIndicator())
|
const CommonLoader()
|
||||||
else if (_keys.isEmpty)
|
else if (_keys.isEmpty)
|
||||||
const Center(child: Text('Aucune clé API'))
|
Center(child: Text(l.noApiKeys))
|
||||||
else
|
else
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Card(
|
child: Card(
|
||||||
@ -248,13 +254,13 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
columnSpacing: 24,
|
columnSpacing: 24,
|
||||||
headingRowColor: WidgetStateProperty.all(Colors.grey.shade50),
|
headingRowColor: WidgetStateProperty.all(Colors.grey.shade50),
|
||||||
dividerThickness: 1,
|
dividerThickness: 1,
|
||||||
columns: const [
|
columns: [
|
||||||
DataColumn(label: Text('Nom', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.name, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Type', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.type, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Créée le', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.createdOn, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Expiration', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.expiration, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Statut', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.status, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Actions', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.actions, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
],
|
],
|
||||||
rows: _keys.map((key) {
|
rows: _keys.map((key) {
|
||||||
final isActive = key['isActive'] as bool? ?? false;
|
final isActive = key['isActive'] as bool? ?? false;
|
||||||
@ -276,7 +282,7 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
DataCell(Text(expStr, style: TextStyle(color: exp != null && exp.isBefore(DateTime.now()) ? Colors.red : Colors.grey))),
|
DataCell(Text(expStr, style: TextStyle(color: exp != null && exp.isBefore(DateTime.now()) ? Colors.red : Colors.grey))),
|
||||||
DataCell(Chip(
|
DataCell(Chip(
|
||||||
label: Text(
|
label: Text(
|
||||||
isActive ? 'Active' : 'Révoquée',
|
isActive ? l.activeKey : l.revokedKey,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isActive ? Colors.green.shade700 : Colors.red.shade700,
|
color: isActive ? Colors.green.shade700 : Colors.red.shade700,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -290,7 +296,7 @@ class _ApiKeysScreenState extends State<ApiKeysScreen> {
|
|||||||
DataCell(isActive
|
DataCell(isActive
|
||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.block, color: Colors.red, size: 20),
|
icon: const Icon(Icons.block, color: Colors.red, size: 20),
|
||||||
tooltip: 'Révoquer',
|
tooltip: l.tooltipRevoke,
|
||||||
onPressed: () => _confirmRevoke(context, managerCtx, key),
|
onPressed: () => _confirmRevoke(context, managerCtx, key),
|
||||||
)
|
)
|
||||||
: const SizedBox()),
|
: const SizedBox()),
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:manager_app/Components/string_input_container.dart';
|
|||||||
import 'package:manager_app/Screens/Resources/resources_screen.dart';
|
import 'package:manager_app/Screens/Resources/resources_screen.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
import '../Kiosk_devices/change_device_info_modal.dart';
|
import '../Kiosk_devices/change_device_info_modal.dart';
|
||||||
@ -19,7 +20,7 @@ dynamic showAddConfigurationLink (BuildContext mainContext, AppContext appContex
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||||
),
|
),
|
||||||
title: Center(child: Text("Sélectionner une configuration à ajouter")),
|
title: Center(child: Text(AppLocalizations.of(context)!.selectConfigToAdd)),
|
||||||
content: FutureBuilder(
|
content: FutureBuilder(
|
||||||
future: getConfigurations(appContext),
|
future: getConfigurations(appContext),
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
@ -35,7 +36,7 @@ dynamic showAddConfigurationLink (BuildContext mainContext, AppContext appContex
|
|||||||
height: size.height * 0.5,
|
height: size.height * 0.5,
|
||||||
width: size.width * 0.5,
|
width: size.width * 0.5,
|
||||||
constraints: const BoxConstraints(minHeight: 250, minWidth: 250),
|
constraints: const BoxConstraints(minHeight: 250, minWidth: 250),
|
||||||
child: configurations.length == 0 ? Center(child: Text("Aucun élément à afficher")) : ListView.builder(
|
child: configurations.length == 0 ? Center(child: Text(AppLocalizations.of(context)!.noItems)) : ListView.builder(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
itemCount: configurations.length,
|
itemCount: configurations.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
@ -115,7 +116,7 @@ dynamic showAddConfigurationLink (BuildContext mainContext, AppContext appContex
|
|||||||
width: 180,
|
width: 180,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Annuler",
|
text: AppLocalizations.of(context)!.cancel,
|
||||||
icon: Icons.undo,
|
icon: Icons.undo,
|
||||||
color: kSecond,
|
color: kSecond,
|
||||||
press: () {
|
press: () {
|
||||||
@ -128,7 +129,7 @@ dynamic showAddConfigurationLink (BuildContext mainContext, AppContext appContex
|
|||||||
width: 180,
|
width: 180,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Ajouter",
|
text: AppLocalizations.of(context)!.add,
|
||||||
icon: Icons.add,
|
icon: Icons.add,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
press: () {
|
press: () {
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import 'package:manager_app/Screens/Applications/add_configuration_link_popup.da
|
|||||||
import 'package:manager_app/Screens/Applications/phone_mockup.dart';
|
import 'package:manager_app/Screens/Applications/phone_mockup.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("Informations générales", style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
|
Text(AppLocalizations.of(context)!.generalInfo, style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Center(
|
child: Center(
|
||||||
@ -75,7 +76,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
height: elementHeight,
|
height: elementHeight,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ResourceInputContainer(
|
child: ResourceInputContainer(
|
||||||
label: "Image principale :",
|
label: AppLocalizations.of(context)!.mainImageLabel,
|
||||||
initialValue: _applicationInstanceDTO.mainImageId,
|
initialValue: _applicationInstanceDTO.mainImageId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
imageFit: BoxFit.fitHeight,
|
imageFit: BoxFit.fitHeight,
|
||||||
@ -91,7 +92,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
// automatic save
|
// automatic save
|
||||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
|
|
||||||
});*/
|
});*/
|
||||||
@ -106,7 +107,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
height: elementHeight,
|
height: elementHeight,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ResourceInputContainer(
|
child: ResourceInputContainer(
|
||||||
label: "Loader :",
|
label: AppLocalizations.of(context)!.loaderLabel,
|
||||||
initialValue: _applicationInstanceDTO.loaderImageId,
|
initialValue: _applicationInstanceDTO.loaderImageId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
imageFit: BoxFit.fitHeight,
|
imageFit: BoxFit.fitHeight,
|
||||||
@ -122,7 +123,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
// automatic save
|
// automatic save
|
||||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
|
|
||||||
});*/
|
});*/
|
||||||
@ -137,7 +138,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
height: elementHeight,
|
height: elementHeight,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ColorPickerInputContainer(
|
child: ColorPickerInputContainer(
|
||||||
label: "Couleur principale :",
|
label: AppLocalizations.of(context)!.primaryColorLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: _applicationInstanceDTO.primaryColor,
|
color: _applicationInstanceDTO.primaryColor,
|
||||||
onChanged: (value) async {
|
onChanged: (value) async {
|
||||||
@ -145,7 +146,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
// automatic save
|
// automatic save
|
||||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
|
|
||||||
});*/
|
});*/
|
||||||
@ -160,7 +161,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
height: elementHeight,
|
height: elementHeight,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ColorPickerInputContainer(
|
child: ColorPickerInputContainer(
|
||||||
label: "Couleur secondaire :",
|
label: AppLocalizations.of(context)!.secondaryColorLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: _applicationInstanceDTO.secondaryColor,
|
color: _applicationInstanceDTO.secondaryColor,
|
||||||
onChanged: (value) async {
|
onChanged: (value) async {
|
||||||
@ -168,7 +169,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
// automatic save
|
// automatic save
|
||||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
|
|
||||||
});*/
|
});*/
|
||||||
@ -183,17 +184,17 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
height: elementHeight,
|
height: elementHeight,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: SegmentedEnumInputContainer(
|
child: SegmentedEnumInputContainer(
|
||||||
label: "Affichage :",
|
label: AppLocalizations.of(context)!.layoutLabel,
|
||||||
selected: _applicationInstanceDTO.layoutMainPage,
|
selected: _applicationInstanceDTO.layoutMainPage,
|
||||||
values: LayoutMainPageType.values,
|
values: LayoutMainPageType.values,
|
||||||
inputValues: { LayoutMainPageType.SimpleGrid: {'label': 'Grille', 'icon': Icons.grid_view}, LayoutMainPageType.MasonryGrid : {'label': 'Masonry', 'icon': Icons.view_quilt }},
|
inputValues: { LayoutMainPageType.SimpleGrid: {'label': AppLocalizations.of(context)!.layoutGrid, 'icon': Icons.grid_view}, LayoutMainPageType.MasonryGrid : {'label': 'Masonry', 'icon': Icons.view_quilt }},
|
||||||
onChanged: (value) async {
|
onChanged: (value) async {
|
||||||
var tempOutput = value;
|
var tempOutput = value;
|
||||||
_applicationInstanceDTO.layoutMainPage = tempOutput;
|
_applicationInstanceDTO.layoutMainPage = tempOutput;
|
||||||
// automatic save
|
// automatic save
|
||||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
|
|
||||||
});*/
|
});*/
|
||||||
@ -209,7 +210,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
height: elementHeight,
|
height: elementHeight,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: MultiSelectDropdownLanguageContainer(
|
child: MultiSelectDropdownLanguageContainer(
|
||||||
label: "Langues :",
|
label: AppLocalizations.of(context)!.languagesLabel,
|
||||||
initialValue: _applicationInstanceDTO.languages != null ? _applicationInstanceDTO.languages!: [],
|
initialValue: _applicationInstanceDTO.languages != null ? _applicationInstanceDTO.languages!: [],
|
||||||
values: languages,
|
values: languages,
|
||||||
isMultiple: true,
|
isMultiple: true,
|
||||||
@ -221,7 +222,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
// automatic save
|
// automatic save
|
||||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
|
|
||||||
});*/
|
});*/
|
||||||
@ -245,14 +246,14 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
List<SectionEventDTO>? sectionEvents = rawSubsections?.whereType<SectionEventDTO>().toList();
|
List<SectionEventDTO>? sectionEvents = rawSubsections?.whereType<SectionEventDTO>().toList();
|
||||||
sectionEvents = sectionEvents == null ? [] : sectionEvents;
|
sectionEvents = sectionEvents == null ? [] : sectionEvents;
|
||||||
|
|
||||||
sectionEvents.add(SectionEventDTO(id: null, label: "Aucun"));
|
sectionEvents.add(SectionEventDTO(id: null, label: AppLocalizations.of(context)!.noneOption));
|
||||||
|
|
||||||
print(_applicationInstanceDTO.sectionEventId);
|
print(_applicationInstanceDTO.sectionEventId);
|
||||||
print(_applicationInstanceDTO.sectionEventDTO);
|
print(_applicationInstanceDTO.sectionEventDTO);
|
||||||
|
|
||||||
return SingleChoiceInputContainer<SectionEventDTO?>(
|
return SingleChoiceInputContainer<SectionEventDTO?>(
|
||||||
label: "Evènement à l'affiche :",
|
label: AppLocalizations.of(context)!.featuredEventLabel,
|
||||||
selectLabel: "Choisir un évènement",
|
selectLabel: AppLocalizations.of(context)!.chooseEvent,
|
||||||
selected: _applicationInstanceDTO.sectionEventDTO,
|
selected: _applicationInstanceDTO.sectionEventDTO,
|
||||||
values: sectionEvents.toList(),
|
values: sectionEvents.toList(),
|
||||||
valueExtractor: (SectionEventDTO? dto) => dto?.id ?? "",
|
valueExtractor: (SectionEventDTO? dto) => dto?.id ?? "",
|
||||||
@ -273,7 +274,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
// automatic save
|
// automatic save
|
||||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
//setState(() {
|
//setState(() {
|
||||||
_applicationInstanceDTO.sectionEventDTO = applicationLink.sectionEventDTO;
|
_applicationInstanceDTO.sectionEventDTO = applicationLink.sectionEventDTO;
|
||||||
//_applicationInstanceDTO = applicationLink;
|
//_applicationInstanceDTO = applicationLink;
|
||||||
@ -296,7 +297,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Assistant IA :", style: TextStyle(fontSize: 16)),
|
Text(AppLocalizations.of(context)!.aiAssistantLabel, style: TextStyle(fontSize: 16)),
|
||||||
Switch(
|
Switch(
|
||||||
activeThumbColor: kPrimaryColor,
|
activeThumbColor: kPrimaryColor,
|
||||||
inactiveThumbColor: kBodyTextColor,
|
inactiveThumbColor: kBodyTextColor,
|
||||||
@ -311,10 +312,10 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
localSetState(() {
|
localSetState(() {
|
||||||
_applicationInstanceDTO.isAssistant = applicationLink.isAssistant;
|
_applicationInstanceDTO.isAssistant = applicationLink.isAssistant;
|
||||||
});
|
});
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite, "Une erreur est survenue", context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.errorOccurred, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -347,7 +348,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Text("Configurations sur le téléphone", style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
|
child: Text(AppLocalizations.of(context)!.phoneConfigTitle, style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
|
||||||
),
|
),
|
||||||
appConfigurationLinks != null ? Padding(
|
appConfigurationLinks != null ? Padding(
|
||||||
padding: const EdgeInsets.only(left: 32, right: 32, top: 75),
|
padding: const EdgeInsets.only(left: 32, right: 32, top: 75),
|
||||||
@ -375,7 +376,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
// TODO use order put method
|
// TODO use order put method
|
||||||
var result = await updateAppConfigurationOrder(appContext, updatedList);
|
var result = await updateAppConfigurationOrder(appContext, updatedList);
|
||||||
localSetState(() {});
|
localSetState(() {});
|
||||||
showNotification(kSuccess, kWhite, "Application mobile mise à jour succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||||
},
|
},
|
||||||
actions: [
|
actions: [
|
||||||
(BuildContext context, int index, AppConfigurationLinkDTO link) {
|
(BuildContext context, int index, AppConfigurationLinkDTO link) {
|
||||||
@ -394,16 +395,16 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
var applicationLink = await updateApplicationLink(appContext, link);
|
var applicationLink = await updateApplicationLink(appContext, link);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
if(newValue) {
|
if(newValue) {
|
||||||
showNotification(kSuccess, kWhite, "Configuration activée avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configActivatedSuccess, context, null);
|
||||||
} else {
|
} else {
|
||||||
showNotification(kSuccess, kWhite, "Configuration désactivée avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configDeactivatedSuccess, context, null);
|
||||||
}
|
}
|
||||||
localSetState(() {
|
localSetState(() {
|
||||||
link.isActive = applicationLink.isActive;
|
link.isActive = applicationLink.isActive;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite, "Une erreur est survenue", context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.errorOccurred, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -416,19 +417,19 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir retirer cette configuration de l'application ?",
|
AppLocalizations.of(context)!.configRemoveConfirm,
|
||||||
() {},
|
() {},
|
||||||
() async {
|
() async {
|
||||||
try {
|
try {
|
||||||
var result = await deleteConfigurationToApp(appContext, link, _applicationInstanceDTO);
|
var result = await deleteConfigurationToApp(appContext, link, _applicationInstanceDTO);
|
||||||
|
|
||||||
showNotification(kSuccess, kWhite, "La configuration a été retirée de l'application avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configRemovedSuccess, context, null);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// for refresh ui
|
// for refresh ui
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors du retrait de la configuration', context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.configRemoveError, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
@ -498,19 +499,19 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir retirer cette configuration de l'application ?",
|
AppLocalizations.of(context)!.configRemoveConfirm,
|
||||||
() {},
|
() {},
|
||||||
() async {
|
() async {
|
||||||
try {
|
try {
|
||||||
var result = await deleteConfigurationToApp(appContext, appConfigurationLink, _applicationInstanceDTO);
|
var result = await deleteConfigurationToApp(appContext, appConfigurationLink, _applicationInstanceDTO);
|
||||||
|
|
||||||
showNotification(kSuccess, kWhite, "La configuration a été retirée de l'application avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configRemovedSuccess, context, null);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// for refresh ui
|
// for refresh ui
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors du retrait de la configuration', context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.configRemoveError, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
@ -526,7 +527,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),*/
|
),*/
|
||||||
): Center(child: Text("No data")),
|
): Center(child: Text(AppLocalizations.of(context)!.noData)),
|
||||||
appConfigurationLinks != null ? Positioned(
|
appConfigurationLinks != null ? Positioned(
|
||||||
top: 8,
|
top: 8,
|
||||||
right: 8,
|
right: 8,
|
||||||
@ -630,7 +631,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text("Informations générales"),
|
child: Text(AppLocalizations.of(context)!.generalInfo),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Align(
|
Align(
|
||||||
@ -656,7 +657,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
),*/
|
),*/
|
||||||
// Image principale
|
// Image principale
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Image principale :",
|
label: AppLocalizations.of(context)!.mainImageLabel,
|
||||||
initialValue: _applicationInstanceDTO.mainImageId,
|
initialValue: _applicationInstanceDTO.mainImageId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (ResourceDTO resource) {
|
onChanged: (ResourceDTO resource) {
|
||||||
@ -671,7 +672,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
),
|
),
|
||||||
// Image Loader
|
// Image Loader
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Loader :",
|
label: AppLocalizations.of(context)!.loaderLabel,
|
||||||
initialValue: _applicationInstanceDTO.loaderImageId,
|
initialValue: _applicationInstanceDTO.loaderImageId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (ResourceDTO resource) {
|
onChanged: (ResourceDTO resource) {
|
||||||
@ -686,7 +687,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
),
|
),
|
||||||
// Primary color
|
// Primary color
|
||||||
ColorPickerInputContainer(
|
ColorPickerInputContainer(
|
||||||
label: "Couleur principale :",
|
label: AppLocalizations.of(context)!.primaryColorLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: _applicationInstanceDTO.primaryColor,
|
color: _applicationInstanceDTO.primaryColor,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -695,7 +696,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
),
|
),
|
||||||
// Secondary color
|
// Secondary color
|
||||||
ColorPickerInputContainer(
|
ColorPickerInputContainer(
|
||||||
label: "Couleur secondaire :",
|
label: AppLocalizations.of(context)!.secondaryColorLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: _applicationInstanceDTO.secondaryColor,
|
color: _applicationInstanceDTO.secondaryColor,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -706,7 +707,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
Text('Todo Type selector Grid or Mansonry'),
|
Text('Todo Type selector Grid or Mansonry'),
|
||||||
// Langues
|
// Langues
|
||||||
MultiSelectDropdownLanguageContainer(
|
MultiSelectDropdownLanguageContainer(
|
||||||
label: "Langues :",
|
label: AppLocalizations.of(context)!.languagesLabel,
|
||||||
initialValue: _applicationInstanceDTO.languages != null ? _applicationInstanceDTO.languages!: [],
|
initialValue: _applicationInstanceDTO.languages != null ? _applicationInstanceDTO.languages!: [],
|
||||||
values: languages,
|
values: languages,
|
||||||
isMultiple: true,
|
isMultiple: true,
|
||||||
@ -728,7 +729,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text("Configurations sur le téléphone"),
|
child: Text(AppLocalizations.of(context)!.phoneConfigTitle),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Align(
|
Align(
|
||||||
@ -774,16 +775,16 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
if(newValue) {
|
if(newValue) {
|
||||||
showNotification(kSuccess, kWhite, "Configuration activée avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configActivatedSuccess, context, null);
|
||||||
} else {
|
} else {
|
||||||
showNotification(kSuccess, kWhite, "Configuration désactivée avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configDeactivatedSuccess, context, null);
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
link.isActive = applicationLink.isActive;
|
link.isActive = applicationLink.isActive;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite, "Une erreur est survenue", context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.errorOccurred, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Icon(Icons.star, color: kError, size: 25),
|
child: Icon(Icons.star, color: kError, size: 25),
|
||||||
@ -806,16 +807,16 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
var applicationLink = await updateApplicationLink(appContext, link);
|
var applicationLink = await updateApplicationLink(appContext, link);
|
||||||
if(applicationLink != null) {
|
if(applicationLink != null) {
|
||||||
if(newValue) {
|
if(newValue) {
|
||||||
showNotification(kSuccess, kWhite, "Configuration activée avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configActivatedSuccess, context, null);
|
||||||
} else {
|
} else {
|
||||||
showNotification(kSuccess, kWhite, "Configuration désactivée avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configDeactivatedSuccess, context, null);
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
link.isActive = applicationLink.isActive;
|
link.isActive = applicationLink.isActive;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite, "Une erreur est survenue", context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.errorOccurred, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -828,19 +829,19 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir retirer cette configuration de l'application ?",
|
AppLocalizations.of(context)!.configRemoveConfirm,
|
||||||
() {},
|
() {},
|
||||||
() async {
|
() async {
|
||||||
try {
|
try {
|
||||||
var result = await deleteConfigurationToApp(appContext, link, _applicationInstanceDTO);
|
var result = await deleteConfigurationToApp(appContext, link, _applicationInstanceDTO);
|
||||||
|
|
||||||
showNotification(kSuccess, kWhite, "La configuration a été retirée de l'application avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configRemovedSuccess, context, null);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// for refresh ui
|
// for refresh ui
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors du retrait de la configuration', context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.configRemoveError, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
@ -949,19 +950,19 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir retirer cette configuration de l'application ?",
|
AppLocalizations.of(context)!.configRemoveConfirm,
|
||||||
() {},
|
() {},
|
||||||
() async {
|
() async {
|
||||||
try {
|
try {
|
||||||
var result = await deleteConfigurationToApp(appContext, appConfigurationLink, _applicationInstanceDTO);
|
var result = await deleteConfigurationToApp(appContext, appConfigurationLink, _applicationInstanceDTO);
|
||||||
|
|
||||||
showNotification(kSuccess, kWhite, "La configuration a été retirée de l'application avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configRemovedSuccess, context, null);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
// for refresh ui
|
// for refresh ui
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors du retrait de la configuration', context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.configRemoveError, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
@ -979,14 +980,14 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
|||||||
),*/
|
),*/
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
): Center(child: Text("No data")),
|
): Center(child: Text(AppLocalizations.of(context)!.noData)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
return Text("No data");
|
return Text(AppLocalizations.of(context)!.noData);
|
||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:manager_app/Components/single_select_container.dart';
|
|||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||||
import 'showNewOrUpdateEventAgenda.dart';
|
import 'showNewOrUpdateEventAgenda.dart';
|
||||||
@ -94,12 +95,12 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Text("Évènements",
|
Text(AppLocalizations.of(context)!.agendaEventsLabel,
|
||||||
style:
|
style:
|
||||||
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: const Text("Ajouter un évènement"),
|
label: Text(AppLocalizations.of(context)!.addEvent),
|
||||||
onPressed: agendaDTO.id == null
|
onPressed: agendaDTO.id == null
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
@ -115,13 +116,13 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
if (created != null && mounted) {
|
if (created != null && mounted) {
|
||||||
setState(() => events.add(created));
|
setState(() => events.add(created));
|
||||||
showNotification(kSuccess, kWhite,
|
showNotification(kSuccess, kWhite,
|
||||||
'Évènement créé avec succès', context, null);
|
AppLocalizations.of(context)!.agendaEventCreatedSuccess, context, null);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la création de l\'évènement',
|
AppLocalizations.of(context)!.agendaEventCreateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
rethrow;
|
rethrow;
|
||||||
@ -145,8 +146,8 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
height: 600,
|
height: 600,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: events.isEmpty
|
child: events.isEmpty
|
||||||
? const Center(
|
? Center(
|
||||||
child: Text("Aucun évènement",
|
child: Text(AppLocalizations.of(context)!.noEvents,
|
||||||
style: TextStyle(fontStyle: FontStyle.italic)))
|
style: TextStyle(fontStyle: FontStyle.italic)))
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
itemCount: events.length,
|
itemCount: events.length,
|
||||||
@ -170,14 +171,14 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
(event.label != null && event.label!.isNotEmpty)
|
(event.label != null && event.label!.isNotEmpty)
|
||||||
? (event.label!.firstWhere(
|
? (event.label!.firstWhere(
|
||||||
(t) => t.language == 'FR',
|
(t) => t.language == 'FR',
|
||||||
orElse: () => event.label![0])).value ?? "Évènement $index"
|
orElse: () => event.label![0])).value ?? "${AppLocalizations.of(context)!.agendaEventFallback} $index"
|
||||||
: "Évènement $index",
|
: "${AppLocalizations.of(context)!.agendaEventFallback} $index",
|
||||||
textStyle: const TextStyle(fontWeight: FontWeight.bold),
|
textStyle: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
subtitle: Padding(
|
subtitle: Padding(
|
||||||
padding: const EdgeInsets.only(top: 4),
|
padding: const EdgeInsets.only(top: 4),
|
||||||
child:
|
child:
|
||||||
Text(event.address?.address ?? "Pas d'adresse"),
|
Text(event.address?.address ?? AppLocalizations.of(context)!.noAddress),
|
||||||
),
|
),
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -201,7 +202,7 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Évènement mis à jour avec succès',
|
AppLocalizations.of(context)!.agendaEventUpdatedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -209,7 +210,7 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la mise à jour de l\'évènement',
|
AppLocalizations.of(context)!.agendaEventUpdateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
rethrow;
|
rethrow;
|
||||||
@ -232,7 +233,7 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Évènement supprimé avec succès',
|
AppLocalizations.of(context)!.agendaEventDeletedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -240,7 +241,7 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la suppression de l\'évènement',
|
AppLocalizations.of(context)!.agendaEventDeleteError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -279,7 +280,7 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
CheckInputContainer(
|
CheckInputContainer(
|
||||||
label: "En ligne :",
|
label: AppLocalizations.of(context)!.onlineLabel,
|
||||||
isChecked: agendaDTO.isOnlineAgenda ?? true,
|
isChecked: agendaDTO.isOnlineAgenda ?? true,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -289,7 +290,7 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
CheckInputContainer(
|
CheckInputContainer(
|
||||||
label: "Vue carte :",
|
label: AppLocalizations.of(context)!.mapViewLabel,
|
||||||
isChecked: agendaDTO.agendaMapProvider != null,
|
isChecked: agendaDTO.agendaMapProvider != null,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -304,7 +305,7 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
),
|
),
|
||||||
if (agendaDTO.agendaMapProvider != null)
|
if (agendaDTO.agendaMapProvider != null)
|
||||||
SingleSelectContainer(
|
SingleSelectContainer(
|
||||||
label: "Service carte :",
|
label: AppLocalizations.of(context)!.mapServiceLabel,
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
initialValue: mapProviderIn,
|
initialValue: mapProviderIn,
|
||||||
inputValues: const ["Google", "MapBox"],
|
inputValues: const ["Google", "MapBox"],
|
||||||
@ -324,9 +325,9 @@ class _AgendaConfigState extends State<AgendaConfig> {
|
|||||||
),
|
),
|
||||||
if (agendaDTO.isOnlineAgenda == true)
|
if (agendaDTO.isOnlineAgenda == true)
|
||||||
MultiStringInputContainer(
|
MultiStringInputContainer(
|
||||||
label: "Fichiers json :",
|
label: AppLocalizations.of(context)!.jsonFilesLabel,
|
||||||
resourceTypes: const [ResourceType.Json, ResourceType.JsonUrl],
|
resourceTypes: const [ResourceType.Json, ResourceType.JsonUrl],
|
||||||
modalLabel: "JSON",
|
modalLabel: AppLocalizations.of(context)!.jsonLabel,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: agendaDTO.resourceIds ?? [],
|
initialValue: agendaDTO.resourceIds ?? [],
|
||||||
isTitle: false,
|
isTitle: false,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
import 'package:manager_app/Components/string_input_container.dart';
|
import 'package:manager_app/Components/string_input_container.dart';
|
||||||
@ -51,7 +52,7 @@ void showNewOrUpdateEventAgenda(
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
event == null ? "Nouvel Évènement" : "Modifier l'Évènement",
|
event == null ? AppLocalizations.of(context)!.newAgendaEventTitle : AppLocalizations.of(context)!.editAgendaEventTitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
@ -70,7 +71,7 @@ void showNewOrUpdateEventAgenda(
|
|||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Titre :",
|
label: "Titre :",
|
||||||
modalLabel: "Titre de l'évènement",
|
modalLabel: AppLocalizations.of(context)!.eventTitleLabel,
|
||||||
initialValue: workingEvent.label ?? [],
|
initialValue: workingEvent.label ?? [],
|
||||||
onGetResult: (val) =>
|
onGetResult: (val) =>
|
||||||
setState(() => workingEvent.label = val),
|
setState(() => workingEvent.label = val),
|
||||||
@ -84,7 +85,7 @@ void showNewOrUpdateEventAgenda(
|
|||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Description :",
|
label: "Description :",
|
||||||
modalLabel: "Description de l'évènement",
|
modalLabel: AppLocalizations.of(context)!.eventDescriptionLabel,
|
||||||
initialValue: workingEvent.description ?? [],
|
initialValue: workingEvent.description ?? [],
|
||||||
onGetResult: (val) => setState(
|
onGetResult: (val) => setState(
|
||||||
() => workingEvent.description = val),
|
() => workingEvent.description = val),
|
||||||
@ -104,7 +105,7 @@ void showNewOrUpdateEventAgenda(
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("Date de début :"),
|
Text(AppLocalizations.of(context)!.startDateColonLabel),
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
OutlinedButton.icon(
|
OutlinedButton.icon(
|
||||||
icon: Icon(Icons.calendar_today, size: 16),
|
icon: Icon(Icons.calendar_today, size: 16),
|
||||||
@ -172,7 +173,7 @@ void showNewOrUpdateEventAgenda(
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: ResourceInputContainer(
|
child: ResourceInputContainer(
|
||||||
label: "Vidéo :",
|
label: AppLocalizations.of(context)!.videoResourceLabel,
|
||||||
initialValue: workingEvent.videoResourceId,
|
initialValue: workingEvent.videoResourceId,
|
||||||
inResourceTypes: const [ResourceType.Video, ResourceType.VideoUrl],
|
inResourceTypes: const [ResourceType.Video, ResourceType.VideoUrl],
|
||||||
onChanged: (res) => setState(() {
|
onChanged: (res) => setState(() {
|
||||||
@ -199,7 +200,7 @@ void showNewOrUpdateEventAgenda(
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Lien vidéo direct :",
|
label: AppLocalizations.of(context)!.directVideoLinkLabel,
|
||||||
initialValue: workingEvent.videoLink ?? "",
|
initialValue: workingEvent.videoLink ?? "",
|
||||||
onChanged: (val) => setState(() => workingEvent.videoLink = val.isEmpty ? null : val),
|
onChanged: (val) => setState(() => workingEvent.videoLink = val.isEmpty ? null : val),
|
||||||
),
|
),
|
||||||
@ -223,7 +224,7 @@ void showNewOrUpdateEventAgenda(
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: thirdWidth,
|
width: thirdWidth,
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Téléphone :",
|
label: AppLocalizations.of(context)!.phoneLabel,
|
||||||
initialValue: workingEvent.phone ?? "",
|
initialValue: workingEvent.phone ?? "",
|
||||||
onChanged: (val) =>
|
onChanged: (val) =>
|
||||||
setState(() => workingEvent.phone = val),
|
setState(() => workingEvent.phone = val),
|
||||||
@ -242,7 +243,7 @@ void showNewOrUpdateEventAgenda(
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Divider(height: 24),
|
Divider(height: 24),
|
||||||
Text("Localisation / Géométrie",
|
Text(AppLocalizations.of(context)!.locationGeometryLabel,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
StringInputContainer(
|
StringInputContainer(
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import 'package:manager_app/constants.dart';
|
|||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ class _ArticleConfigState extends State<ArticleConfig> {
|
|||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
MultiStringInputContainer(
|
MultiStringInputContainer(
|
||||||
label: "Contenu affiché :",
|
label: AppLocalizations.of(context)!.displayedContentLabel,
|
||||||
modalLabel: "Contenu",
|
modalLabel: "Contenu",
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:intl/intl.dart';
|
|||||||
import 'showNewOrUpdateProgrammeBlock.dart';
|
import 'showNewOrUpdateProgrammeBlock.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/parcours_config.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/parcours_config.dart';
|
||||||
@ -98,11 +99,11 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text("Date de début"),
|
title: Text(AppLocalizations.of(context)!.startDateLabel),
|
||||||
subtitle: Text(eventDTO.startDate != null
|
subtitle: Text(eventDTO.startDate != null
|
||||||
? DateFormat('dd/MM/yyyy HH:mm')
|
? DateFormat('dd/MM/yyyy HH:mm')
|
||||||
.format(eventDTO.startDate!.toLocal())
|
.format(eventDTO.startDate!.toLocal())
|
||||||
: "Non définie"),
|
: AppLocalizations.of(context)!.notDefined),
|
||||||
trailing: Icon(Icons.calendar_today),
|
trailing: Icon(Icons.calendar_today),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
DateTime initialDate = eventDTO.startDate?.toLocal() ?? DateTime.now();
|
DateTime initialDate = eventDTO.startDate?.toLocal() ?? DateTime.now();
|
||||||
@ -158,10 +159,10 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text("Date de fin"),
|
title: Text(AppLocalizations.of(context)!.endDateLabel),
|
||||||
subtitle: Text(eventDTO.endDate != null
|
subtitle: Text(eventDTO.endDate != null
|
||||||
? DateFormat('dd/MM/yyyy HH:mm').format(eventDTO.endDate!.toLocal())
|
? DateFormat('dd/MM/yyyy HH:mm').format(eventDTO.endDate!.toLocal())
|
||||||
: "Non définie"),
|
: AppLocalizations.of(context)!.notDefined),
|
||||||
trailing: Icon(Icons.calendar_today),
|
trailing: Icon(Icons.calendar_today),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
DateTime initialDate = eventDTO.endDate?.toLocal() ??
|
DateTime initialDate = eventDTO.endDate?.toLocal() ??
|
||||||
@ -231,11 +232,11 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Programme",
|
Text(AppLocalizations.of(context)!.programmeLabel,
|
||||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: Icon(Icons.add),
|
icon: Icon(Icons.add),
|
||||||
label: Text("Ajouter un bloc"),
|
label: Text(AppLocalizations.of(context)!.addBlock),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final appContext =
|
final appContext =
|
||||||
Provider.of<AppContext>(context, listen: false);
|
Provider.of<AppContext>(context, listen: false);
|
||||||
@ -277,7 +278,7 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Bloc de programme créé avec succès',
|
AppLocalizations.of(context)!.programmeBlockCreatedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -285,7 +286,7 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la création du bloc',
|
AppLocalizations.of(context)!.programmeBlockCreateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -302,7 +303,7 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
height: 600,
|
height: 600,
|
||||||
child: (eventDTO.programme == null || eventDTO.programme!.isEmpty)
|
child: (eventDTO.programme == null || eventDTO.programme!.isEmpty)
|
||||||
? Center(
|
? Center(
|
||||||
child: Text("Aucun bloc de programme défini",
|
child: Text(AppLocalizations.of(context)!.noBlocks,
|
||||||
style: TextStyle(fontStyle: FontStyle.italic)))
|
style: TextStyle(fontStyle: FontStyle.italic)))
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
itemCount: eventDTO.programme!.length,
|
itemCount: eventDTO.programme!.length,
|
||||||
@ -318,9 +319,9 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
(t) => t.language == 'FR',
|
(t) => t.language == 'FR',
|
||||||
orElse: () => block.title![0])
|
orElse: () => block.title![0])
|
||||||
.value ??
|
.value ??
|
||||||
"Bloc ${index + 1}",
|
"${AppLocalizations.of(context)!.blockFallback} ${index + 1}",
|
||||||
)
|
)
|
||||||
: Text("Bloc ${index + 1}"),
|
: Text("${AppLocalizations.of(context)!.blockFallback} ${index + 1}"),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
"${block.startTime != null ? DateFormat('HH:mm').format(block.startTime!.toLocal()) : '??'} - ${block.endTime != null ? DateFormat('HH:mm').format(block.endTime!.toLocal()) : '??'}"),
|
"${block.startTime != null ? DateFormat('HH:mm').format(block.startTime!.toLocal()) : '??'} - ${block.endTime != null ? DateFormat('HH:mm').format(block.endTime!.toLocal()) : '??'}"),
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
@ -368,7 +369,7 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Bloc mis à jour avec succès',
|
AppLocalizations.of(context)!.programmeBlockUpdatedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -376,7 +377,7 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la mise à jour du bloc',
|
AppLocalizations.of(context)!.programmeBlockUpdateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -407,14 +408,14 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Bloc supprimé avec succès',
|
AppLocalizations.of(context)!.programmeBlockDeletedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la suppression du bloc',
|
AppLocalizations.of(context)!.programmeBlockDeleteError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -457,10 +458,10 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Carte de base",
|
Text(AppLocalizations.of(context)!.baseMapLabel,
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
DropDownInputContainer(
|
DropDownInputContainer(
|
||||||
label: "Carte :",
|
label: AppLocalizations.of(context)!.mapLabel,
|
||||||
values: mapItems,
|
values: mapItems,
|
||||||
initialValue: currentValue,
|
initialValue: currentValue,
|
||||||
onChange: (val) {
|
onChange: (val) {
|
||||||
@ -493,11 +494,11 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Text("Annotations globales",
|
Text(AppLocalizations.of(context)!.globalAnnotationsLabel,
|
||||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: const Text("Ajouter une annotation"),
|
label: Text(AppLocalizations.of(context)!.addAnnotation),
|
||||||
onPressed: eventDTO.id == null
|
onPressed: eventDTO.id == null
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
@ -518,11 +519,11 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
showNotification(kSuccess, kWhite,
|
showNotification(kSuccess, kWhite,
|
||||||
'Annotation créée avec succès', context, null);
|
AppLocalizations.of(context)!.annotationCreatedSuccess, context, null);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite,
|
showNotification(kError, kWhite,
|
||||||
'Erreur lors de la création de l\'annotation',
|
AppLocalizations.of(context)!.annotationCreateError,
|
||||||
context, null);
|
context, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -540,9 +541,9 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
if (annotations.isEmpty)
|
if (annotations.isEmpty)
|
||||||
const Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 8),
|
padding: EdgeInsets.only(top: 8),
|
||||||
child: Text("Aucune annotation globale",
|
child: Text(AppLocalizations.of(context)!.noAnnotations,
|
||||||
style: TextStyle(fontStyle: FontStyle.italic)),
|
style: TextStyle(fontStyle: FontStyle.italic)),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@ -552,8 +553,8 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
final labelText = ann.label != null && ann.label!.isNotEmpty
|
final labelText = ann.label != null && ann.label!.isNotEmpty
|
||||||
? (ann.label!.firstWhere((t) => t.language == 'FR',
|
? (ann.label!.firstWhere((t) => t.language == 'FR',
|
||||||
orElse: () => ann.label![0])
|
orElse: () => ann.label![0])
|
||||||
.value ?? 'Annotation ${idx + 1}')
|
.value ?? '${AppLocalizations.of(context)!.annotationFallback} ${idx + 1}')
|
||||||
: 'Annotation ${idx + 1}';
|
: '${AppLocalizations.of(context)!.annotationFallback} ${idx + 1}';
|
||||||
return Card(
|
return Card(
|
||||||
margin:
|
margin:
|
||||||
const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
|
const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
|
||||||
@ -578,11 +579,11 @@ class _EventConfigState extends State<EventConfig> {
|
|||||||
eventDTO.globalMapAnnotations = updated;
|
eventDTO.globalMapAnnotations = updated;
|
||||||
});
|
});
|
||||||
showNotification(kSuccess, kWhite,
|
showNotification(kSuccess, kWhite,
|
||||||
'Annotation supprimée', context, null);
|
AppLocalizations.of(context)!.annotationDeletedSuccess, context, null);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(kError, kWhite,
|
showNotification(kError, kWhite,
|
||||||
'Erreur lors de la suppression', context, null);
|
AppLocalizations.of(context)!.annotationDeleteError, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
import 'package:manager_app/Components/string_input_container.dart';
|
import 'package:manager_app/Components/string_input_container.dart';
|
||||||
@ -102,7 +103,7 @@ void showNewOrUpdateMapAnnotation(
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: DropDownInputContainer(
|
child: DropDownInputContainer(
|
||||||
label: "Géométrie :",
|
label: AppLocalizations.of(context)!.geometryLabel,
|
||||||
values: geometryTypeLabels,
|
values: geometryTypeLabels,
|
||||||
initialValue: geometryTypeToLabel(working.geometryType),
|
initialValue: geometryTypeToLabel(working.geometryType),
|
||||||
onChange: (val) => setState(() =>
|
onChange: (val) => setState(() =>
|
||||||
@ -127,7 +128,7 @@ void showNewOrUpdateMapAnnotation(
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Icône (material) :",
|
label: AppLocalizations.of(context)!.materialIconLabel,
|
||||||
initialValue: working.icon ?? '',
|
initialValue: working.icon ?? '',
|
||||||
onChanged: (val) =>
|
onChanged: (val) =>
|
||||||
setState(() => working.icon = val.isEmpty ? null : val),
|
setState(() => working.icon = val.isEmpty ? null : val),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/confirmation_dialog.dart';
|
import 'package:manager_app/Components/confirmation_dialog.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
@ -112,12 +113,12 @@ void showNewOrUpdateProgrammeBlock(
|
|||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(Icons.schedule,
|
leading: Icon(Icons.schedule,
|
||||||
color: kPrimaryColor),
|
color: kPrimaryColor),
|
||||||
title: Text("Heure de début"),
|
title: Text(AppLocalizations.of(context)!.startTimeLabel),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
workingBlock.startTime != null
|
workingBlock.startTime != null
|
||||||
? DateFormat('HH:mm')
|
? DateFormat('HH:mm')
|
||||||
.format(workingBlock.startTime!.toLocal())
|
.format(workingBlock.startTime!.toLocal())
|
||||||
: "Non définie",
|
: AppLocalizations.of(context)!.notDefined,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
@ -161,12 +162,12 @@ void showNewOrUpdateProgrammeBlock(
|
|||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(Icons.schedule_outlined,
|
leading: Icon(Icons.schedule_outlined,
|
||||||
color: kPrimaryColor),
|
color: kPrimaryColor),
|
||||||
title: Text("Heure de fin"),
|
title: Text(AppLocalizations.of(context)!.endTimeLabel),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
workingBlock.endTime != null
|
workingBlock.endTime != null
|
||||||
? DateFormat('HH:mm')
|
? DateFormat('HH:mm')
|
||||||
.format(workingBlock.endTime!.toLocal())
|
.format(workingBlock.endTime!.toLocal())
|
||||||
: "Non définie",
|
: AppLocalizations.of(context)!.notDefined,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
@ -212,7 +213,7 @@ void showNewOrUpdateProgrammeBlock(
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Annotations",
|
Text(AppLocalizations.of(context)!.annotationsLabel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 15)),
|
fontSize: 15)),
|
||||||
@ -242,7 +243,7 @@ void showNewOrUpdateProgrammeBlock(
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(vertical: 8),
|
const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Aucune annotation configurée.",
|
AppLocalizations.of(context)!.noAnnotationConfigured,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
color: Colors.grey[600]),
|
color: Colors.grey[600]),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:manager_app/Components/resource_input_container.dart';
|
|||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/parcours_config.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/parcours_config.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
|
|
||||||
class GameConfig extends StatefulWidget {
|
class GameConfig extends StatefulWidget {
|
||||||
final String? color;
|
final String? color;
|
||||||
@ -148,8 +149,8 @@ class _GameConfigState extends State<GameConfig> {
|
|||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: MultiStringInputAndResourceContainer(
|
child: MultiStringInputAndResourceContainer(
|
||||||
label: "Message départ :",
|
label: AppLocalizations.of(context)!.startMessageLabel,
|
||||||
modalLabel: "Message départ",
|
modalLabel: AppLocalizations.of(context)!.startMessageModalLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: gameDTO.messageDebut ?? [],
|
initialValue: gameDTO.messageDebut ?? [],
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:manager_api_new/api.dart';
|
|||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/category_list.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/category_list.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
|
|
||||||
class CategoryInputContainer extends StatefulWidget {
|
class CategoryInputContainer extends StatefulWidget {
|
||||||
final Color color;
|
final Color color;
|
||||||
@ -51,7 +52,7 @@ class _CategoryInputContainerState extends State<CategoryInputContainer> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
List<CategorieDTO> newValues = <CategorieDTO>[];
|
List<CategorieDTO> newValues = <CategorieDTO>[];
|
||||||
showCreateOrUpdateCategories("Catégories", middleCategories, newValues, (value) {
|
showCreateOrUpdateCategories(AppLocalizations.of(context)!.categoriesTitle, middleCategories, newValues, (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
widget.onChanged(value);
|
widget.onChanged(value);
|
||||||
middleCategories = value;
|
middleCategories = value;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
|||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/new_update_categorie.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/new_update_categorie.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ class _CategoryListState extends State<CategoryList> {
|
|||||||
onTap: () async {
|
onTap: () async {
|
||||||
CategorieDTO newCategory = CategorieDTO(order: null);
|
CategorieDTO newCategory = CategorieDTO(order: null);
|
||||||
|
|
||||||
var result = await showNewOrUpdateCategory(newCategory, appContext, context, "Création catégorie", currentIndex);
|
var result = await showNewOrUpdateCategory(newCategory, appContext, context, AppLocalizations.of(context)!.createCategoryTitle, currentIndex);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -203,7 +204,7 @@ class _CategoryListState extends State<CategoryList> {
|
|||||||
message: "Modifier",
|
message: "Modifier",
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
var result = await showNewOrUpdateCategory(category, appContext, context, "Modification catégorie", currentIndex);
|
var result = await showNewOrUpdateCategory(category, appContext, context, AppLocalizations.of(context)!.editCategoryTitle, currentIndex);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/listVi
|
|||||||
import 'package:manager_app/Screens/Resources/select_resource_modal.dart';
|
import 'package:manager_app/Screens/Resources/select_resource_modal.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ class _GeoPointContentListState extends State<GeoPointContentList> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
var result = await showSelectResourceModal(
|
var result = await showSelectResourceModal(
|
||||||
"Sélectionner une ressource",
|
AppLocalizations.of(context)!.selectResource,
|
||||||
1,
|
1,
|
||||||
[ResourceType.Image, ResourceType.ImageUrl, ResourceType.Video, ResourceType.VideoUrl, ResourceType.Audio],
|
[ResourceType.Image, ResourceType.ImageUrl, ResourceType.Video, ResourceType.VideoUrl, ResourceType.Audio],
|
||||||
context,
|
context,
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/showNe
|
|||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/client.dart';
|
import 'package:manager_app/client.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/parcours_config.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/parcours_config.dart';
|
||||||
|
|
||||||
@ -137,8 +138,8 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
unselectedLabelColor: Colors.grey,
|
unselectedLabelColor: Colors.grey,
|
||||||
indicatorColor: kPrimaryColor,
|
indicatorColor: kPrimaryColor,
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(icon: Icon(Icons.map), text: "Points d'Intérêt"),
|
Tab(icon: Icon(Icons.map), text: AppLocalizations.of(context)!.pointsOfInterestLabel),
|
||||||
Tab(icon: Icon(Icons.route), text: "Parcours"),
|
Tab(icon: Icon(Icons.route), text: AppLocalizations.of(context)!.pathsLabel),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
@ -293,7 +294,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
top: 10,
|
top: 10,
|
||||||
left: 10,
|
left: 10,
|
||||||
child: Text(
|
child: Text(
|
||||||
"Points géographiques",
|
AppLocalizations.of(context)!.geopointsLabel,
|
||||||
style: TextStyle(fontSize: 15),
|
style: TextStyle(fontSize: 15),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -351,7 +352,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
constraints:
|
constraints:
|
||||||
BoxConstraints(minHeight: 85),
|
BoxConstraints(minHeight: 85),
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Recherche:",
|
label: AppLocalizations.of(context)!.searchLabel,
|
||||||
isSmall: true,
|
isSmall: true,
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontSizeText: 15,
|
fontSizeText: 15,
|
||||||
@ -379,7 +380,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Le point géographique a été créé avec succès',
|
AppLocalizations.of(context)!.geopointCreatedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -390,7 +391,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Une erreur est survenue lors de la création du point géographique',
|
AppLocalizations.of(context)!.geopointCreateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -428,7 +429,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Une erreur est survenue lors de la récupération des points géographiques"),
|
AppLocalizations.of(context)!.geopointsLoadError),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -507,7 +508,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Le point géographique a été mis à jour avec succès',
|
AppLocalizations.of(context)!.geopointUpdatedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -518,7 +519,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Une erreur est survenue lors de la mise à jour du point géographique',
|
AppLocalizations.of(context)!.geopointUpdateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -547,7 +548,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir supprimer ce point géographique ?",
|
AppLocalizations.of(context)!.geopointDeleteConfirm,
|
||||||
() {}, () async {
|
() {}, () async {
|
||||||
try {
|
try {
|
||||||
var pointToRemove = pointsToShow[index];
|
var pointToRemove = pointsToShow[index];
|
||||||
@ -558,7 +559,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Le point géographique a été supprimé avec succès',
|
AppLocalizations.of(context)!.geopointDeletedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
// refresh UI
|
// refresh UI
|
||||||
@ -569,7 +570,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Une erreur est survenue lors de la suppression du point géographique',
|
AppLocalizations.of(context)!.geopointDeleteError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -609,7 +610,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
SingleSelectContainer(
|
SingleSelectContainer(
|
||||||
label: "Service :",
|
label: AppLocalizations.of(context)!.serviceLabel,
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
initialValue: mapProviderIn,
|
initialValue: mapProviderIn,
|
||||||
inputValues: map_providers,
|
inputValues: map_providers,
|
||||||
@ -625,7 +626,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
widget.onChanged(mapDTO);
|
widget.onChanged(mapDTO);
|
||||||
}),
|
}),
|
||||||
GeolocInputContainer(
|
GeolocInputContainer(
|
||||||
label: "Point de centrage :",
|
label: AppLocalizations.of(context)!.centerPointLabel,
|
||||||
initialValue: mapDTO.centerLatitude != null &&
|
initialValue: mapDTO.centerLatitude != null &&
|
||||||
mapDTO.centerLongitude != null
|
mapDTO.centerLongitude != null
|
||||||
? LatLong(double.parse(mapDTO.centerLatitude!),
|
? LatLong(double.parse(mapDTO.centerLatitude!),
|
||||||
@ -642,7 +643,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
},
|
},
|
||||||
isSmall: true),
|
isSmall: true),
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Icône :",
|
label: AppLocalizations.of(context)!.iconLabel,
|
||||||
initialValue: mapDTO.iconResourceId,
|
initialValue: mapDTO.iconResourceId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
imageFit: BoxFit.contain,
|
imageFit: BoxFit.contain,
|
||||||
@ -664,7 +665,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
CheckInputContainer(
|
CheckInputContainer(
|
||||||
label: "Vue liste :",
|
label: AppLocalizations.of(context)!.listViewLabel,
|
||||||
isChecked: mapDTO.isListViewEnabled ?? false,
|
isChecked: mapDTO.isListViewEnabled ?? false,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -675,7 +676,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
),
|
),
|
||||||
if (mapDTO.mapProvider == MapProvider.Google)
|
if (mapDTO.mapProvider == MapProvider.Google)
|
||||||
DropDownInputContainer(
|
DropDownInputContainer(
|
||||||
label: "Type :",
|
label: AppLocalizations.of(context)!.typeLabel,
|
||||||
values: map_types,
|
values: map_types,
|
||||||
initialValue: mapType,
|
initialValue: mapType,
|
||||||
onChange: (String? value) {
|
onChange: (String? value) {
|
||||||
@ -685,7 +686,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
),
|
),
|
||||||
if (mapDTO.mapProvider == MapProvider.MapBox)
|
if (mapDTO.mapProvider == MapProvider.MapBox)
|
||||||
DropDownInputContainer(
|
DropDownInputContainer(
|
||||||
label: "Type :",
|
label: AppLocalizations.of(context)!.typeLabel,
|
||||||
values: map_types_mapBox,
|
values: map_types_mapBox,
|
||||||
initialValue: mapTypeMapBox,
|
initialValue: mapTypeMapBox,
|
||||||
onChange: (String? value) {
|
onChange: (String? value) {
|
||||||
@ -694,7 +695,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
SliderInputContainer(
|
SliderInputContainer(
|
||||||
label: "Zoom :",
|
label: AppLocalizations.of(context)!.zoomLabel,
|
||||||
initialValue:
|
initialValue:
|
||||||
mapDTO.zoom != null ? mapDTO.zoom!.toDouble() : 18,
|
mapDTO.zoom != null ? mapDTO.zoom!.toDouble() : 18,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
@ -708,7 +709,7 @@ class _MapConfigState extends State<MapConfig> {
|
|||||||
Container(
|
Container(
|
||||||
height: 70,
|
height: 70,
|
||||||
child: CategoryInputContainer(
|
child: CategoryInputContainer(
|
||||||
label: "Catégories :",
|
label: AppLocalizations.of(context)!.categoriesLabel,
|
||||||
initialValue:
|
initialValue:
|
||||||
mapDTO.categories != null ? mapDTO.categories! : [],
|
mapDTO.categories != null ? mapDTO.categories! : [],
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:manager_app/Components/rounded_button.dart';
|
|||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
Future<CategorieDTO?> showNewOrUpdateCategory(CategorieDTO? inputCategorieDTO, AppContext appContext, BuildContext context, String text, int currentIndex) async {
|
Future<CategorieDTO?> showNewOrUpdateCategory(CategorieDTO? inputCategorieDTO, AppContext appContext, BuildContext context, String text, int currentIndex) async {
|
||||||
@ -60,7 +61,7 @@ Future<CategorieDTO?> showNewOrUpdateCategory(CategorieDTO? inputCategorieDTO, A
|
|||||||
height: size.height * 0.2,
|
height: size.height * 0.2,
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Nom affiché :",
|
label: AppLocalizations.of(context)!.displayedNameLabel,
|
||||||
modalLabel: text,
|
modalLabel: text,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
@ -79,7 +80,7 @@ Future<CategorieDTO?> showNewOrUpdateCategory(CategorieDTO? inputCategorieDTO, A
|
|||||||
height: size.height * 0.2,
|
height: size.height * 0.2,
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||||
child: ResourceInputContainer(
|
child: ResourceInputContainer(
|
||||||
label: "Icône catégorie :",
|
label: AppLocalizations.of(context)!.categoryIconLabel,
|
||||||
initialValue: categorieDTO.resourceDTO?.id,
|
initialValue: categorieDTO.resourceDTO?.id,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (ResourceDTO resource) {
|
onChanged: (ResourceDTO resource) {
|
||||||
@ -124,7 +125,7 @@ Future<CategorieDTO?> showNewOrUpdateCategory(CategorieDTO? inputCategorieDTO, A
|
|||||||
width: inputCategorieDTO != null ? 220: 150,
|
width: inputCategorieDTO != null ? 220: 150,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: inputCategorieDTO != null ? "Sauvegarder" : "Créer",
|
text: inputCategorieDTO != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import 'package:manager_app/Models/managerContext.dart';
|
|||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/geopoint_image_list.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/geopoint_image_list.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO,
|
void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO,
|
||||||
@ -67,7 +68,7 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO,
|
|||||||
children: [
|
children: [
|
||||||
// Titre du dialog
|
// Titre du dialog
|
||||||
Text(
|
Text(
|
||||||
"Point géographique / Zone",
|
AppLocalizations.of(context)!.geopointZoneTitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
@ -82,7 +83,7 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO,
|
|||||||
children: [
|
children: [
|
||||||
// Géométrie
|
// Géométrie
|
||||||
GeometryInputContainer(
|
GeometryInputContainer(
|
||||||
label: "Géométrie (Point/Ligne/Zone) :",
|
label: AppLocalizations.of(context)!.geometryTypeLabel,
|
||||||
initialGeometry: geoPointDTO.geometry,
|
initialGeometry: geoPointDTO.geometry,
|
||||||
initialColor: geoPointDTO.polyColor,
|
initialColor: geoPointDTO.polyColor,
|
||||||
onSave: (geometry, color) {
|
onSave: (geometry, color) {
|
||||||
@ -176,7 +177,7 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO,
|
|||||||
width: thirdWidth,
|
width: thirdWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Tel :",
|
label: "Tel :",
|
||||||
modalLabel: "Téléphone",
|
modalLabel: AppLocalizations.of(context)!.phoneModalLabel,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
@ -255,7 +256,7 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO,
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: thirdWidth,
|
width: thirdWidth,
|
||||||
child: DropDownInputContainerCategories(
|
child: DropDownInputContainerCategories(
|
||||||
label: "Catégorie :",
|
label: AppLocalizations.of(context)!.categoryLabel,
|
||||||
categories: mapDTO.categories!,
|
categories: mapDTO.categories!,
|
||||||
initialValue: geoPointDTO.categorieId,
|
initialValue: geoPointDTO.categorieId,
|
||||||
onChange: (CategorieDTO? value) {
|
onChange: (CategorieDTO? value) {
|
||||||
@ -326,7 +327,7 @@ void showNewOrUpdateGeoPoint(MapDTO mapDTO, GeoPointDTO? inputGeoPointDTO,
|
|||||||
height: 46,
|
height: 46,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text:
|
text:
|
||||||
geoPointDTO.id != null ? "Sauvegarder" : "Créer",
|
geoPointDTO.id != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_app/Components/confirmation_dialog.dart';
|
import 'package:manager_app/Components/confirmation_dialog.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/fetch_section_icon.dart';
|
import 'package:manager_app/Components/fetch_section_icon.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
@ -63,17 +64,18 @@ class _ListViewCardSubSection extends State<ListViewCardSubSection> {
|
|||||||
showEditSubSection(
|
showEditSubSection(
|
||||||
widget.listItems[widget.index],
|
widget.listItems[widget.index],
|
||||||
(Object value) async {
|
(Object value) async {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
try {
|
try {
|
||||||
var test = updateSectionDetail(widget.listItems[widget.index], value);
|
var test = updateSectionDetail(widget.listItems[widget.index], value);
|
||||||
// update sub section
|
// update sub section
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionApi!.sectionUpdate(test);
|
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionApi!.sectionUpdate(test);
|
||||||
showNotification(kSuccess, kWhite, "La sous section a été mis à jour avec succès", context, null);
|
showNotification(kSuccess, kWhite, l.subSectionUpdatedSuccess, context, null);
|
||||||
setState(() {
|
setState(() {
|
||||||
//widget.listItems[widget.index] = value;
|
//widget.listItems[widget.index] = value;
|
||||||
widget.onChanged(widget.listItems); // For resfreh ui
|
widget.onChanged(widget.listItems); // For resfreh ui
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, "Une erreur est survenue lors de la mise à jour de la sous section", context, null);
|
showNotification(kError, kWhite, l.subSectionUpdateError, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
widget.appContext,
|
widget.appContext,
|
||||||
@ -92,19 +94,20 @@ class _ListViewCardSubSection extends State<ListViewCardSubSection> {
|
|||||||
),
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir supprimer cette sous section ?",
|
l.sectionDeleteConfirm,
|
||||||
() {},
|
() {},
|
||||||
() async {
|
() async {
|
||||||
try {
|
try {
|
||||||
var sectionToDelete = widget.listItems[widget.index];
|
var sectionToDelete = widget.listItems[widget.index];
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
await managerAppContext.clientAPI!.sectionApi!.sectionDelete(sectionToDelete.id!);
|
await managerAppContext.clientAPI!.sectionApi!.sectionDelete(sectionToDelete.id!);
|
||||||
showNotification(kSuccess, kWhite, 'La sous section a été supprimée avec succès', context, null);
|
showNotification(kSuccess, kWhite, l.subSectionDeletedSuccess, context, null);
|
||||||
// refresh UI
|
// refresh UI
|
||||||
widget.onChanged(widget.listItems);
|
widget.onChanged(widget.listItems);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors de la suppression de la sous section', context, null);
|
showNotification(kError, kWhite, l.subSectionDeleteError, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'dart:js_interop';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Menu/listView_card_subSection.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Menu/listView_card_subSection.dart';
|
||||||
@ -63,13 +64,13 @@ class _MenuConfigState extends State<MenuConfig> {
|
|||||||
|
|
||||||
item.order = newIndex;
|
item.order = newIndex;
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionApi!.sectionUpdate(item);
|
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionApi!.sectionUpdate(item);
|
||||||
showNotification(kSuccess, kWhite, "L'ordre des sous sections a été mis à jour avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.subSectionOrderUpdatedSuccess, context, null);
|
||||||
setState(() {
|
setState(() {
|
||||||
// refresh ui
|
// refresh ui
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, "Une erreur est survenue lors de la mise à jour de l'ordre des sous sections", context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.subSectionOrderUpdateError, context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*setState(
|
/*setState(
|
||||||
@ -143,7 +144,7 @@ class _MenuConfigState extends State<MenuConfig> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Center(child: Text(
|
return Center(child: Text(
|
||||||
"Une erreur est survenue lors de la récupération des sous sections"));
|
AppLocalizations.of(context)!.errorOccurred));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,14 +169,14 @@ class _MenuConfigState extends State<MenuConfig> {
|
|||||||
newSubsection.isBeacon = false;
|
newSubsection.isBeacon = false;
|
||||||
newSubsection.isActive = true;
|
newSubsection.isActive = true;
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionApi!.sectionCreate(newSubsection);
|
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionApi!.sectionCreate(newSubsection);
|
||||||
showNotification(kSuccess, kWhite, 'La sous section a été créée avec succès', context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.subSectionCreatedSuccess, context, null);
|
||||||
setState(() {
|
setState(() {
|
||||||
// refresh ui
|
// refresh ui
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors de la création de la sous section', context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.subSectionCreateError, context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import 'package:manager_app/Screens/Configurations/Section/SubSection/Weather/we
|
|||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/WebOrVideo/web_config.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/WebOrVideo/web_config.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
import 'menu_config.dart';
|
import 'menu_config.dart';
|
||||||
@ -77,7 +78,7 @@ void showEditSubSection(SectionDTO subSectionDTO, Function getResult, AppContext
|
|||||||
Container(
|
Container(
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Titre affiché:",
|
label: AppLocalizations.of(context)!.displayTitleLabel,
|
||||||
modalLabel: "Titre",
|
modalLabel: "Titre",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
@ -95,7 +96,7 @@ void showEditSubSection(SectionDTO subSectionDTO, Function getResult, AppContext
|
|||||||
Container(
|
Container(
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Description affichée:",
|
label: AppLocalizations.of(context)!.displayedDescriptionLabel,
|
||||||
modalLabel: "Description",
|
modalLabel: "Description",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
@ -129,7 +130,7 @@ void showEditSubSection(SectionDTO subSectionDTO, Function getResult, AppContext
|
|||||||
appContext,
|
appContext,
|
||||||
(updatedData) {
|
(updatedData) {
|
||||||
updatedRawSubSectionData = updatedData;
|
updatedRawSubSectionData = updatedData;
|
||||||
}),
|
}, context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -183,7 +184,7 @@ void showEditSubSection(SectionDTO subSectionDTO, Function getResult, AppContext
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSpecificData(SectionDTO subSectionDTO, Object? rawSectionData, Object sectionDetailDTO, AppContext appContext, Function(Object) onChanged) {
|
getSpecificData(SectionDTO subSectionDTO, Object? rawSectionData, Object sectionDetailDTO, AppContext appContext, Function(Object) onChanged, [BuildContext? context]) {
|
||||||
switch(subSectionDTO.type) {
|
switch(subSectionDTO.type) {
|
||||||
case SectionType.Map:
|
case SectionType.Map:
|
||||||
MapDTO mapDTO = MapDTO.fromJson(rawSectionData)!;
|
MapDTO mapDTO = MapDTO.fromJson(rawSectionData)!;
|
||||||
@ -207,7 +208,7 @@ getSpecificData(SectionDTO subSectionDTO, Object? rawSectionData, Object section
|
|||||||
VideoDTO videoDTO = VideoDTO.fromJson(rawSectionData)!;
|
VideoDTO videoDTO = VideoDTO.fromJson(rawSectionData)!;
|
||||||
sectionDetailDTO = videoDTO;
|
sectionDetailDTO = videoDTO;
|
||||||
return VideoConfig(
|
return VideoConfig(
|
||||||
label: "Url de la vidéo:",
|
label: context != null ? AppLocalizations.of(context)!.videoUrlLabel : "Url de la vidéo:",
|
||||||
initialValue: videoDTO,
|
initialValue: videoDTO,
|
||||||
onChanged: (VideoDTO updatedWebDTO) {
|
onChanged: (VideoDTO updatedWebDTO) {
|
||||||
onChanged(updatedWebDTO);
|
onChanged(updatedWebDTO);
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import 'package:manager_app/Components/rounded_button.dart';
|
|||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
Future<OrderedTranslationAndResourceDTO?> showNewOrUpdatePDFFile(OrderedTranslationAndResourceDTO? inputPdfFile, AppContext appContext, BuildContext context, String text) async {
|
Future<OrderedTranslationAndResourceDTO?> showNewOrUpdatePDFFile(OrderedTranslationAndResourceDTO? inputPdfFile, AppContext appContext, BuildContext context, String text) async {
|
||||||
@ -81,7 +82,7 @@ Future<OrderedTranslationAndResourceDTO?> showNewOrUpdatePDFFile(OrderedTranslat
|
|||||||
height: size.height * 0.2,
|
height: size.height * 0.2,
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||||
child: ResourceInputContainer(
|
child: ResourceInputContainer(
|
||||||
label: "Icône catégorie :",
|
label: AppLocalizations.of(context)!.categoryIconLabel,
|
||||||
initialValue: categorieDTO.iconResourceId,
|
initialValue: categorieDTO.iconResourceId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (ResourceDTO resource) {
|
onChanged: (ResourceDTO resource) {
|
||||||
@ -130,7 +131,7 @@ Future<OrderedTranslationAndResourceDTO?> showNewOrUpdatePDFFile(OrderedTranslat
|
|||||||
width: inputPdfFile != null ? 220: 150,
|
width: inputPdfFile != null ? 220: 150,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: inputPdfFile != null ? "Sauvegarder" : "Créer",
|
text: inputPdfFile != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:manager_app/Screens/Configurations/Section/SubSection/Map/new_up
|
|||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/PDF/new_update_pdfFile.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/PDF/new_update_pdfFile.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ class _PDFListState extends State<PDFList> {
|
|||||||
onTap: () async {
|
onTap: () async {
|
||||||
OrderedTranslationAndResourceDTO newPdfFile = OrderedTranslationAndResourceDTO(order: null);
|
OrderedTranslationAndResourceDTO newPdfFile = OrderedTranslationAndResourceDTO(order: null);
|
||||||
|
|
||||||
var result = await showNewOrUpdatePDFFile(newPdfFile, appContext, context, "Création PDF");
|
var result = await showNewOrUpdatePDFFile(newPdfFile, appContext, context, AppLocalizations.of(context)!.createPdfTitle);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:manager_app/constants.dart';
|
|||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/showNewOrUpdateGuidedPath.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/showNewOrUpdateGuidedPath.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
|
|
||||||
@ -68,11 +69,11 @@ class _ParcoursConfigState extends State<ParcoursConfig> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Parcours Guidés",
|
Text(AppLocalizations.of(context)!.guidedPathsLabel,
|
||||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
icon: Icon(Icons.add),
|
icon: Icon(Icons.add),
|
||||||
label: Text("Ajouter un parcours"),
|
label: Text(AppLocalizations.of(context)!.addPath),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final appContext =
|
final appContext =
|
||||||
Provider.of<AppContext>(context, listen: false);
|
Provider.of<AppContext>(context, listen: false);
|
||||||
@ -111,13 +112,13 @@ class _ParcoursConfigState extends State<ParcoursConfig> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
showNotification(kSuccess, kWhite,
|
showNotification(kSuccess, kWhite,
|
||||||
'Parcours créé avec succès', context, null);
|
AppLocalizations.of(context)!.pathCreatedSuccess, context, null);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la création du parcours',
|
AppLocalizations.of(context)!.pathCreateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
rethrow; // Important so showNewOrUpdateGuidedPath knows it failed
|
rethrow; // Important so showNewOrUpdateGuidedPath knows it failed
|
||||||
@ -134,7 +135,7 @@ class _ParcoursConfigState extends State<ParcoursConfig> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: paths.isEmpty
|
child: paths.isEmpty
|
||||||
? Center(
|
? Center(
|
||||||
child: Text("Aucun parcours configuré",
|
child: Text(AppLocalizations.of(context)!.noPathConfigured,
|
||||||
style: TextStyle(fontStyle: FontStyle.italic)))
|
style: TextStyle(fontStyle: FontStyle.italic)))
|
||||||
: ReorderableListView.builder(
|
: ReorderableListView.builder(
|
||||||
buildDefaultDragHandles: false,
|
buildDefaultDragHandles: false,
|
||||||
@ -164,7 +165,7 @@ class _ParcoursConfigState extends State<ParcoursConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la mise à jour de l\'ordre',
|
AppLocalizations.of(context)!.pathOrderUpdateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -185,10 +186,10 @@ class _ParcoursConfigState extends State<ParcoursConfig> {
|
|||||||
.firstWhere((t) => t.language == 'FR',
|
.firstWhere((t) => t.language == 'FR',
|
||||||
orElse: () => path.title![0])
|
orElse: () => path.title![0])
|
||||||
.value ??
|
.value ??
|
||||||
"Parcours sans titre",
|
AppLocalizations.of(context)!.pathNoTitle,
|
||||||
)
|
)
|
||||||
: Text("Parcours sans titre"),
|
: Text(AppLocalizations.of(context)!.pathNoTitle),
|
||||||
subtitle: Text("${path.steps?.length ?? 0} étapes"),
|
subtitle: Text(AppLocalizations.of(context)!.stepsCount(path.steps?.length ?? 0)),
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@ -223,7 +224,7 @@ class _ParcoursConfigState extends State<ParcoursConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Parcours mis à jour avec succès',
|
AppLocalizations.of(context)!.pathUpdatedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -231,7 +232,7 @@ class _ParcoursConfigState extends State<ParcoursConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la mise à jour du parcours',
|
AppLocalizations.of(context)!.pathUpdateError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
rethrow;
|
rethrow;
|
||||||
@ -265,14 +266,14 @@ class _ParcoursConfigState extends State<ParcoursConfig> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Parcours supprimé avec succès',
|
AppLocalizations.of(context)!.pathDeletedSuccess,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showNotification(
|
showNotification(
|
||||||
kError,
|
kError,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Erreur lors de la suppression du parcours',
|
AppLocalizations.of(context)!.pathDeleteError,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
import 'package:manager_app/Components/check_input_container.dart';
|
import 'package:manager_app/Components/check_input_container.dart';
|
||||||
@ -107,7 +108,7 @@ void showNewOrUpdateGuidedPath(
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: thirdWidth,
|
width: thirdWidth,
|
||||||
child: CheckInputContainer(
|
child: CheckInputContainer(
|
||||||
label: "Linéaire :",
|
label: AppLocalizations.of(context)!.linearLabel,
|
||||||
isChecked: workingPath.isLinear ?? false,
|
isChecked: workingPath.isLinear ?? false,
|
||||||
onChanged: (val) => setState(
|
onChanged: (val) => setState(
|
||||||
() => workingPath.isLinear = val),
|
() => workingPath.isLinear = val),
|
||||||
@ -117,7 +118,7 @@ void showNewOrUpdateGuidedPath(
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: thirdWidth,
|
width: thirdWidth,
|
||||||
child: CheckInputContainer(
|
child: CheckInputContainer(
|
||||||
label: "Réussite requise :",
|
label: AppLocalizations.of(context)!.requiredSuccessLabel,
|
||||||
isChecked:
|
isChecked:
|
||||||
workingPath.requireSuccessToAdvance ??
|
workingPath.requireSuccessToAdvance ??
|
||||||
false,
|
false,
|
||||||
@ -144,7 +145,7 @@ void showNewOrUpdateGuidedPath(
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Étapes du parcours",
|
Text(AppLocalizations.of(context)!.pathStepsLabel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 15)),
|
fontSize: 15)),
|
||||||
@ -174,7 +175,7 @@ void showNewOrUpdateGuidedPath(
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Aucun point/étape configuré.",
|
AppLocalizations.of(context)!.noStepConfigured,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
color: Colors.grey[600]),
|
color: Colors.grey[600]),
|
||||||
@ -198,8 +199,8 @@ void showNewOrUpdateGuidedPath(
|
|||||||
orElse: () =>
|
orElse: () =>
|
||||||
step.title![0])
|
step.title![0])
|
||||||
.value ??
|
.value ??
|
||||||
"Étape $index"
|
"${AppLocalizations.of(context)!.stepFallback} $index"
|
||||||
: "Étape $index",
|
: "${AppLocalizations.of(context)!.stepFallback} $index",
|
||||||
),
|
),
|
||||||
subtitle: isEscapeMode
|
subtitle: isEscapeMode
|
||||||
? Text(
|
? Text(
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import 'package:manager_app/Components/multi_string_input_container.dart';
|
|||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/string_input_container.dart';
|
import 'package:manager_app/Components/string_input_container.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'showNewOrUpdateQuizQuestion.dart';
|
import 'showNewOrUpdateQuizQuestion.dart';
|
||||||
|
|
||||||
void showNewOrUpdateGuidedStep(
|
void showNewOrUpdateGuidedStep(
|
||||||
@ -53,7 +54,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
step == null ? "Nouvelle Étape" : "Modifier l'Étape",
|
step == null ? AppLocalizations.of(context)!.newStepTitle : AppLocalizations.of(context)!.editStepTitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
@ -72,7 +73,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Titre :",
|
label: "Titre :",
|
||||||
modalLabel: "Titre de l'étape",
|
modalLabel: AppLocalizations.of(context)!.stepTitleLabel,
|
||||||
initialValue: workingStep.title ?? [],
|
initialValue: workingStep.title ?? [],
|
||||||
onGetResult: (val) =>
|
onGetResult: (val) =>
|
||||||
setState(() => workingStep.title = val),
|
setState(() => workingStep.title = val),
|
||||||
@ -86,7 +87,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Description :",
|
label: "Description :",
|
||||||
modalLabel: "Description de l'étape",
|
modalLabel: AppLocalizations.of(context)!.stepDescriptionLabel,
|
||||||
initialValue: workingStep.description ?? [],
|
initialValue: workingStep.description ?? [],
|
||||||
onGetResult: (val) => setState(
|
onGetResult: (val) => setState(
|
||||||
() => workingStep.description = val),
|
() => workingStep.description = val),
|
||||||
@ -100,7 +101,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
Divider(height: 24),
|
Divider(height: 24),
|
||||||
// Géométrie — Directement avec GeometryDTO
|
// Géométrie — Directement avec GeometryDTO
|
||||||
GeometryInputContainer(
|
GeometryInputContainer(
|
||||||
label: "Emplacement de l'étape :",
|
label: AppLocalizations.of(context)!.stepLocationLabel,
|
||||||
initialGeometry: workingStep.geometry,
|
initialGeometry: workingStep.geometry,
|
||||||
initialColor: null,
|
initialColor: null,
|
||||||
onSave: (geometry, color) {
|
onSave: (geometry, color) {
|
||||||
@ -118,7 +119,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: SwitchListTile(
|
child: SwitchListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
title: Text("Cachée initialement"),
|
title: Text(AppLocalizations.of(context)!.initiallyHiddenLabel),
|
||||||
value: workingStep.isHiddenInitially ?? false,
|
value: workingStep.isHiddenInitially ?? false,
|
||||||
onChanged: (val) => setState(() => workingStep.isHiddenInitially = val),
|
onChanged: (val) => setState(() => workingStep.isHiddenInitially = val),
|
||||||
activeThumbColor: kPrimaryColor,
|
activeThumbColor: kPrimaryColor,
|
||||||
@ -127,7 +128,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: SwitchListTile(
|
child: SwitchListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
title: Text("Verrouillée"),
|
title: Text(AppLocalizations.of(context)!.lockedLabel),
|
||||||
value: workingStep.isStepLocked ?? false,
|
value: workingStep.isStepLocked ?? false,
|
||||||
onChanged: (val) => setState(() => workingStep.isStepLocked = val),
|
onChanged: (val) => setState(() => workingStep.isStepLocked = val),
|
||||||
activeThumbColor: kPrimaryColor,
|
activeThumbColor: kPrimaryColor,
|
||||||
@ -151,7 +152,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: halfWidth,
|
width: halfWidth,
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Durée (secondes) :",
|
label: AppLocalizations.of(context)!.durationSecondsLabel,
|
||||||
initialValue: workingStep.timerSeconds?.toString() ?? "",
|
initialValue: workingStep.timerSeconds?.toString() ?? "",
|
||||||
onChanged: (val) => setState(() =>
|
onChanged: (val) => setState(() =>
|
||||||
workingStep.timerSeconds = int.tryParse(val)),
|
workingStep.timerSeconds = int.tryParse(val)),
|
||||||
@ -176,7 +177,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
],
|
],
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
StringInputContainer(
|
StringInputContainer(
|
||||||
label: "GeoPoint de déclenchement (ID) :",
|
label: AppLocalizations.of(context)!.triggerGeopointLabel,
|
||||||
initialValue: workingStep.triggerGeoPointId?.toString() ?? "",
|
initialValue: workingStep.triggerGeoPointId?.toString() ?? "",
|
||||||
onChanged: (val) => setState(() =>
|
onChanged: (val) => setState(() =>
|
||||||
workingStep.triggerGeoPointId = int.tryParse(val)),
|
workingStep.triggerGeoPointId = int.tryParse(val)),
|
||||||
@ -187,7 +188,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Questions / Défis",
|
Text(AppLocalizations.of(context)!.questionsChallengesLabel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 15)),
|
fontSize: 15)),
|
||||||
@ -220,7 +221,7 @@ void showNewOrUpdateGuidedStep(
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(vertical: 8),
|
const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Aucune question configurée.",
|
AppLocalizations.of(context)!.noQuestionsConfigured,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
color: Colors.grey[600]),
|
color: Colors.grey[600]),
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
import 'package:manager_app/Components/resource_input_container.dart';
|
import 'package:manager_app/Components/resource_input_container.dart';
|
||||||
@ -104,8 +105,8 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
children: [
|
children: [
|
||||||
// --- Intitulé (multi-langue via MultiStringInputContainer) ---
|
// --- Intitulé (multi-langue via MultiStringInputContainer) ---
|
||||||
MultiStringInputContainer(
|
MultiStringInputContainer(
|
||||||
label: "Question posée :",
|
label: AppLocalizations.of(context)!.questionAskedLabel,
|
||||||
modalLabel: "Intitulé de la question",
|
modalLabel: AppLocalizations.of(context)!.questionTitleLabel,
|
||||||
initialValue: workingLabel,
|
initialValue: workingLabel,
|
||||||
onGetResult: (val) => setState(() {
|
onGetResult: (val) => setState(() {
|
||||||
workingLabel = val;
|
workingLabel = val;
|
||||||
@ -146,7 +147,7 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
if (workingQuestion.validationQuestionType ==
|
if (workingQuestion.validationQuestionType ==
|
||||||
QuestionType.number0) ...[
|
QuestionType.number0) ...[
|
||||||
Divider(height: 24),
|
Divider(height: 24),
|
||||||
Text("Réponse attendue :",
|
Text(AppLocalizations.of(context)!.expectedAnswerLabel,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
Builder(builder: (_) {
|
Builder(builder: (_) {
|
||||||
@ -156,7 +157,7 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
workingQuestion.responses[0].label);
|
workingQuestion.responses[0].label);
|
||||||
return MultiStringInputContainer(
|
return MultiStringInputContainer(
|
||||||
label: "",
|
label: "",
|
||||||
modalLabel: "Réponse attendue",
|
modalLabel: AppLocalizations.of(context)!.expectedAnswerModalLabel,
|
||||||
initialValue: respLabel,
|
initialValue: respLabel,
|
||||||
onGetResult: (val) => setState(() {
|
onGetResult: (val) => setState(() {
|
||||||
workingQuestion.responses[0].label =
|
workingQuestion.responses[0].label =
|
||||||
@ -170,7 +171,7 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
}),
|
}),
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
"La validation se fait par comparaison (insensible à la casse).",
|
AppLocalizations.of(context)!.validationNote,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
@ -187,7 +188,7 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text("Réponses possibles :",
|
Text(AppLocalizations.of(context)!.possibleAnswersLabel,
|
||||||
style:
|
style:
|
||||||
TextStyle(fontWeight: FontWeight.bold)),
|
TextStyle(fontWeight: FontWeight.bold)),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
@ -208,7 +209,7 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(vertical: 8),
|
const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Aucune réponse définie. Ajoutez-en au moins une.",
|
AppLocalizations.of(context)!.noAnswerDefined,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
color: Colors.grey[600]),
|
color: Colors.grey[600]),
|
||||||
@ -233,8 +234,8 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
// Checkbox bonne réponse
|
// Checkbox bonne réponse
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: resp.isGood == true
|
message: resp.isGood == true
|
||||||
? "Bonne réponse ✓"
|
? AppLocalizations.of(context)!.correctAnswer
|
||||||
: "Mauvaise réponse",
|
: AppLocalizations.of(context)!.wrongAnswer,
|
||||||
child: Checkbox(
|
child: Checkbox(
|
||||||
value: resp.isGood ?? false,
|
value: resp.isGood ?? false,
|
||||||
activeColor: kSuccess,
|
activeColor: kSuccess,
|
||||||
@ -245,8 +246,8 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
// Traductions (via MultiStringInputContainer)
|
// Traductions (via MultiStringInputContainer)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Réponse ${i + 1} :",
|
label: "${AppLocalizations.of(context)!.answerLabel} ${i + 1} :",
|
||||||
modalLabel: "Réponse ${i + 1}",
|
modalLabel: "${AppLocalizations.of(context)!.answerLabel} ${i + 1}",
|
||||||
initialValue: respLabel,
|
initialValue: respLabel,
|
||||||
onGetResult: (val) => setState(
|
onGetResult: (val) => setState(
|
||||||
() => resp.label =
|
() => resp.label =
|
||||||
@ -273,7 +274,7 @@ void showNewOrUpdateQuizQuestion(
|
|||||||
),
|
),
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
"✓ = bonne réponse. Plusieurs peuvent être correctes.",
|
AppLocalizations.of(context)!.answerNote,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:manager_app/Models/managerContext.dart';
|
|||||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Quizz/quizz_answer_list.dart';
|
import 'package:manager_app/Screens/Configurations/Section/SubSection/Quizz/quizz_answer_list.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO, AppContext appContext, BuildContext context, String text) async {
|
Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO, AppContext appContext, BuildContext context, String text) async {
|
||||||
@ -54,7 +55,7 @@ Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO,
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Image fond d'écran :",
|
label: AppLocalizations.of(context)!.backgroundImageLabel,
|
||||||
initialValue: questionDTO.imageBackgroundResourceId,
|
initialValue: questionDTO.imageBackgroundResourceId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (ResourceDTO resource) {
|
onChanged: (ResourceDTO resource) {
|
||||||
@ -75,8 +76,8 @@ Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO,
|
|||||||
height: size.height * 0.15,
|
height: size.height * 0.15,
|
||||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||||
child: MultiStringInputAndResourceContainer(
|
child: MultiStringInputAndResourceContainer(
|
||||||
label: "Question :",
|
label: AppLocalizations.of(context)!.questionInputLabel,
|
||||||
modalLabel: "Question",
|
modalLabel: AppLocalizations.of(context)!.questionLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
resourceTypes: [ResourceType.Image, ResourceType.ImageUrl, ResourceType.Video, ResourceType.VideoUrl, ResourceType.Audio],
|
resourceTypes: [ResourceType.Image, ResourceType.ImageUrl, ResourceType.Video, ResourceType.VideoUrl, ResourceType.Audio],
|
||||||
@ -133,7 +134,7 @@ Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO,
|
|||||||
width: 175,
|
width: 175,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Annuler",
|
text: AppLocalizations.of(context)!.cancel,
|
||||||
icon: Icons.undo,
|
icon: Icons.undo,
|
||||||
color: kSecond,
|
color: kSecond,
|
||||||
press: () {
|
press: () {
|
||||||
@ -149,7 +150,7 @@ Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO,
|
|||||||
width: inputQuestionDTO != null ? 220: 150,
|
width: inputQuestionDTO != null ? 220: 150,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: inputQuestionDTO != null ? "Sauvegarder" : "Créer",
|
text: inputQuestionDTO != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
@ -157,7 +158,7 @@ Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO,
|
|||||||
if(!questionDTO.label!.any((label) => label.value == null || label.value!.trim() == "")) {
|
if(!questionDTO.label!.any((label) => label.value == null || label.value!.trim() == "")) {
|
||||||
Navigator.pop(dialogContext, questionDTO);
|
Navigator.pop(dialogContext, questionDTO);
|
||||||
} else {
|
} else {
|
||||||
showNotification(kPrimaryColor, kWhite, "La traduction n'est pas complète", context, null);
|
showNotification(kPrimaryColor, kWhite, AppLocalizations.of(context)!.translationIncomplete, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
|||||||
import 'package:manager_app/Components/multi_string_input_html_modal.dart';
|
import 'package:manager_app/Components/multi_string_input_html_modal.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -92,7 +93,7 @@ class _QuizzResponseListState extends State<QuizzResponseList> {
|
|||||||
top: 10,
|
top: 10,
|
||||||
left: 10,
|
left: 10,
|
||||||
child: Text(
|
child: Text(
|
||||||
"Réponses",
|
AppLocalizations.of(context)!.answersLabel,
|
||||||
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
|
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -117,7 +118,7 @@ class _QuizzResponseListState extends State<QuizzResponseList> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
showMultiStringInputAndResourceHTML("Réponse", "Créer la réponse", true, initials, newValues, (value) {
|
showMultiStringInputAndResourceHTML(AppLocalizations.of(context)!.answerLabel, AppLocalizations.of(context)!.createAnswerTitle, true, initials, newValues, (value) {
|
||||||
if(value != null && value.isNotEmpty) {
|
if(value != null && value.isNotEmpty) {
|
||||||
setState(() {
|
setState(() {
|
||||||
newResponse.label = value;
|
newResponse.label = value;
|
||||||
@ -184,7 +185,7 @@ class _QuizzResponseListState extends State<QuizzResponseList> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: "Si coché, la réponse est valide",
|
message: AppLocalizations.of(context)!.answerValidNote,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Checkbox(
|
child: Checkbox(
|
||||||
@ -217,7 +218,7 @@ class _QuizzResponseListState extends State<QuizzResponseList> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
showMultiStringInputAndResourceHTML("Réponse", "Modifier la réponse", true, initials, newValues, (value) {
|
showMultiStringInputAndResourceHTML(AppLocalizations.of(context)!.answerLabel, AppLocalizations.of(context)!.editAnswerTitle, true, initials, newValues, (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (value != null && response.label! != value) {
|
if (value != null && response.label! != value) {
|
||||||
response.label = value;
|
response.label = value;
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import 'package:manager_app/Models/managerContext.dart';
|
|||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/client.dart';
|
import 'package:manager_app/client.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
@ -62,13 +63,13 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
item.order = newIndex;
|
item.order = newIndex;
|
||||||
try {
|
try {
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionQuizApi!.sectionQuizUpdate(item);
|
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionQuizApi!.sectionQuizUpdate(item);
|
||||||
showNotification(kSuccess, kWhite, "L'ordre des questions a été mis à jour avec succès", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.questionOrderUpdatedSuccess, context, null);
|
||||||
setState(() {
|
setState(() {
|
||||||
// refresh ui
|
// refresh ui
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, "Une erreur est survenue lors de la mise à jour de l'ordre des questions", context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.questionOrderUpdateError, context, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,12 +87,12 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
Container(
|
Container(
|
||||||
height: 50,
|
height: 50,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Mauvais score",
|
text: AppLocalizations.of(context)!.quizBadScore,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
icon: Icons.message,
|
icon: Icons.message,
|
||||||
press: () async {
|
press: () async {
|
||||||
updateScoreQuizMessage(context, appContext, quizzDTO.badLevel, "Message pour un mauvais score", 0);
|
updateScoreQuizMessage(context, appContext, quizzDTO.badLevel, AppLocalizations.of(context)!.quizBadScoreMsg, 0);
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
horizontal: 10,
|
horizontal: 10,
|
||||||
@ -102,12 +103,12 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
Container(
|
Container(
|
||||||
height: 50,
|
height: 50,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Moyen score",
|
text: AppLocalizations.of(context)!.quizMediumScore,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
icon: Icons.message,
|
icon: Icons.message,
|
||||||
press: () async {
|
press: () async {
|
||||||
updateScoreQuizMessage(context, appContext, quizzDTO.mediumLevel, "Message pour un score moyen", 1);
|
updateScoreQuizMessage(context, appContext, quizzDTO.mediumLevel, AppLocalizations.of(context)!.quizMediumScoreMsg, 1);
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
horizontal: 10,
|
horizontal: 10,
|
||||||
@ -118,12 +119,12 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
Container(
|
Container(
|
||||||
height: 50,
|
height: 50,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Bon score",
|
text: AppLocalizations.of(context)!.quizGoodScore,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
icon: Icons.message,
|
icon: Icons.message,
|
||||||
press: () async {
|
press: () async {
|
||||||
updateScoreQuizMessage(context, appContext, quizzDTO.goodLevel, "Message pour un bon score", 2);
|
updateScoreQuizMessage(context, appContext, quizzDTO.goodLevel, AppLocalizations.of(context)!.quizGoodScoreMsg, 2);
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
horizontal: 10,
|
horizontal: 10,
|
||||||
@ -134,12 +135,12 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
Container(
|
Container(
|
||||||
height: 50,
|
height: 50,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Excellent score",
|
text: AppLocalizations.of(context)!.quizExcellentScore,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
icon: Icons.message,
|
icon: Icons.message,
|
||||||
press: () async {
|
press: () async {
|
||||||
updateScoreQuizMessage(context, appContext, quizzDTO.greatLevel, "Message pour un excellent score", 3);
|
updateScoreQuizMessage(context, appContext, quizzDTO.greatLevel, AppLocalizations.of(context)!.quizExcellentScoreMsg, 3);
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
horizontal: 10,
|
horizontal: 10,
|
||||||
@ -204,7 +205,7 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
top: 10,
|
top: 10,
|
||||||
left: 10,
|
left: 10,
|
||||||
child: Text(
|
child: Text(
|
||||||
"Questions",
|
AppLocalizations.of(context)!.questionsLabel,
|
||||||
style: TextStyle(fontSize: 15,
|
style: TextStyle(fontSize: 15,
|
||||||
fontWeight: FontWeight.w500),
|
fontWeight: FontWeight.w500),
|
||||||
),
|
),
|
||||||
@ -215,20 +216,20 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
QuestionDTO? result = await showNewOrUpdateQuestionQuizz(
|
QuestionDTO? result = await showNewOrUpdateQuestionQuizz(
|
||||||
null, appContext, context, "Question");
|
null, appContext, context, AppLocalizations.of(context)!.questionLabel);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(result != null)
|
if(result != null)
|
||||||
{
|
{
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionQuizApi!.sectionQuizCreate(quizzDTO.id!, result);
|
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionQuizApi!.sectionQuizCreate(quizzDTO.id!, result);
|
||||||
showNotification(kSuccess, kWhite, 'La question a été créée avec succès', context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.questionCreatedSuccess, context, null);
|
||||||
setState(() {
|
setState(() {
|
||||||
// refresh ui
|
// refresh ui
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors de la création de la question', context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.questionCreateError, context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
@ -267,7 +268,7 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Center(child: Text(
|
return Center(child: Text(
|
||||||
"Une erreur est survenue lors de la récupération des questions"));
|
AppLocalizations.of(context)!.questionsLoadError));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,28 +315,28 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: "Modifier",
|
message: AppLocalizations.of(context)!.edit,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
QuestionDTO? result = await showNewOrUpdateQuestionQuizz(
|
QuestionDTO? result = await showNewOrUpdateQuestionQuizz(
|
||||||
question,
|
question,
|
||||||
appContext,
|
appContext,
|
||||||
context,
|
context,
|
||||||
"Modifier la question"
|
AppLocalizations.of(context)!.editQuestion
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(result != null)
|
if(result != null)
|
||||||
{
|
{
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionQuizApi!.sectionQuizUpdate(result);
|
await (appContext.getContext() as ManagerAppContext).clientAPI!.sectionQuizApi!.sectionQuizUpdate(result);
|
||||||
showNotification(kSuccess, kWhite, 'La question a été mis à jour avec succès', context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.questionUpdatedSuccess, context, null);
|
||||||
setState(() {
|
setState(() {
|
||||||
// refresh ui
|
// refresh ui
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors de la mise à jour de la question', context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.questionUpdateError, context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*setState(() {
|
/*setState(() {
|
||||||
@ -354,24 +355,24 @@ class _QuizzConfigState extends State<QuizzConfig> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: "Supprimer",
|
message: AppLocalizations.of(context)!.delete,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir supprimer cette question ?",
|
AppLocalizations.of(context)!.questionDeleteConfirm,
|
||||||
() {},
|
() {},
|
||||||
() async {
|
() async {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var questionToRemove = questions[index];
|
var questionToRemove = questions[index];
|
||||||
(appContext.getContext() as ManagerAppContext).clientAPI!.sectionQuizApi!.sectionQuizDeleteWithHttpInfo(questionToRemove.id!);
|
(appContext.getContext() as ManagerAppContext).clientAPI!.sectionQuizApi!.sectionQuizDeleteWithHttpInfo(questionToRemove.id!);
|
||||||
showNotification(kSuccess, kWhite, 'La question a été supprimée avec succès', context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.questionDeletedSuccess, context, null);
|
||||||
// refresh UI
|
// refresh UI
|
||||||
setState(() {
|
setState(() {
|
||||||
print("Refresh UI");
|
print("Refresh UI");
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
showNotification(kError, kWhite, 'Une erreur est survenue lors de la suppression de la question', context, null);
|
showNotification(kError, kWhite, AppLocalizations.of(context)!.questionDeleteError, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:manager_app/Components/rounded_button.dart';
|
|||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
Future<ContentDTO?> showNewOrUpdateContentSlider(ContentDTO? inputContentDTO, AppContext appContext, BuildContext context, bool showTitle, bool showDescription) async {
|
Future<ContentDTO?> showNewOrUpdateContentSlider(ContentDTO? inputContentDTO, AppContext appContext, BuildContext context, bool showTitle, bool showDescription) async {
|
||||||
@ -75,7 +76,7 @@ Future<ContentDTO?> showNewOrUpdateContentSlider(ContentDTO? inputContentDTO, Ap
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
MultiStringInputContainer(
|
MultiStringInputContainer(
|
||||||
label: "Titre affiché:",
|
label: AppLocalizations.of(context)!.displayTitleLabel,
|
||||||
modalLabel: "Titre",
|
modalLabel: "Titre",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
@ -90,7 +91,7 @@ Future<ContentDTO?> showNewOrUpdateContentSlider(ContentDTO? inputContentDTO, Ap
|
|||||||
isTitle: true
|
isTitle: true
|
||||||
),
|
),
|
||||||
MultiStringInputContainer(
|
MultiStringInputContainer(
|
||||||
label: "Description affichée:",
|
label: AppLocalizations.of(context)!.displayedDescriptionLabel,
|
||||||
modalLabel: "Description",
|
modalLabel: "Description",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
isHTML: true,
|
isHTML: true,
|
||||||
@ -140,7 +141,7 @@ Future<ContentDTO?> showNewOrUpdateContentSlider(ContentDTO? inputContentDTO, Ap
|
|||||||
width: inputContentDTO != null ? 220: 150,
|
width: inputContentDTO != null ? 220: 150,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: inputContentDTO != null ? "Sauvegarder" : "Créer",
|
text: inputContentDTO != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import 'package:manager_app/Components/fetch_section_icon.dart';
|
|||||||
import 'package:manager_app/Components/resource_input_container.dart';
|
import 'package:manager_app/Components/resource_input_container.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
import 'package:manager_app/Components/number_input_container.dart';
|
import 'package:manager_app/Components/number_input_container.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
@ -120,10 +121,10 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Une erreur est survenue lors de la récupération de la section"));
|
AppLocalizations.of(context)!.sectionLoadError));
|
||||||
}
|
}
|
||||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
return Text("No data");
|
return Text(AppLocalizations.of(context)!.noData);
|
||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -235,7 +236,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Ce QR code a été copié dans le presse papier',
|
AppLocalizations.of(context)!.qrCodeCopied,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
},
|
},
|
||||||
@ -263,7 +264,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
CheckInputContainer(
|
CheckInputContainer(
|
||||||
label: "Beacon :",
|
label: AppLocalizations.of(context)!.beaconLabel,
|
||||||
isChecked: sectionDTO.isBeacon!,
|
isChecked: sectionDTO.isBeacon!,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -274,7 +275,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
),
|
),
|
||||||
if (sectionDTO.isBeacon!)
|
if (sectionDTO.isBeacon!)
|
||||||
NumberInputContainer(
|
NumberInputContainer(
|
||||||
label: "Identifiant Beacon :",
|
label: AppLocalizations.of(context)!.beaconIdLabel,
|
||||||
initialValue: sectionDTO.beaconId != null
|
initialValue: sectionDTO.beaconId != null
|
||||||
? sectionDTO.beaconId!
|
? sectionDTO.beaconId!
|
||||||
: 0,
|
: 0,
|
||||||
@ -287,7 +288,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
Colors.orange,
|
Colors.orange,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Cela doit être un chiffre',
|
AppLocalizations.of(context)!.beaconMustBeNumber,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -302,7 +303,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 100,
|
height: 100,
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Identifiant :",
|
label: AppLocalizations.of(context)!.identifierLabel,
|
||||||
initialValue: sectionDTO.label,
|
initialValue: sectionDTO.label,
|
||||||
onChanged: (String value) {
|
onChanged: (String value) {
|
||||||
sectionDTO.label = value;
|
sectionDTO.label = value;
|
||||||
@ -312,8 +313,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 100,
|
height: 100,
|
||||||
child: MultiStringInputContainer(
|
child: MultiStringInputContainer(
|
||||||
label: "Titre affiché:",
|
label: AppLocalizations.of(context)!.displayTitleLabel,
|
||||||
modalLabel: "Titre",
|
modalLabel: AppLocalizations.of(context)!.messageTitle,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
initialValue: sectionDTO.title!,
|
initialValue: sectionDTO.title!,
|
||||||
onGetResult: (value) {
|
onGetResult: (value) {
|
||||||
@ -351,7 +352,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Image :",
|
label: AppLocalizations.of(context)!.imageLabel,
|
||||||
initialValue: sectionDTO.imageId,
|
initialValue: sectionDTO.imageId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
onChanged: (ResourceDTO resource) {
|
onChanged: (ResourceDTO resource) {
|
||||||
@ -400,7 +401,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Annuler",
|
text: AppLocalizations.of(context)!.cancel,
|
||||||
icon: Icons.undo,
|
icon: Icons.undo,
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
@ -413,7 +414,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
if (canEdit) Padding(
|
if (canEdit) Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Supprimer",
|
text: AppLocalizations.of(context)!.delete,
|
||||||
icon: Icons.delete,
|
icon: Icons.delete,
|
||||||
color: kError,
|
color: kError,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
@ -426,7 +427,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
if (canEdit) Padding(
|
if (canEdit) Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Sauvegarder",
|
text: AppLocalizations.of(context)!.save,
|
||||||
icon: Icons.done,
|
icon: Icons.done,
|
||||||
color: kSuccess,
|
color: kSuccess,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
@ -456,7 +457,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
|
|
||||||
Future<void> delete(AppContext appContext) async {
|
Future<void> delete(AppContext appContext) async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir supprimer cette section ?", () {}, () async {
|
AppLocalizations.of(context)!.sectionDeleteConfirm, () {}, () async {
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
await managerAppContext.clientAPI!.sectionApi!
|
await managerAppContext.clientAPI!.sectionApi!
|
||||||
.sectionDelete(sectionDTO.id!);
|
.sectionDelete(sectionDTO.id!);
|
||||||
@ -482,12 +483,12 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
showNotification(
|
showNotification(
|
||||||
kSuccess,
|
kSuccess,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Les traductions de la section ont été sauvegardées avec succès',
|
AppLocalizations.of(context)!.sectionTranslationSaved,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
} else {
|
} else {
|
||||||
showNotification(kSuccess, kWhite,
|
showNotification(kSuccess, kWhite,
|
||||||
'La section a été sauvegardée avec succès', context, null);
|
AppLocalizations.of(context)!.sectionSavedSuccess, context, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,7 +510,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
);
|
);
|
||||||
case SectionType.Video:
|
case SectionType.Video:
|
||||||
return VideoConfig(
|
return VideoConfig(
|
||||||
label: "Url de la vidéo:",
|
label: AppLocalizations.of(context)!.videoUrlLabel,
|
||||||
initialValue: sectionDetailDTO as VideoDTO,
|
initialValue: sectionDetailDTO as VideoDTO,
|
||||||
onChanged: (VideoDTO updatedWebDTO) {
|
onChanged: (VideoDTO updatedWebDTO) {
|
||||||
sectionDetailDTO = updatedWebDTO;
|
sectionDetailDTO = updatedWebDTO;
|
||||||
@ -517,7 +518,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
|||||||
);
|
);
|
||||||
case SectionType.Web:
|
case SectionType.Web:
|
||||||
return WebConfig(
|
return WebConfig(
|
||||||
label: "Url du site web:",
|
label: AppLocalizations.of(context)!.webUrlLabel,
|
||||||
initialValue: sectionDetailDTO as WebDTO,
|
initialValue: sectionDetailDTO as WebDTO,
|
||||||
onChanged: (WebDTO updatedWebDTO) {
|
onChanged: (WebDTO updatedWebDTO) {
|
||||||
sectionDetailDTO = updatedWebDTO;
|
sectionDetailDTO = updatedWebDTO;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import 'package:manager_app/Components/number_input_container.dart';
|
|||||||
import 'package:manager_app/Components/resource_input_container.dart';
|
import 'package:manager_app/Components/resource_input_container.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/multi_select_dropdown_language_container.dart';
|
import 'package:manager_app/Components/multi_select_dropdown_language_container.dart';
|
||||||
import 'package:manager_app/Components/multi_string_input_container.dart';
|
import 'package:manager_app/Components/multi_string_input_container.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
@ -50,7 +51,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
return bodyConfiguration(snapshot.data, size, appContext, context);
|
return bodyConfiguration(snapshot.data, size, appContext, context);
|
||||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
return Text("No data");
|
return Text(AppLocalizations.of(context)!.noData);
|
||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -100,11 +101,11 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
anchorElement.click();
|
anchorElement.click();
|
||||||
} else {
|
} else {
|
||||||
File test = await FileHelper().storeConfiguration(export);
|
File test = await FileHelper().storeConfiguration(export);
|
||||||
showNotification(kSuccess, kWhite, "L'export de la configuration a réussi, le document se trouve à cet endroit : " + test.path, context, 3000);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configExportSuccess(test.path), context, 3000);
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
log(e.toString());
|
log(e.toString());
|
||||||
showNotification(kPrimaryColor, kWhite, "L'export de la configuration a échoué", context, null);
|
showNotification(kPrimaryColor, kWhite, AppLocalizations.of(context)!.configExportFailed, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -167,7 +168,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 70,
|
height: 70,
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Identifiant :",
|
label: AppLocalizations.of(context)!.identifierLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontSizeText: 20,
|
fontSizeText: 20,
|
||||||
initialValue: configurationDTO.label,
|
initialValue: configurationDTO.label,
|
||||||
@ -182,7 +183,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
MultiSelectDropdownLanguageContainer(
|
MultiSelectDropdownLanguageContainer(
|
||||||
label: "Langues :",
|
label: AppLocalizations.of(context)!.languagesLabel,
|
||||||
initialValue: configurationDTO.languages != null ? configurationDTO.languages! : [],
|
initialValue: configurationDTO.languages != null ? configurationDTO.languages! : [],
|
||||||
values: languages,
|
values: languages,
|
||||||
isMultiple: true,
|
isMultiple: true,
|
||||||
@ -195,7 +196,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
),
|
),
|
||||||
CheckInputContainer(
|
CheckInputContainer(
|
||||||
icon: Icons.signal_wifi_off,
|
icon: Icons.signal_wifi_off,
|
||||||
label: "Hors ligne :",
|
label: "Hors ligne :", // no ARB key for this one yet, leave as-is
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
isChecked: configurationDTO.isOffline,
|
isChecked: configurationDTO.isOffline,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -211,7 +212,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Image fond d'écran :",
|
label: AppLocalizations.of(context)!.mainImageLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
initialValue: configurationDTO.imageId,
|
initialValue: configurationDTO.imageId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
@ -226,7 +227,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ResourceInputContainer(
|
ResourceInputContainer(
|
||||||
label: "Image loader :",
|
label: AppLocalizations.of(context)!.loaderLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
initialValue: configurationDTO.loaderImageId,
|
initialValue: configurationDTO.loaderImageId,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
@ -355,7 +356,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Annuler",
|
text: AppLocalizations.of(context)!.cancel,
|
||||||
icon: Icons.undo,
|
icon: Icons.undo,
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
@ -368,7 +369,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
if (canEdit) Padding(
|
if (canEdit) Padding(
|
||||||
padding: const EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Supprimer",
|
text: AppLocalizations.of(context)!.delete,
|
||||||
icon: Icons.delete,
|
icon: Icons.delete,
|
||||||
color: kError,
|
color: kError,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
@ -381,7 +382,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
if (canEdit) Padding(
|
if (canEdit) Padding(
|
||||||
padding: const EdgeInsets.all(5.0),
|
padding: const EdgeInsets.all(5.0),
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Sauvegarder",
|
text: AppLocalizations.of(context)!.save,
|
||||||
icon: Icons.done,
|
icon: Icons.done,
|
||||||
color: kSuccess,
|
color: kSuccess,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
@ -432,14 +433,14 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
|
|
||||||
Future<void> delete(ConfigurationDTO configurationDTO, AppContext appContext) async {
|
Future<void> delete(ConfigurationDTO configurationDTO, AppContext appContext) async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir supprimer cette visite ?",
|
AppLocalizations.of(context)!.configDeleteConfirm,
|
||||||
() {},
|
() {},
|
||||||
() async {
|
() async {
|
||||||
ManagerAppContext managerAppContext = appContext.getContext();
|
ManagerAppContext managerAppContext = appContext.getContext();
|
||||||
await managerAppContext.clientAPI!.configurationApi!.configurationDelete(configurationDTO.id!);
|
await managerAppContext.clientAPI!.configurationApi!.configurationDelete(configurationDTO.id!);
|
||||||
managerAppContext.selectedConfiguration = null;
|
managerAppContext.selectedConfiguration = null;
|
||||||
appContext.setContext(managerAppContext);
|
appContext.setContext(managerAppContext);
|
||||||
showNotification(kSuccess, kWhite, 'La configuration a été supprimée avec succès', context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configDeletedSuccess, context, null);
|
||||||
},
|
},
|
||||||
context
|
context
|
||||||
);
|
);
|
||||||
@ -451,7 +452,7 @@ class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
|||||||
managerAppContext.selectedConfiguration = configuration;
|
managerAppContext.selectedConfiguration = configuration;
|
||||||
appContext.setContext(managerAppContext);
|
appContext.setContext(managerAppContext);
|
||||||
|
|
||||||
showNotification(kSuccess, kWhite, 'La configuration a été sauvegardée avec succès', context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configSavedSuccess, context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ConfigurationDTO?> getConfiguration(ConfigurationDetailScreen widget, Client client) async {
|
Future<ConfigurationDTO?> getConfiguration(ConfigurationDetailScreen widget, Client client) async {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Screens/Configurations/configuration_detail_screen.dart';
|
import 'package:manager_app/Screens/Configurations/configuration_detail_screen.dart';
|
||||||
@ -46,7 +47,7 @@ class _ConfigurationsScreenState extends State<ConfigurationsScreen> {
|
|||||||
if (managerAppContext.canEdit) tempOutput.add(ConfigurationDTO(id: null));
|
if (managerAppContext.canEdit) tempOutput.add(ConfigurationDTO(id: null));
|
||||||
return bodyGrid(tempOutput, size, appContext, context);
|
return bodyGrid(tempOutput, size, appContext, context);
|
||||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
return Text("No data");
|
return Text(AppLocalizations.of(context)!.noData);
|
||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -96,7 +97,7 @@ class _ConfigurationsScreenState extends State<ConfigurationsScreen> {
|
|||||||
managerAppContext.selectedConfiguration = null;
|
managerAppContext.selectedConfiguration = null;
|
||||||
await appContext.setContext(managerAppContext);
|
await appContext.setContext(managerAppContext);
|
||||||
|
|
||||||
showNotification(kSuccess, kWhite, 'La configuration a été créée avec succès', context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configCreatedSuccess, context, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
//import 'package:filepicker_windows/filepicker_windows.dart';
|
//import 'package:filepicker_windows/filepicker_windows.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/string_input_container.dart';
|
import 'package:manager_app/Components/string_input_container.dart';
|
||||||
@ -11,6 +12,7 @@ import 'package:manager_app/constants.dart';
|
|||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChanged<bool> isImport, BuildContext context, BuildContext mainContext) {
|
Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChanged<bool> isImport, BuildContext context, BuildContext mainContext) {
|
||||||
|
final l = AppLocalizations.of(mainContext)!;
|
||||||
ConfigurationDTO configurationDTO = new ConfigurationDTO();
|
ConfigurationDTO configurationDTO = new ConfigurationDTO();
|
||||||
Size size = MediaQuery.of(mainContext).size;
|
Size size = MediaQuery.of(mainContext).size;
|
||||||
configurationDTO.label = "";
|
configurationDTO.label = "";
|
||||||
@ -28,12 +30,12 @@ Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChang
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Center(child: Text("Nouvelle configuration", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400))),
|
Center(child: Text(l.newConfiguration, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400))),
|
||||||
Center(
|
Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 100,
|
height: 100,
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Nom :",
|
label: l.configNameLabel,
|
||||||
initialValue: configurationDTO.label,
|
initialValue: configurationDTO.label,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
configurationDTO.label = value;
|
configurationDTO.label = value;
|
||||||
@ -41,12 +43,12 @@ Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChang
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("ou"),
|
Text(l.orText),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 5.0),
|
padding: const EdgeInsets.only(bottom: 5.0),
|
||||||
child: Text("Importer", style: TextStyle(fontSize: 25, fontWeight: FontWeight.w300)),
|
child: Text(l.importLabel, style: TextStyle(fontSize: 25, fontWeight: FontWeight.w300)),
|
||||||
),
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@ -85,7 +87,7 @@ Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChang
|
|||||||
width: 175,
|
width: 175,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Annuler",
|
text: l.cancel,
|
||||||
icon: Icons.undo,
|
icon: Icons.undo,
|
||||||
color: kSecond,
|
color: kSecond,
|
||||||
press: () {
|
press: () {
|
||||||
@ -101,7 +103,7 @@ Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChang
|
|||||||
width: 150,
|
width: 150,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Créer",
|
text: l.create,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
@ -110,7 +112,7 @@ Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChang
|
|||||||
//create(configurationDTO, appContext, context);
|
//create(configurationDTO, appContext, context);
|
||||||
Navigator.of(context).pop(configurationDTO);
|
Navigator.of(context).pop(configurationDTO);
|
||||||
} else {
|
} else {
|
||||||
showNotification(Colors.orange, kWhite, 'Veuillez spécifier un nom pour la nouvelle visite', context, null);
|
showNotification(Colors.orange, kWhite, l.configNameRequired, context, null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_app/Components/dropDown_input_container.dart';
|
import 'package:manager_app/Components/dropDown_input_container.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/string_input_container.dart';
|
import 'package:manager_app/Components/string_input_container.dart';
|
||||||
@ -10,6 +11,7 @@ import 'package:manager_api_new/api.dart';
|
|||||||
|
|
||||||
Future<SectionDTO?> showNewSection(String configurationId,
|
Future<SectionDTO?> showNewSection(String configurationId,
|
||||||
AppContext appContext, BuildContext contextBuild, bool isSubSection) {
|
AppContext appContext, BuildContext contextBuild, bool isSubSection) {
|
||||||
|
final l = AppLocalizations.of(contextBuild)!;
|
||||||
SectionDTO sectionDTO = new SectionDTO();
|
SectionDTO sectionDTO = new SectionDTO();
|
||||||
sectionDTO.label = "";
|
sectionDTO.label = "";
|
||||||
sectionDTO.configurationId = configurationId;
|
sectionDTO.configurationId = configurationId;
|
||||||
@ -18,7 +20,6 @@ Future<SectionDTO?> showNewSection(String configurationId,
|
|||||||
sectionDTO.parentId = isSubSection
|
sectionDTO.parentId = isSubSection
|
||||||
? (appContext.getContext() as ManagerAppContext).selectedSection!.id
|
? (appContext.getContext() as ManagerAppContext).selectedSection!.id
|
||||||
: null;
|
: null;
|
||||||
Size size = MediaQuery.of(contextBuild).size;
|
|
||||||
sectionDTO.type = SectionType.Map;
|
sectionDTO.type = SectionType.Map;
|
||||||
|
|
||||||
var section = showDialog<SectionDTO?>(
|
var section = showDialog<SectionDTO?>(
|
||||||
@ -35,8 +36,8 @@ Future<SectionDTO?> showNewSection(String configurationId,
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
isSubSection
|
isSubSection
|
||||||
? "Nouvelle sous section"
|
? l.newSubSection
|
||||||
: "Nouvelle section",
|
: l.newSection,
|
||||||
style: new TextStyle(
|
style: new TextStyle(
|
||||||
fontSize: 25, fontWeight: FontWeight.w400)),
|
fontSize: 25, fontWeight: FontWeight.w400)),
|
||||||
Column(
|
Column(
|
||||||
@ -44,7 +45,7 @@ Future<SectionDTO?> showNewSection(String configurationId,
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 100,
|
height: 100,
|
||||||
child: StringInputContainer(
|
child: StringInputContainer(
|
||||||
label: "Nom :",
|
label: l.sectionNameLabel,
|
||||||
initialValue: sectionDTO.label,
|
initialValue: sectionDTO.label,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
sectionDTO.label = value;
|
sectionDTO.label = value;
|
||||||
@ -52,7 +53,7 @@ Future<SectionDTO?> showNewSection(String configurationId,
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
DropDownInputContainer(
|
DropDownInputContainer(
|
||||||
label: "Type:",
|
label: l.sectionTypeLabel,
|
||||||
values: isSubSection
|
values: isSubSection
|
||||||
? section_types
|
? section_types
|
||||||
.where(
|
.where(
|
||||||
@ -92,7 +93,7 @@ Future<SectionDTO?> showNewSection(String configurationId,
|
|||||||
width: 175,
|
width: 175,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Annuler",
|
text: l.cancel,
|
||||||
icon: Icons.undo,
|
icon: Icons.undo,
|
||||||
color: kSecond,
|
color: kSecond,
|
||||||
press: () {
|
press: () {
|
||||||
@ -108,7 +109,7 @@ Future<SectionDTO?> showNewSection(String configurationId,
|
|||||||
width: 150,
|
width: 150,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Créer",
|
text: l.create,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
@ -122,7 +123,7 @@ Future<SectionDTO?> showNewSection(String configurationId,
|
|||||||
showNotification(
|
showNotification(
|
||||||
Colors.orange,
|
Colors.orange,
|
||||||
kWhite,
|
kWhite,
|
||||||
'Veuillez spécifier un nom pour la nouvelle section',
|
l.sectionNameRequired,
|
||||||
context,
|
context,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -156,7 +157,7 @@ void create(SectionDTO sectionDTO, AppContext appContext, BuildContext context,
|
|||||||
}
|
}
|
||||||
managerAppContext.selectedConfiguration.sectionIds.add(newSection.id);*/
|
managerAppContext.selectedConfiguration.sectionIds.add(newSection.id);*/
|
||||||
appContext.setContext(managerAppContext);
|
appContext.setContext(managerAppContext);
|
||||||
showNotification(kSuccess, kWhite, 'La section a été créée avec succès !',
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.sectionCreatedSuccess,
|
||||||
context, null);
|
context, null);
|
||||||
} else {
|
} else {
|
||||||
sendSubSection!(newSection);
|
sendSubSection!(newSection);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import 'package:manager_app/Components/string_input_container.dart';
|
|||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
import '../../Components/resource_input_container.dart';
|
import '../../Components/resource_input_container.dart';
|
||||||
@ -73,7 +74,7 @@ showChangeInfo (String text, DeviceDTO inputDevice, AppConfigurationLinkDTO appC
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Text("Aucune configuration trouvée");
|
return Text(AppLocalizations.of(context)!.noConfigFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
@ -104,7 +105,7 @@ showChangeInfo (String text, DeviceDTO inputDevice, AppConfigurationLinkDTO appC
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ColorPickerInputContainer(
|
ColorPickerInputContainer(
|
||||||
label: "Couleur fond d'écran :",
|
label: AppLocalizations.of(context)!.backgroundColorLabel,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: appConfiguration.secondaryColor,
|
color: appConfiguration.secondaryColor,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:manager_app/Models/managerContext.dart';
|
|||||||
import 'package:manager_app/Screens/Kiosk_devices/change_device_info_modal.dart';
|
import 'package:manager_app/Screens/Kiosk_devices/change_device_info_modal.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ class _DeviceElementState extends State<DeviceElement> {
|
|||||||
icon: Icon(Icons.edit),
|
icon: Icon(Icons.edit),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showChangeInfo(
|
showChangeInfo(
|
||||||
"Mettre à jour la tablette",
|
AppLocalizations.of(context)!.updateTabletBtn,
|
||||||
widget.deviceDTO,
|
widget.deviceDTO,
|
||||||
widget.appConfigurationLinkDTO,
|
widget.appConfigurationLinkDTO,
|
||||||
(DeviceDTO outputDevice, AppConfigurationLinkDTO outputAppConfig) async {
|
(DeviceDTO outputDevice, AppConfigurationLinkDTO outputAppConfig) async {
|
||||||
@ -120,7 +121,7 @@ class _DeviceElementState extends State<DeviceElement> {
|
|||||||
AppConfigurationLinkDTO? result = await managerAppContext.clientAPI!.applicationInstanceApi!.applicationInstanceUpdateApplicationLink(appConfigurationToUpdate);
|
AppConfigurationLinkDTO? result = await managerAppContext.clientAPI!.applicationInstanceApi!.applicationInstanceUpdateApplicationLink(appConfigurationToUpdate);
|
||||||
|
|
||||||
//print(device);
|
//print(device);
|
||||||
showNotification(kSuccess, kWhite, "Le kiosk a été mis à jour", context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.kioskUpdatedSuccess, context, null);
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Screens/Applications/app_configuration_link_screen.dart';
|
import 'package:manager_app/Screens/Applications/app_configuration_link_screen.dart';
|
||||||
@ -35,7 +36,7 @@ class _KioskScreenState extends State<KioskScreen> {
|
|||||||
child: Align(
|
child: Align(
|
||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
child: AutoSizeText(
|
child: AutoSizeText(
|
||||||
"Code pin: " + managerAppContext.pinCode.toString(),
|
AppLocalizations.of(context)!.pinCode(managerAppContext.pinCode.toString()),
|
||||||
style: TextStyle(fontSize: 25.0, fontWeight: FontWeight.w300),
|
style: TextStyle(fontSize: 25.0, fontWeight: FontWeight.w300),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
maxFontSize: 25.0,
|
maxFontSize: 25.0,
|
||||||
@ -49,7 +50,7 @@ class _KioskScreenState extends State<KioskScreen> {
|
|||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text("Tablettes"),
|
child: Text(AppLocalizations.of(context)!.tablets),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
@ -179,7 +180,7 @@ class _KioskScreenState extends State<KioskScreen> {
|
|||||||
icon: Icon(Icons.edit),
|
icon: Icon(Icons.edit),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showSelectConfigModal(
|
showSelectConfigModal(
|
||||||
"Sélectionner une configuration",
|
AppLocalizations.of(context)!.selectConfiguration,
|
||||||
(String configurationId) {
|
(String configurationId) {
|
||||||
|
|
||||||
device.configurationId = configurationId;
|
device.configurationId = configurationId;
|
||||||
@ -201,7 +202,7 @@ class _KioskScreenState extends State<KioskScreen> {
|
|||||||
) : InkWell(
|
) : InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showSelectConfigModal(
|
showSelectConfigModal(
|
||||||
"Sélectionner une configuration",
|
AppLocalizations.of(context)!.selectConfiguration,
|
||||||
(String configurationId) {
|
(String configurationId) {
|
||||||
|
|
||||||
device.configurationId = configurationId;
|
device.configurationId = configurationId;
|
||||||
@ -226,7 +227,7 @@ class _KioskScreenState extends State<KioskScreen> {
|
|||||||
padding: const EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 15),
|
padding: const EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 15),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: AutoSizeText(
|
child: AutoSizeText(
|
||||||
"Sélectionner",
|
AppLocalizations.of(context)!.choose,
|
||||||
style: TextStyle(color: kWhite),
|
style: TextStyle(color: kWhite),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -16,7 +16,9 @@ import 'package:manager_app/Screens/Statistics/statistics_screen.dart';
|
|||||||
import 'package:manager_app/Screens/Applications/app_configuration_link_screen.dart';
|
import 'package:manager_app/Screens/Applications/app_configuration_link_screen.dart';
|
||||||
import 'package:manager_app/Screens/Notifications/notifications_screen.dart';
|
import 'package:manager_app/Screens/Notifications/notifications_screen.dart';
|
||||||
import 'package:manager_app/Screens/Users/users_screen.dart';
|
import 'package:manager_app/Screens/Users/users_screen.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
|
import 'package:manager_app/Components/quota_bars_widget.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_app/main.dart';
|
import 'package:manager_app/main.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
@ -81,6 +83,100 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
selectedElement = initElementToShow(context, widget.view, currentPosition.value!, menu, widget.instance);
|
selectedElement = initElementToShow(context, widget.view, currentPosition.value!, menu, widget.instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _showAssignPlanDialog(BuildContext context, ManagerAppContext managerCtx, Instance inst, {void Function()? onSaved}) async {
|
||||||
|
List<SubscriptionPlanDTO>? plans;
|
||||||
|
InstanceDTO? instanceDetail;
|
||||||
|
try {
|
||||||
|
plans = await managerCtx.clientAPI!.subscriptionPlanApi!.subscriptionPlanGet();
|
||||||
|
instanceDetail = await managerCtx.clientAPI!.instanceApi!.instanceGetDetail(inst.id);
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
if (!context.mounted) return;
|
||||||
|
|
||||||
|
final planList = plans ?? [];
|
||||||
|
String? selectedPlanId = instanceDetail?.subscriptionPlanId;
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (dialogContext) => StatefulBuilder(
|
||||||
|
builder: (dialogContext, setDialogState) => AlertDialog(
|
||||||
|
title: Text('Plan — ${inst.name}'),
|
||||||
|
content: SizedBox(
|
||||||
|
width: 360,
|
||||||
|
child: planList.isEmpty
|
||||||
|
? Text(AppLocalizations.of(context)!.noPlansAvailable)
|
||||||
|
: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
RadioListTile<String?>(
|
||||||
|
title: Text(AppLocalizations.of(context)!.noPlan),
|
||||||
|
value: null,
|
||||||
|
groupValue: selectedPlanId,
|
||||||
|
onChanged: (v) => setDialogState(() => selectedPlanId = v),
|
||||||
|
),
|
||||||
|
...planList.map((plan) => RadioListTile<String?>(
|
||||||
|
title: Text(plan.name),
|
||||||
|
subtitle: Text(
|
||||||
|
'${_formatQuotaBytes(plan.storageQuotaBytes, unlimitedLabel: AppLocalizations.of(dialogContext)!.unlimitedStorage)} · ${plan.aiRequestsPerMonth == 0 ? AppLocalizations.of(dialogContext)!.unlimitedAI : AppLocalizations.of(dialogContext)!.aiRequestsPerMonth(plan.aiRequestsPerMonth ?? 0)}',
|
||||||
|
style: const TextStyle(fontSize: 11),
|
||||||
|
),
|
||||||
|
value: plan.id,
|
||||||
|
groupValue: selectedPlanId,
|
||||||
|
onChanged: (v) => setDialogState(() => selectedPlanId = v),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(dialogContext, rootNavigator: true).pop(),
|
||||||
|
child: Text(AppLocalizations.of(dialogContext)!.cancel),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.of(dialogContext, rootNavigator: true).pop();
|
||||||
|
try {
|
||||||
|
await managerCtx.clientAPI!.instanceApi!.instanceUpdateinstance(
|
||||||
|
InstanceDTO(
|
||||||
|
id: instanceDetail?.id,
|
||||||
|
name: instanceDetail?.name,
|
||||||
|
pinCode: instanceDetail?.pinCode,
|
||||||
|
isPushNotification: instanceDetail?.isPushNotification,
|
||||||
|
isStatistic: instanceDetail?.isStatistic,
|
||||||
|
isMobile: instanceDetail?.isMobile,
|
||||||
|
isTablet: instanceDetail?.isTablet,
|
||||||
|
isWeb: instanceDetail?.isWeb,
|
||||||
|
isVR: instanceDetail?.isVR,
|
||||||
|
isAssistant: instanceDetail?.isAssistant,
|
||||||
|
aiRequestsThisMonth: instanceDetail?.aiRequestsThisMonth,
|
||||||
|
aiUsageMonthKey: instanceDetail?.aiUsageMonthKey,
|
||||||
|
subscriptionPlanId: selectedPlanId ?? '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
onSaved?.call();
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context)!.planUpdated)));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context)!.errorMessage(e.toString()))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text(AppLocalizations.of(dialogContext)!.save),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String _formatQuotaBytes(int? bytes, {String? unlimitedLabel}) {
|
||||||
|
if (bytes == null || bytes == 0) return unlimitedLabel ?? 'Stockage illimité';
|
||||||
|
if (bytes < 1024 * 1024 * 1024) return '${(bytes / (1024 * 1024)).toStringAsFixed(0)} MB';
|
||||||
|
return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(1)} GB';
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _showSwitchInstanceDialog(BuildContext context, ManagerAppContext managerCtx) async {
|
Future<void> _showSwitchInstanceDialog(BuildContext context, ManagerAppContext managerCtx) async {
|
||||||
List<Instance>? instances;
|
List<Instance>? instances;
|
||||||
try {
|
try {
|
||||||
@ -94,11 +190,11 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => AlertDialog(
|
builder: (_) => AlertDialog(
|
||||||
title: const Text('Changer d\'instance'),
|
title: Text(AppLocalizations.of(context)!.switchInstance),
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
width: 400,
|
width: 400,
|
||||||
child: instanceList.isEmpty
|
child: instanceList.isEmpty
|
||||||
? const Text('Aucune instance trouvée')
|
? Text(AppLocalizations.of(context)!.noInstanceFound)
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: instanceList.length,
|
itemCount: instanceList.length,
|
||||||
@ -117,7 +213,19 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
fontWeight: isCurrent ? FontWeight.bold : FontWeight.normal,
|
fontWeight: isCurrent ? FontWeight.bold : FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trailing: isCurrent ? const Icon(Icons.check, color: Colors.green) : null,
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (isCurrent) const Icon(Icons.check, color: Colors.green),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.edit_outlined, size: 18),
|
||||||
|
tooltip: AppLocalizations.of(context)!.configurePlan,
|
||||||
|
onPressed: () => _showAssignPlanDialog(context, managerCtx, inst, onSaved: () {
|
||||||
|
Navigator.of(context, rootNavigator: true).pop();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
onTap: isCurrent
|
onTap: isCurrent
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
@ -141,12 +249,26 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: () => Navigator.of(context, rootNavigator: true).pop(), child: const Text('Fermer')),
|
TextButton(onPressed: () => Navigator.of(context, rootNavigator: true).pop(), child: Text(AppLocalizations.of(context)!.close)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String _localizedSectionName(BuildContext context, String type) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
|
switch (type) {
|
||||||
|
case 'devices': return l.menuApplications;
|
||||||
|
case 'configurations': return l.menuConfigurations;
|
||||||
|
case 'resources': return l.menuResources;
|
||||||
|
case 'statistics': return l.menuStatistics;
|
||||||
|
case 'notifications': return l.menuNotifications;
|
||||||
|
case 'users': return l.menuUsers;
|
||||||
|
case 'apikeys': return l.menuApiKeys;
|
||||||
|
default: return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static IconData _sectionIcon(String type) {
|
static IconData _sectionIcon(String type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'devices': return Icons.apps;
|
case 'devices': return Icons.apps;
|
||||||
@ -228,7 +350,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
color: currentPath.contains(section.type) ? kPrimaryColor : kBodyTextColor,
|
color: currentPath.contains(section.type) ? kPrimaryColor : kBodyTextColor,
|
||||||
size: 22,
|
size: 22,
|
||||||
),
|
),
|
||||||
title: Text(section.name, style: TextStyle(color: currentPath.contains(section.type) ? kPrimaryColor : kBodyTextColor, fontSize: 22, fontWeight: currentPath.contains(section.type) ? FontWeight.w500 : FontWeight.w100)),
|
title: Text(_localizedSectionName(context, section.type), style: TextStyle(color: currentPath.contains(section.type) ? kPrimaryColor : kBodyTextColor, fontSize: 22, fontWeight: currentPath.contains(section.type) ? FontWeight.w500 : FontWeight.w100)),
|
||||||
selected: currentPosition == section.menuId,
|
selected: currentPosition == section.menuId,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) =>
|
WidgetsBinding.instance.addPostFrameCallback((_) =>
|
||||||
@ -252,7 +374,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
),
|
),
|
||||||
iconColor: isAppActive ? kPrimaryColor : kBodyTextColor,
|
iconColor: isAppActive ? kPrimaryColor : kBodyTextColor,
|
||||||
collapsedIconColor: isAppActive ? kPrimaryColor : kBodyTextColor,
|
collapsedIconColor: isAppActive ? kPrimaryColor : kBodyTextColor,
|
||||||
title: Text(section.name, style: TextStyle(color: isAppActive ? kPrimaryColor : kBodyTextColor, fontSize: 22, fontWeight: isAppActive ? FontWeight.w500 : FontWeight.w100)),
|
title: Text(_localizedSectionName(context, section.type), style: TextStyle(color: isAppActive ? kPrimaryColor : kBodyTextColor, fontSize: 22, fontWeight: isAppActive ? FontWeight.w500 : FontWeight.w100)),
|
||||||
children: section.subMenu.map((subSection) {
|
children: section.subMenu.map((subSection) {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: currentPath.contains(subSection.type)
|
decoration: currentPath.contains(subSection.type)
|
||||||
@ -276,7 +398,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
subSection.type == "vr" ? Icon(Icons.panorama_photosphere, color: currentPath.contains(subSection.type)? kPrimaryColor : kBodyTextColor, size: 20) : SizedBox(),
|
subSection.type == "vr" ? Icon(Icons.panorama_photosphere, color: currentPath.contains(subSection.type)? kPrimaryColor : kBodyTextColor, size: 20) : SizedBox(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(subSection.name, style: TextStyle(color: currentPath.contains(subSection.type) ? kPrimaryColor : kBodyTextColor, fontSize: 18)),
|
child: Text(_localizedSectionName(context, subSection.type), style: TextStyle(color: currentPath.contains(subSection.type) ? kPrimaryColor : kBodyTextColor, fontSize: 18)),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -302,11 +424,26 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Footer: Email + Switch instance (SuperAdmin) + Logout
|
// Footer: Quota + Language + Email + Switch instance (SuperAdmin) + Logout
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
const QuotaBarsWidget(),
|
||||||
|
DropdownButton<Locale>(
|
||||||
|
value: managerAppContext.locale,
|
||||||
|
underline: const SizedBox(),
|
||||||
|
isDense: true,
|
||||||
|
items: const [
|
||||||
|
DropdownMenuItem(value: Locale('fr'), child: Text('🇫🇷 FR')),
|
||||||
|
DropdownMenuItem(value: Locale('en'), child: Text('🇬🇧 EN')),
|
||||||
|
DropdownMenuItem(value: Locale('nl'), child: Text('🇧🇪 NL')),
|
||||||
|
],
|
||||||
|
onChanged: (locale) {
|
||||||
|
if (locale != null) appContext.setLocale(locale);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
AutoSizeText(
|
AutoSizeText(
|
||||||
(appContext.getContext() as ManagerAppContext).email ?? "",
|
(appContext.getContext() as ManagerAppContext).email ?? "",
|
||||||
style: TextStyle(color: kBodyTextColor, fontSize: 16, fontWeight: FontWeight.w300, fontFamily: "Helvetica"),
|
style: TextStyle(color: kBodyTextColor, fontSize: 16, fontWeight: FontWeight.w300, fontFamily: "Helvetica"),
|
||||||
@ -315,7 +452,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
if ((appContext.getContext() as ManagerAppContext).role == UserRole.SuperAdmin)
|
if ((appContext.getContext() as ManagerAppContext).role == UserRole.SuperAdmin)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.swap_horiz, color: kPrimaryColor),
|
icon: Icon(Icons.swap_horiz, color: kPrimaryColor),
|
||||||
tooltip: 'Changer d\'instance',
|
tooltip: AppLocalizations.of(context)!.tooltipSwitchInstance,
|
||||||
onPressed: () => _showSwitchInstanceDialog(context, appContext.getContext() as ManagerAppContext),
|
onPressed: () => _showSwitchInstanceDialog(context, appContext.getContext() as ManagerAppContext),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -17,17 +19,15 @@ class NotificationsScreen extends StatefulWidget {
|
|||||||
class _NotificationsScreenState extends State<NotificationsScreen> {
|
class _NotificationsScreenState extends State<NotificationsScreen> {
|
||||||
List<PushNotificationDTO> _notifications = [];
|
List<PushNotificationDTO> _notifications = [];
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
String? _statusFilter; // null = toutes
|
String? _statusFilter;
|
||||||
int _page = 0;
|
int _page = 0;
|
||||||
static const _pageSize = 15;
|
static const _pageSize = 15;
|
||||||
|
|
||||||
// ─── KPI counts ───────────────────────────────────────────
|
|
||||||
int get _totalCount => _notifications.length;
|
int get _totalCount => _notifications.length;
|
||||||
int get _sentCount => _notifications.where((n) => n.status == 'Sent').length;
|
int get _sentCount => _notifications.where((n) => n.status == 'Sent').length;
|
||||||
int get _scheduledCount => _notifications.where((n) => n.status == 'Scheduled').length;
|
int get _scheduledCount => _notifications.where((n) => n.status == 'Scheduled').length;
|
||||||
int get _failedCount => _notifications.where((n) => n.status == 'Failed').length;
|
int get _failedCount => _notifications.where((n) => n.status == 'Failed').length;
|
||||||
|
|
||||||
// ─── Filtre + pagination ───────────────────────────────────
|
|
||||||
List<PushNotificationDTO> get _filtered => _statusFilter == null
|
List<PushNotificationDTO> get _filtered => _statusFilter == null
|
||||||
? _notifications
|
? _notifications
|
||||||
: _notifications.where((n) => n.status == _statusFilter).toList();
|
: _notifications.where((n) => n.status == _statusFilter).toList();
|
||||||
@ -43,7 +43,6 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── API helpers ──────────────────────────────────────────
|
|
||||||
Future<void> _load(ManagerAppContext ctx) async {
|
Future<void> _load(ManagerAppContext ctx) async {
|
||||||
try {
|
try {
|
||||||
final response = await ctx.clientAPI!.notificationApi!.notificationGetWithHttpInfo();
|
final response = await ctx.clientAPI!.notificationApi!.notificationGetWithHttpInfo();
|
||||||
@ -78,8 +77,8 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
return response.statusCode == 202;
|
return response.statusCode == 202;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Dialogs ──────────────────────────────────────────────
|
|
||||||
void _showSendModal(BuildContext context, ManagerAppContext ctx) {
|
void _showSendModal(BuildContext context, ManagerAppContext ctx) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final titleCtrl = TextEditingController();
|
final titleCtrl = TextEditingController();
|
||||||
final bodyCtrl = TextEditingController();
|
final bodyCtrl = TextEditingController();
|
||||||
bool isScheduled = false;
|
bool isScheduled = false;
|
||||||
@ -90,18 +89,18 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) {
|
builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text('Nouveau message'),
|
title: Text(l.newMessage),
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
width: 480,
|
width: 480,
|
||||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
TextField(
|
TextField(
|
||||||
controller: titleCtrl,
|
controller: titleCtrl,
|
||||||
decoration: const InputDecoration(labelText: 'Titre'),
|
decoration: InputDecoration(labelText: l.messageTitle),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
TextField(
|
TextField(
|
||||||
controller: bodyCtrl,
|
controller: bodyCtrl,
|
||||||
decoration: const InputDecoration(labelText: 'Message'),
|
decoration: InputDecoration(labelText: l.messageBody),
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@ -111,7 +110,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
value: isScheduled,
|
value: isScheduled,
|
||||||
onChanged: (v) => setLocal(() => isScheduled = v ?? false),
|
onChanged: (v) => setLocal(() => isScheduled = v ?? false),
|
||||||
),
|
),
|
||||||
const Text('Planifier'),
|
Text(l.schedule),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isScheduled) ...[
|
if (isScheduled) ...[
|
||||||
@ -122,7 +121,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
icon: const Icon(Icons.calendar_today, size: 16),
|
icon: const Icon(Icons.calendar_today, size: 16),
|
||||||
label: Text(scheduledDate != null
|
label: Text(scheduledDate != null
|
||||||
? '${scheduledDate!.day.toString().padLeft(2, '0')}/${scheduledDate!.month.toString().padLeft(2, '0')}/${scheduledDate!.year}'
|
? '${scheduledDate!.day.toString().padLeft(2, '0')}/${scheduledDate!.month.toString().padLeft(2, '0')}/${scheduledDate!.year}'
|
||||||
: 'Date'),
|
: l.date),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final d = await showDatePicker(
|
final d = await showDatePicker(
|
||||||
context: ctx2,
|
context: ctx2,
|
||||||
@ -140,7 +139,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
icon: const Icon(Icons.access_time, size: 16),
|
icon: const Icon(Icons.access_time, size: 16),
|
||||||
label: Text(scheduledTime != null
|
label: Text(scheduledTime != null
|
||||||
? scheduledTime!.format(ctx2)
|
? scheduledTime!.format(ctx2)
|
||||||
: 'Heure'),
|
: l.time),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final t = await showTimePicker(
|
final t = await showTimePicker(
|
||||||
context: ctx2,
|
context: ctx2,
|
||||||
@ -157,7 +156,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(ctx2),
|
onPressed: () => Navigator.pop(ctx2),
|
||||||
child: const Text('Annuler'),
|
child: Text(l.cancel),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: titleCtrl.text.isEmpty ? null : () async {
|
onPressed: titleCtrl.text.isEmpty ? null : () async {
|
||||||
@ -179,7 +178,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
await _load(ctx);
|
await _load(ctx);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Text('Envoyer'),
|
child: Text(l.send),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -188,13 +187,14 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _confirmCancel(BuildContext context, ManagerAppContext ctx, PushNotificationDTO notif) {
|
void _confirmCancel(BuildContext context, ManagerAppContext ctx, PushNotificationDTO notif) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => AlertDialog(
|
builder: (_) => AlertDialog(
|
||||||
title: const Text('Annuler la notification'),
|
title: Text(l.cancelNotification),
|
||||||
content: Text('Annuler « ${notif.title} » ?'),
|
content: Text(l.cancelNotificationConfirm(notif.title ?? '')),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: () => Navigator.pop(context), child: const Text('Non')),
|
TextButton(onPressed: () => Navigator.pop(context), child: Text(l.no)),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@ -202,14 +202,13 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
final ok = await _cancel(ctx, notif.id!);
|
final ok = await _cancel(ctx, notif.id!);
|
||||||
if (ok && context.mounted) await _load(ctx);
|
if (ok && context.mounted) await _load(ctx);
|
||||||
},
|
},
|
||||||
child: const Text('Annuler', style: TextStyle(color: Colors.white)),
|
child: Text(l.cancel, style: const TextStyle(color: Colors.white)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Helpers ──────────────────────────────────────────────
|
|
||||||
static String _formatDate(DateTime? dt) {
|
static String _formatDate(DateTime? dt) {
|
||||||
if (dt == null) return '—';
|
if (dt == null) return '—';
|
||||||
final d = dt.toLocal();
|
final d = dt.toLocal();
|
||||||
@ -245,7 +244,6 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Build ────────────────────────────────────────────────
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -257,32 +255,30 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final appContext = Provider.of<AppContext>(context);
|
final appContext = Provider.of<AppContext>(context);
|
||||||
final ctx = appContext.getContext() as ManagerAppContext;
|
final ctx = appContext.getContext() as ManagerAppContext;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// ── Header ──
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('Notifications',
|
Text(l.notificationsTitle,
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () => _showSendModal(context, ctx),
|
onPressed: () => _showSendModal(context, ctx),
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: const Text('Nouveau message'),
|
label: Text(l.newMessage),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// ── KPIs ──
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
_KpiCard(
|
_KpiCard(
|
||||||
label: 'Toutes',
|
label: l.allNotifications,
|
||||||
count: _totalCount,
|
count: _totalCount,
|
||||||
color: Colors.blueGrey,
|
color: Colors.blueGrey,
|
||||||
selected: _statusFilter == null,
|
selected: _statusFilter == null,
|
||||||
@ -290,7 +286,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
_KpiCard(
|
_KpiCard(
|
||||||
label: 'Envoyées',
|
label: l.sentNotifications,
|
||||||
count: _sentCount,
|
count: _sentCount,
|
||||||
color: Colors.green,
|
color: Colors.green,
|
||||||
selected: _statusFilter == 'Sent',
|
selected: _statusFilter == 'Sent',
|
||||||
@ -298,7 +294,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
_KpiCard(
|
_KpiCard(
|
||||||
label: 'Planifiées',
|
label: l.scheduledNotifications,
|
||||||
count: _scheduledCount,
|
count: _scheduledCount,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
selected: _statusFilter == 'Scheduled',
|
selected: _statusFilter == 'Scheduled',
|
||||||
@ -306,7 +302,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
_KpiCard(
|
_KpiCard(
|
||||||
label: 'Échouées',
|
label: l.failedNotifications,
|
||||||
count: _failedCount,
|
count: _failedCount,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
selected: _statusFilter == 'Failed',
|
selected: _statusFilter == 'Failed',
|
||||||
@ -315,14 +311,12 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// ── List ──
|
|
||||||
if (_loading)
|
if (_loading)
|
||||||
const Center(child: CircularProgressIndicator())
|
const CommonLoader()
|
||||||
else if (_notifications.isEmpty)
|
else if (_notifications.isEmpty)
|
||||||
const Center(child: Text('Aucune notification envoyée'))
|
Center(child: Text(l.noNotifications))
|
||||||
else if (_filtered.isEmpty)
|
else if (_filtered.isEmpty)
|
||||||
const Center(child: Text('Aucune notification pour ce filtre'))
|
Center(child: Text(l.noNotificationsForFilter))
|
||||||
else
|
else
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Card(
|
child: Card(
|
||||||
@ -344,12 +338,12 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
columnSpacing: 24,
|
columnSpacing: 24,
|
||||||
headingRowColor: WidgetStateProperty.all(Colors.grey.shade50),
|
headingRowColor: WidgetStateProperty.all(Colors.grey.shade50),
|
||||||
dividerThickness: 1,
|
dividerThickness: 1,
|
||||||
columns: const [
|
columns: [
|
||||||
DataColumn(label: Text('Titre', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.messageTitle, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Topic', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.topic, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Date', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.date, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Statut', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.status, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('')),
|
const DataColumn(label: Text('')),
|
||||||
],
|
],
|
||||||
rows: _paginated.map((n) {
|
rows: _paginated.map((n) {
|
||||||
final isScheduled = n.status == 'Scheduled';
|
final isScheduled = n.status == 'Scheduled';
|
||||||
@ -362,7 +356,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
DataCell(isScheduled
|
DataCell(isScheduled
|
||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.delete_outline, color: Colors.red, size: 20),
|
icon: const Icon(Icons.delete_outline, color: Colors.red, size: 20),
|
||||||
tooltip: 'Annuler',
|
tooltip: l.tooltipCancelNotification,
|
||||||
onPressed: () => _confirmCancel(context, ctx, n),
|
onPressed: () => _confirmCancel(context, ctx, n),
|
||||||
)
|
)
|
||||||
: const SizedBox()),
|
: const SizedBox()),
|
||||||
@ -372,7 +366,6 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// ── Pagination ──
|
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(top: BorderSide(color: Colors.grey.shade200)),
|
border: Border(top: BorderSide(color: Colors.grey.shade200)),
|
||||||
@ -392,7 +385,7 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(
|
Text(
|
||||||
'${_filtered.length} résultat${_filtered.length > 1 ? 's' : ''}',
|
l.resultsCount(_filtered.length),
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'dart:ui' as ui;
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
|
|
||||||
class WebView extends StatefulWidget {
|
class WebView extends StatefulWidget {
|
||||||
WebView({required this.htmlText});
|
WebView({required this.htmlText});
|
||||||
@ -63,5 +64,5 @@ class _WebViewWidget extends State<WebView> {
|
|||||||
) :
|
) :
|
||||||
//WebViewWidget(controller: controller!)
|
//WebViewWidget(controller: controller!)
|
||||||
Text("Texte"):
|
Text("Texte"):
|
||||||
Center(child: Text("La page internet ne peut pas être affichée, l'url est incorrecte ou vide"));
|
Center(child: Text(AppLocalizations.of(context)!.webViewError));
|
||||||
} //_webView
|
} //_webView
|
||||||
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
import 'package:manager_app/Components/audio_player.dart';
|
import 'package:manager_app/Components/audio_player.dart';
|
||||||
import 'package:manager_app/Components/video_viewer.dart';
|
import 'package:manager_app/Components/video_viewer.dart';
|
||||||
|
import 'package:manager_app/Components/video_viewer_youtube.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
@ -87,14 +88,11 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ResourceType.VideoUrl:
|
case ResourceType.VideoUrl:
|
||||||
return SelectableText(resourceDTO.url!);
|
|
||||||
|
|
||||||
/*case ResourceType.VideoUrl:
|
|
||||||
if(resourceDTO.url == null) {
|
if(resourceDTO.url == null) {
|
||||||
return Center(child: Text("Error loading video"));
|
return Center(child: Text("Error loading video"));
|
||||||
} else {
|
} else {
|
||||||
return VideoViewerYoutube(videoUrl: resourceDTO.url!);
|
return VideoViewerYoutube(videoUrl: resourceDTO.url!);
|
||||||
}*/ // TODO
|
}
|
||||||
|
|
||||||
case ResourceType.Pdf:
|
case ResourceType.Pdf:
|
||||||
return Text("Fichier pdf - aucune visualisation possible");
|
return Text("Fichier pdf - aucune visualisation possible");
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
dynamic showNewResource(AppContext appContext, BuildContext context) async {
|
dynamic showNewResource(AppContext appContext, BuildContext context) async {
|
||||||
@ -27,7 +28,7 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
|
|||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text("Nouvelle ressource", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
Text(AppLocalizations.of(context)!.newResource, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||||
/*Column(
|
/*Column(
|
||||||
children: [
|
children: [
|
||||||
StringInputContainer(
|
StringInputContainer(
|
||||||
@ -70,7 +71,7 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
|
|||||||
width: 175,
|
width: 175,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Annuler",
|
text: AppLocalizations.of(context)!.cancel,
|
||||||
icon: Icons.undo,
|
icon: Icons.undo,
|
||||||
color: kSecond,
|
color: kSecond,
|
||||||
press: () {
|
press: () {
|
||||||
@ -86,7 +87,7 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
|
|||||||
width: 150,
|
width: 150,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Créer",
|
text: AppLocalizations.of(context)!.create,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
textColor: kWhite,
|
textColor: kWhite,
|
||||||
@ -96,13 +97,13 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
|
|||||||
if(resourceDetailDTO.url != null || filesToSendWeb != null) { // TODO clarify resourceDetailDTO.data != null
|
if(resourceDetailDTO.url != null || filesToSendWeb != null) { // TODO clarify resourceDetailDTO.data != null
|
||||||
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
|
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
|
||||||
} else {
|
} else {
|
||||||
showNotification(Colors.orange, kWhite, 'Aucun fichier n\'a été chargé', context, null);
|
showNotification(Colors.orange, kWhite, AppLocalizations.of(context)!.resourceNoFileLoaded, context, null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (resourceDetailDTO.url != null || filesToSendWeb!.length > 0 || filesToSend!.length > 0) { // TODO clarify resourceDetailDTO.data != null
|
if (resourceDetailDTO.url != null || filesToSendWeb!.length > 0 || filesToSend!.length > 0) { // TODO clarify resourceDetailDTO.data != null
|
||||||
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
|
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
|
||||||
} else {
|
} else {
|
||||||
showNotification(Colors.orange, kWhite, 'Aucun fichier n\'a été chargé', context, null);
|
showNotification(Colors.orange, kWhite, AppLocalizations.of(context)!.resourceNoFileLoaded, context, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*} else {
|
/*} else {
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:firebase_storage/firebase_storage.dart';
|
import 'package:firebase_storage/firebase_storage.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_app/Components/common_loader.dart';
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/Components/message_notification.dart';
|
import 'package:manager_app/Components/message_notification.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Screens/Resources/new_resource_popup.dart';
|
import 'package:manager_app/Screens/Resources/new_resource_popup.dart';
|
||||||
import 'package:manager_app/Screens/Resources/resource_body_grid.dart';
|
import 'package:manager_app/Screens/Resources/resource_body_grid.dart';
|
||||||
@ -103,7 +106,7 @@ class _ResourcesScreenState extends State<ResourcesScreen> {
|
|||||||
var resourceUpdated = managerAppContext.clientAPI!.resourceApi!.resourceUpdate(result);
|
var resourceUpdated = managerAppContext.clientAPI!.resourceApi!.resourceUpdate(result);
|
||||||
setState(() {
|
setState(() {
|
||||||
// refresh ui
|
// refresh ui
|
||||||
showNotification(kSuccess, kWhite, 'La ressource a été mise à jour avec succès', context, null);
|
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.resourceUpdatedSuccess, context, null);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error during updating resource");
|
print("Error during updating resource");
|
||||||
@ -117,10 +120,10 @@ class _ResourcesScreenState extends State<ResourcesScreen> {
|
|||||||
}
|
}
|
||||||
});//bodyGrid(tempOutput, size, appContext);
|
});//bodyGrid(tempOutput, size, appContext);
|
||||||
} else {
|
} else {
|
||||||
return Text("No data");
|
return Text(AppLocalizations.of(context)!.noData);
|
||||||
}
|
}
|
||||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
return Text("No data");
|
return Text(AppLocalizations.of(context)!.noData);
|
||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -149,6 +152,24 @@ Future<List<ResourceDTO?>?> create(ResourceDTO resourceDTO, List<File>? files, L
|
|||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
if(filesWeb != null) {
|
if(filesWeb != null) {
|
||||||
|
// Vérification quota stockage avant upload
|
||||||
|
if ((managerAppContext.instanceDTO?.storageQuotaBytes ?? 0) > 0) {
|
||||||
|
try {
|
||||||
|
final quotaUri = Uri.parse('${managerAppContext.host}/api/Instance/${managerAppContext.instanceId}/quota');
|
||||||
|
final quotaResponse = await http.get(quotaUri, headers: {'Authorization': 'Bearer ${managerAppContext.accessToken}'});
|
||||||
|
if (quotaResponse.statusCode == 200) {
|
||||||
|
final quotaData = jsonDecode(quotaResponse.body);
|
||||||
|
final storageUsed = (quotaData['storageUsedBytes'] as num).toInt();
|
||||||
|
final storageQuota = (quotaData['storageQuotaBytes'] as num).toInt();
|
||||||
|
final incomingBytes = filesWeb.fold<int>(0, (sum, f) => sum + (f.size));
|
||||||
|
if (storageUsed + incomingBytes > storageQuota) {
|
||||||
|
showNotification(kError, kWhite, 'Quota de stockage dépassé', context, null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
for (PlatformFile platformFile in filesWeb) {
|
for (PlatformFile platformFile in filesWeb) {
|
||||||
var mimeType = "";
|
var mimeType = "";
|
||||||
ResourceDTO resourceDTO = new ResourceDTO(label: platformFile.name);
|
ResourceDTO resourceDTO = new ResourceDTO(label: platformFile.name);
|
||||||
@ -200,8 +221,9 @@ Future<List<ResourceDTO?>?> create(ResourceDTO resourceDTO, List<File>? files, L
|
|||||||
UploadTask uploadTask = ref.putData(platformFile.bytes!, metadata);
|
UploadTask uploadTask = ref.putData(platformFile.bytes!, metadata);
|
||||||
uploadTask.then((res) {
|
uploadTask.then((res) {
|
||||||
res.ref.getDownloadURL().then((urlRessource) {
|
res.ref.getDownloadURL().then((urlRessource) {
|
||||||
showNotification(Colors.green, kWhite, 'La ressource a été créée avec succès', context, null);
|
showNotification(Colors.green, kWhite, AppLocalizations.of(context)!.resourceCreatedSuccess, context, null);
|
||||||
newResource.url = urlRessource;
|
newResource.url = urlRessource;
|
||||||
|
newResource.sizeBytes = platformFile.size;
|
||||||
(appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceUpdate(newResource);
|
(appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceUpdate(newResource);
|
||||||
createdResources.add(newResource);
|
createdResources.add(newResource);
|
||||||
index++;
|
index++;
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:manager_app/Components/string_input_container.dart';
|
|||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'dart:html' as html;
|
import 'dart:html' as html;
|
||||||
|
|
||||||
@ -110,7 +111,7 @@ Future<ResourceDTO?> showResource(ResourceDTO resourceDTO, AppContext appContext
|
|||||||
width: 220,
|
width: 220,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Télécharger",
|
text: AppLocalizations.of(context)!.download,
|
||||||
icon: Icons.download,
|
icon: Icons.download,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
press: () {
|
press: () {
|
||||||
@ -134,7 +135,7 @@ Future<ResourceDTO?> showResource(ResourceDTO resourceDTO, AppContext appContext
|
|||||||
width: 220,
|
width: 220,
|
||||||
height: 70,
|
height: 70,
|
||||||
child: RoundedButton(
|
child: RoundedButton(
|
||||||
text: "Sauvegarder",
|
text: AppLocalizations.of(context)!.save,
|
||||||
icon: Icons.check,
|
icon: Icons.check,
|
||||||
color: kPrimaryColor,
|
color: kPrimaryColor,
|
||||||
press: () {
|
press: () {
|
||||||
@ -157,7 +158,7 @@ Future<ResourceDTO?> showResource(ResourceDTO resourceDTO, AppContext appContext
|
|||||||
|
|
||||||
Future<void> delete(ResourceDTO resourceDTO, AppContext appContext, context) async {
|
Future<void> delete(ResourceDTO resourceDTO, AppContext appContext, context) async {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
"Êtes-vous sûr de vouloir supprimer cette ressource ?",
|
AppLocalizations.of(context)!.resourceDeleteConfirm,
|
||||||
() {},
|
() {},
|
||||||
() async {
|
() async {
|
||||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceDelete(resourceDTO.id!);
|
await (appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceDelete(resourceDTO.id!);
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -55,20 +57,20 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildHeader(),
|
_buildHeader(context),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FutureBuilder<StatsSummaryDTO?>(
|
child: FutureBuilder<StatsSummaryDTO?>(
|
||||||
future: _future,
|
future: _future,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const CommonLoader();
|
||||||
}
|
}
|
||||||
if (snapshot.hasError || snapshot.data == null) {
|
if (snapshot.hasError || snapshot.data == null) {
|
||||||
return Center(child: Text('Impossible de charger les statistiques', style: TextStyle(color: kBodyTextColor)));
|
return Center(child: Text(AppLocalizations.of(context)!.statsLoadError, style: TextStyle(color: kBodyTextColor)));
|
||||||
}
|
}
|
||||||
final stats = snapshot.data!;
|
final stats = snapshot.data!;
|
||||||
return _buildDashboard(stats);
|
return _buildDashboard(context, stats);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -77,23 +79,33 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildHeader() {
|
bool get _hasAdvancedStats =>
|
||||||
|
_managerAppContext.instanceDTO?.hasAdvancedStats ?? false;
|
||||||
|
|
||||||
|
int get _statsHistoryDays =>
|
||||||
|
_managerAppContext.instanceDTO?.statsHistoryDays ?? 30;
|
||||||
|
|
||||||
|
Widget _buildHeader(BuildContext context) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
|
final historyDays = _statsHistoryDays;
|
||||||
|
final maxDays = historyDays == 0 ? 999 : historyDays;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('Statistiques', style: TextStyle(fontSize: 26, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
Text(l.statisticsTitle, style: TextStyle(fontSize: 26, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
||||||
SegmentedButton<int>(
|
SegmentedButton<int>(
|
||||||
style: SegmentedButton.styleFrom(
|
style: SegmentedButton.styleFrom(
|
||||||
selectedBackgroundColor: kPrimaryColor,
|
selectedBackgroundColor: kPrimaryColor,
|
||||||
selectedForegroundColor: kWhite,
|
selectedForegroundColor: kWhite,
|
||||||
),
|
),
|
||||||
segments: const [
|
segments: [
|
||||||
ButtonSegment(value: 7, label: Text('7j')),
|
const ButtonSegment(value: 7, label: Text('7j')),
|
||||||
ButtonSegment(value: 30, label: Text('30j')),
|
const ButtonSegment(value: 30, label: Text('30j')),
|
||||||
ButtonSegment(value: 90, label: Text('90j')),
|
ButtonSegment(value: 90, label: Text('90j'), enabled: maxDays >= 90),
|
||||||
],
|
],
|
||||||
selected: {_selectedDays},
|
selected: {_selectedDays},
|
||||||
onSelectionChanged: (s) {
|
onSelectionChanged: (s) {
|
||||||
@ -108,7 +120,7 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
spacing: 8,
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
ChoiceChip(
|
ChoiceChip(
|
||||||
label: const Text('Tous'),
|
label: Text(l.statsAll),
|
||||||
selected: _selectedAppType == null,
|
selected: _selectedAppType == null,
|
||||||
selectedColor: kPrimaryColor,
|
selectedColor: kPrimaryColor,
|
||||||
labelStyle: TextStyle(color: _selectedAppType == null ? kWhite : kBodyTextColor),
|
labelStyle: TextStyle(color: _selectedAppType == null ? kWhite : kBodyTextColor),
|
||||||
@ -127,7 +139,8 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDashboard(StatsSummaryDTO stats) {
|
Widget _buildDashboard(BuildContext context, StatsSummaryDTO stats) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
if (stats.totalSessions == 0) {
|
if (stats.totalSessions == 0) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -136,13 +149,13 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
Icon(Icons.bar_chart_outlined, size: 56, color: kBodyTextColor.withValues(alpha: 0.4)),
|
Icon(Icons.bar_chart_outlined, size: 56, color: kBodyTextColor.withValues(alpha: 0.4)),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
'Pas encore de données pour cette période',
|
l.statsNoData,
|
||||||
style: TextStyle(fontSize: 15, color: kBodyTextColor),
|
style: TextStyle(fontSize: 15, color: kBodyTextColor),
|
||||||
),
|
),
|
||||||
if (_selectedAppType != null) ...[
|
if (_selectedAppType != null) ...[
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'Aucun event reçu pour le type "${_selectedAppType!.name}"',
|
l.statsNoDataForType(_selectedAppType!.name),
|
||||||
style: TextStyle(fontSize: 13, color: kBodyTextColor.withValues(alpha: 0.6)),
|
style: TextStyle(fontSize: 13, color: kBodyTextColor.withValues(alpha: 0.6)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -155,23 +168,20 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// KPI cards
|
_buildKpiRow(context, stats),
|
||||||
_buildKpiRow(stats),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
// Line chart
|
_buildLineChart(context, stats),
|
||||||
_buildLineChart(stats),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
// Bar chart + Donut charts
|
_buildChartsRow(context, stats),
|
||||||
_buildChartsRow(stats),
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
// Bottom tables
|
_buildTablesRow(context, stats),
|
||||||
_buildTablesRow(stats),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildKpiRow(StatsSummaryDTO stats) {
|
Widget _buildKpiRow(BuildContext context, StatsSummaryDTO stats) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final topAppType = stats.appTypeDistribution.isNotEmpty
|
final topAppType = stats.appTypeDistribution.isNotEmpty
|
||||||
? stats.appTypeDistribution.entries.reduce((a, b) => a.value > b.value ? a : b)
|
? stats.appTypeDistribution.entries.reduce((a, b) => a.value > b.value ? a : b)
|
||||||
: null;
|
: null;
|
||||||
@ -181,13 +191,13 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
_kpiCard('Sessions', '${stats.totalSessions}', Icons.people_outline),
|
_kpiCard(l.statsSessions, '${stats.totalSessions}', Icons.people_outline),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
_kpiCard('Durée moy.', _formatDuration(stats.avgVisitDurationSeconds), Icons.timer_outlined),
|
_kpiCard(l.statsAvgDuration, _formatDuration(stats.avgVisitDurationSeconds), Icons.timer_outlined),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
_kpiCard('App top', topAppType?.key ?? '—', Icons.phone_iphone),
|
_kpiCard(l.statsTopApp, topAppType?.key ?? '—', Icons.phone_iphone),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
_kpiCard('Langue top', topLang?.key.toUpperCase() ?? '—', Icons.language),
|
_kpiCard(l.statsTopLang, topLang?.key.toUpperCase() ?? '—', Icons.language),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -215,7 +225,8 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLineChart(StatsSummaryDTO stats) {
|
Widget _buildLineChart(BuildContext context, StatsSummaryDTO stats) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
if (stats.visitsByDay.isEmpty) return const SizedBox();
|
if (stats.visitsByDay.isEmpty) return const SizedBox();
|
||||||
|
|
||||||
final spots = <FlSpot>[];
|
final spots = <FlSpot>[];
|
||||||
@ -229,7 +240,9 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
tabletSpots.add(FlSpot(i.toDouble(), d.tablet.toDouble()));
|
tabletSpots.add(FlSpot(i.toDouble(), d.tablet.toDouble()));
|
||||||
}
|
}
|
||||||
|
|
||||||
final isFiltered = _selectedAppType != null;
|
final mobileHasData = mobileSpots.any((s) => s.y > 0);
|
||||||
|
final tabletHasData = tabletSpots.any((s) => s.y > 0);
|
||||||
|
final showBreakdown = _selectedAppType == null && (mobileHasData || tabletHasData);
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
@ -240,17 +253,17 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('Visites par jour', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
Text(l.statsVisitsByDay, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
if (!isFiltered) Row(children: [
|
if (showBreakdown) Row(children: [
|
||||||
_legendDot(kPrimaryColor), const SizedBox(width: 4), Text('Mobile', style: TextStyle(fontSize: 12, color: kBodyTextColor)),
|
if (mobileHasData) ...[_legendDot(kPrimaryColor), const SizedBox(width: 4), Text('Mobile', style: TextStyle(fontSize: 12, color: kBodyTextColor)), const SizedBox(width: 12)],
|
||||||
const SizedBox(width: 12),
|
if (tabletHasData) ...[_legendDot(kSecond), const SizedBox(width: 4), Text('Tablet', style: TextStyle(fontSize: 12, color: kBodyTextColor))],
|
||||||
_legendDot(kSecond), const SizedBox(width: 4), Text('Tablet', style: TextStyle(fontSize: 12, color: kBodyTextColor)),
|
|
||||||
]),
|
]),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 200,
|
height: 200,
|
||||||
child: LineChart(LineChartData(
|
child: LineChart(LineChartData(
|
||||||
|
minY: 0,
|
||||||
gridData: FlGridData(show: true, drawVerticalLine: false),
|
gridData: FlGridData(show: true, drawVerticalLine: false),
|
||||||
titlesData: FlTitlesData(
|
titlesData: FlTitlesData(
|
||||||
leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: 32)),
|
leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: true, reservedSize: 32)),
|
||||||
@ -268,9 +281,12 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
borderData: FlBorderData(show: false),
|
borderData: FlBorderData(show: false),
|
||||||
lineBarsData: isFiltered
|
lineBarsData: showBreakdown
|
||||||
? [_lineBar(spots, kPrimaryColor)]
|
? [
|
||||||
: [_lineBar(mobileSpots, kPrimaryColor), _lineBar(tabletSpots, kSecond)],
|
if (mobileHasData) _lineBar(mobileSpots, kPrimaryColor),
|
||||||
|
if (tabletHasData) _lineBar(tabletSpots, kSecond),
|
||||||
|
]
|
||||||
|
: [_lineBar(spots, kPrimaryColor)],
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -289,28 +305,30 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
isCurved: true,
|
isCurved: true,
|
||||||
color: color,
|
color: color,
|
||||||
barWidth: 2,
|
barWidth: 2,
|
||||||
dotData: FlDotData(show: false),
|
dotData: FlDotData(show: spots.length <= 1),
|
||||||
belowBarData: BarAreaData(show: true, color: color.withOpacity(0.1)),
|
belowBarData: BarAreaData(show: true, color: color.withValues(alpha: 0.1)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildChartsRow(StatsSummaryDTO stats) {
|
Widget _buildChartsRow(BuildContext context, StatsSummaryDTO stats) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final showAppTypeDonut = _selectedAppType == null;
|
final showAppTypeDonut = _selectedAppType == null;
|
||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(flex: 2, child: _buildTopSectionsChart(stats)),
|
Expanded(flex: 2, child: _buildTopSectionsChart(context, stats)),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
if (showAppTypeDonut) ...[
|
if (showAppTypeDonut) ...[
|
||||||
Expanded(child: _buildDonut(stats.appTypeDistribution, 'Apps')),
|
Expanded(child: _buildDonut(stats.appTypeDistribution, l.statsApps)),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
],
|
],
|
||||||
Expanded(child: _buildDonut(stats.languageDistribution, 'Langues')),
|
Expanded(child: _buildDonut(stats.languageDistribution, l.statsLanguages)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTopSectionsChart(StatsSummaryDTO stats) {
|
Widget _buildTopSectionsChart(BuildContext context, StatsSummaryDTO stats) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
if (stats.topSections.isEmpty) return const SizedBox();
|
if (stats.topSections.isEmpty) return const SizedBox();
|
||||||
final sections = stats.topSections.take(8).toList();
|
final sections = stats.topSections.take(8).toList();
|
||||||
final maxViews = sections.map((s) => s.views).reduce((a, b) => a > b ? a : b);
|
final maxViews = sections.map((s) => s.views).reduce((a, b) => a > b ? a : b);
|
||||||
@ -324,7 +342,7 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('Top sections', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
Text(l.statsTopSections, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 240,
|
height: 240,
|
||||||
@ -341,7 +359,8 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
getTitlesWidget: (value, meta) {
|
getTitlesWidget: (value, meta) {
|
||||||
final idx = value.toInt();
|
final idx = value.toInt();
|
||||||
if (idx < 0 || idx >= sections.length) return const SizedBox();
|
if (idx < 0 || idx >= sections.length) return const SizedBox();
|
||||||
final title = sections[idx].sectionTitle ?? sections[idx].sectionId ?? '';
|
final raw = sections[idx].sectionTitle ?? sections[idx].sectionId ?? '';
|
||||||
|
final title = raw.replaceAll(RegExp(r'<[^>]*>'), '').trim();
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(top: 4),
|
padding: const EdgeInsets.only(top: 4),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -430,15 +449,19 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTablesRow(StatsSummaryDTO stats) {
|
Widget _buildTablesRow(BuildContext context, StatsSummaryDTO stats) {
|
||||||
|
if (!_hasAdvancedStats) {
|
||||||
|
return _buildPremiumLockedCard(context);
|
||||||
|
}
|
||||||
|
|
||||||
final tables = <Widget>[
|
final tables = <Widget>[
|
||||||
if (stats.topPois.isNotEmpty) Expanded(child: _buildPoiTable(stats)),
|
if (stats.topPois.isNotEmpty) Expanded(child: _buildPoiTable(context, stats)),
|
||||||
if (stats.topAgendaEvents.isNotEmpty) Expanded(child: _buildAgendaTable(stats)),
|
if (stats.topAgendaEvents.isNotEmpty) Expanded(child: _buildAgendaTable(context, stats)),
|
||||||
if (stats.quizStats.isNotEmpty) Expanded(child: _buildQuizTable(stats)),
|
if (stats.quizStats.isNotEmpty) Expanded(child: _buildQuizTable(context, stats)),
|
||||||
if (stats.gameStats.isNotEmpty) Expanded(child: _buildGameTable(stats)),
|
if (stats.gameStats.isNotEmpty) Expanded(child: _buildGameTable(context, stats)),
|
||||||
if (stats.topArticles.isNotEmpty) Expanded(child: _buildArticleTable(stats)),
|
if (stats.topArticles.isNotEmpty) Expanded(child: _buildArticleTable(context, stats)),
|
||||||
if (stats.topMenuItems.isNotEmpty) Expanded(child: _buildMenuTable(stats)),
|
if (stats.topMenuItems.isNotEmpty) Expanded(child: _buildMenuTable(context, stats)),
|
||||||
if (stats.qrScans.totalScans > 0) Expanded(child: _buildQrCard(stats)),
|
if (stats.qrScans.totalScans > 0) Expanded(child: _buildQrCard(context, stats)),
|
||||||
];
|
];
|
||||||
if (tables.isEmpty) return const SizedBox();
|
if (tables.isEmpty) return const SizedBox();
|
||||||
final spaced = <Widget>[];
|
final spaced = <Widget>[];
|
||||||
@ -449,51 +472,88 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
return Row(crossAxisAlignment: CrossAxisAlignment.start, children: spaced);
|
return Row(crossAxisAlignment: CrossAxisAlignment.start, children: spaced);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPoiTable(StatsSummaryDTO stats) {
|
Widget _buildPremiumLockedCard(BuildContext context) {
|
||||||
return _tableCard('Top POI', ['POI', 'Taps'], stats.topPois.map((p) => [
|
return Card(
|
||||||
|
elevation: 0,
|
||||||
|
color: kWhite,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.lock_outline, color: kBodyTextColor.withValues(alpha: 0.5), size: 28),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text('Statistiques avancées', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
'Les stats détaillées (POI, quiz, jeux, articles, QR…) sont disponibles avec le plan Premium.',
|
||||||
|
style: TextStyle(fontSize: 13, color: kBodyTextColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPoiTable(BuildContext context, StatsSummaryDTO stats) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
|
return _tableCard(l.statsTopPOI, [l.statsPOI, l.statsTaps], stats.topPois.map((p) => [
|
||||||
p.title ?? p.geoPointId?.toString() ?? '—',
|
p.title ?? p.geoPointId?.toString() ?? '—',
|
||||||
'${p.taps}',
|
'${p.taps}',
|
||||||
]).toList());
|
]).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAgendaTable(StatsSummaryDTO stats) {
|
Widget _buildAgendaTable(BuildContext context, StatsSummaryDTO stats) {
|
||||||
return _tableCard('Top événements agenda', ['Événement', 'Taps'], stats.topAgendaEvents.map((e) => [
|
final l = AppLocalizations.of(context)!;
|
||||||
|
return _tableCard(l.statsTopAgenda, [l.statsEvent, l.statsTaps], stats.topAgendaEvents.map((e) => [
|
||||||
e.eventTitle ?? e.eventId ?? '—',
|
e.eventTitle ?? e.eventId ?? '—',
|
||||||
'${e.taps}',
|
'${e.taps}',
|
||||||
]).toList());
|
]).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildQuizTable(StatsSummaryDTO stats) {
|
Widget _buildQuizTable(BuildContext context, StatsSummaryDTO stats) {
|
||||||
return _tableCard('Quiz', ['Section', 'Score moy', 'Complétions'], stats.quizStats.map((q) => [
|
final l = AppLocalizations.of(context)!;
|
||||||
|
return _tableCard(l.statsQuiz, [l.statsSection, l.statsAvgScore, l.statsCompletions], stats.quizStats.map((q) => [
|
||||||
q.sectionTitle ?? q.sectionId ?? '—',
|
q.sectionTitle ?? q.sectionId ?? '—',
|
||||||
'${q.avgScore.toStringAsFixed(1)} / ${q.totalQuestions}',
|
'${q.avgScore.toStringAsFixed(1)} / ${q.totalQuestions}',
|
||||||
'${q.completions}',
|
'${q.completions}',
|
||||||
]).toList());
|
]).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildGameTable(StatsSummaryDTO stats) {
|
Widget _buildGameTable(BuildContext context, StatsSummaryDTO stats) {
|
||||||
return _tableCard('Jeux', ['Type', 'Complétions', 'Durée moy.'], stats.gameStats.map((g) => [
|
final l = AppLocalizations.of(context)!;
|
||||||
|
return _tableCard(l.statsGames, [l.statsGameType, l.statsCompletions, l.statsAvgDuration], stats.gameStats.map((g) => [
|
||||||
g.gameType ?? '—',
|
g.gameType ?? '—',
|
||||||
'${g.completions}',
|
'${g.completions}',
|
||||||
_formatDuration(g.avgDurationSeconds),
|
_formatDuration(g.avgDurationSeconds),
|
||||||
]).toList());
|
]).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildArticleTable(StatsSummaryDTO stats) {
|
Widget _buildArticleTable(BuildContext context, StatsSummaryDTO stats) {
|
||||||
return _tableCard('Articles lus', ['Section', 'Lectures'], stats.topArticles.map((a) => [
|
final l = AppLocalizations.of(context)!;
|
||||||
|
return _tableCard(l.statsArticles, [l.statsSection, l.statsReadings], stats.topArticles.map((a) => [
|
||||||
a.sectionId ?? '—',
|
a.sectionId ?? '—',
|
||||||
'${a.reads}',
|
'${a.reads}',
|
||||||
]).toList());
|
]).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMenuTable(StatsSummaryDTO stats) {
|
Widget _buildMenuTable(BuildContext context, StatsSummaryDTO stats) {
|
||||||
return _tableCard('Menu', ['Item', 'Taps'], stats.topMenuItems.map((m) => [
|
final l = AppLocalizations.of(context)!;
|
||||||
|
return _tableCard(l.statsMenuTitle, [l.statsMenuItem, l.statsTaps], stats.topMenuItems.map((m) => [
|
||||||
m.menuItemTitle ?? m.targetSectionId ?? '—',
|
m.menuItemTitle ?? m.targetSectionId ?? '—',
|
||||||
'${m.taps}',
|
'${m.taps}',
|
||||||
]).toList());
|
]).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildQrCard(StatsSummaryDTO stats) {
|
Widget _buildQrCard(BuildContext context, StatsSummaryDTO stats) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final qr = stats.qrScans;
|
final qr = stats.qrScans;
|
||||||
return Card(
|
return Card(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
@ -504,13 +564,13 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('QR Scans', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
Text(l.statsQrScans, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_qrRow(Icons.qr_code_scanner, 'Total', '${qr.totalScans}', kPrimaryColor),
|
_qrRow(Icons.qr_code_scanner, l.statsTotal, '${qr.totalScans}', kPrimaryColor),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_qrRow(Icons.check_circle_outline, 'Valides', '${qr.validScans}', Colors.green.shade600),
|
_qrRow(Icons.check_circle_outline, l.statsValid, '${qr.validScans}', Colors.green.shade600),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_qrRow(Icons.cancel_outlined, 'Invalides', '${qr.invalidScans}', Colors.red.shade400),
|
_qrRow(Icons.cancel_outlined, l.statsInvalid, '${qr.invalidScans}', Colors.red.shade400),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/app_context.dart';
|
import 'package:manager_app/app_context.dart';
|
||||||
|
import 'package:manager_app/Components/common_loader.dart';
|
||||||
import 'package:manager_app/constants.dart';
|
import 'package:manager_app/constants.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -26,7 +28,6 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
return '—';
|
return '—';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convertit une valeur de rôle (String ou int) en int pour les comparaisons
|
|
||||||
static int _roleToInt(dynamic v) {
|
static int _roleToInt(dynamic v) {
|
||||||
if (v is int) return v;
|
if (v is int) return v;
|
||||||
if (v is String) {
|
if (v is String) {
|
||||||
@ -36,7 +37,6 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Roles the caller is allowed to assign (can't assign higher than own role)
|
|
||||||
List<int> _allowedRoles(int callerRoleValue) =>
|
List<int> _allowedRoles(int callerRoleValue) =>
|
||||||
[0, 1, 2, 3].where((r) => r >= callerRoleValue).toList();
|
[0, 1, 2, 3].where((r) => r >= callerRoleValue).toList();
|
||||||
|
|
||||||
@ -88,29 +88,30 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _showCreateDialog(BuildContext context, ManagerAppContext ctx) {
|
void _showCreateDialog(BuildContext context, ManagerAppContext ctx) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final callerRole = _roleToInt(ctx.role?.value);
|
final callerRole = _roleToInt(ctx.role?.value);
|
||||||
final emailCtrl = TextEditingController();
|
final emailCtrl = TextEditingController();
|
||||||
final firstCtrl = TextEditingController();
|
final firstCtrl = TextEditingController();
|
||||||
final lastCtrl = TextEditingController();
|
final lastCtrl = TextEditingController();
|
||||||
final passCtrl = TextEditingController();
|
final passCtrl = TextEditingController();
|
||||||
int selectedRole = callerRole; // default: same as caller
|
int selectedRole = callerRole;
|
||||||
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) {
|
builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text('Créer un utilisateur'),
|
title: Text(l.createUserTitle),
|
||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
TextField(controller: emailCtrl, decoration: const InputDecoration(labelText: 'Email')),
|
TextField(controller: emailCtrl, decoration: InputDecoration(labelText: l.email)),
|
||||||
TextField(controller: firstCtrl, decoration: const InputDecoration(labelText: 'Prénom')),
|
TextField(controller: firstCtrl, decoration: InputDecoration(labelText: l.firstName)),
|
||||||
TextField(controller: lastCtrl, decoration: const InputDecoration(labelText: 'Nom')),
|
TextField(controller: lastCtrl, decoration: InputDecoration(labelText: l.lastName)),
|
||||||
TextField(controller: passCtrl, obscureText: true, decoration: const InputDecoration(labelText: 'Mot de passe')),
|
TextField(controller: passCtrl, obscureText: true, decoration: InputDecoration(labelText: l.password)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('Rôle', style: TextStyle(fontSize: 12, color: Colors.grey)),
|
Text(l.role, style: const TextStyle(fontSize: 12, color: Colors.grey)),
|
||||||
DropdownButton<int>(
|
DropdownButton<int>(
|
||||||
value: selectedRole,
|
value: selectedRole,
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
@ -124,14 +125,14 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: () => Navigator.pop(ctx2), child: const Text('Annuler')),
|
TextButton(onPressed: () => Navigator.pop(ctx2), child: Text(l.cancel)),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.pop(ctx2);
|
Navigator.pop(ctx2);
|
||||||
await _createUser(ctx, emailCtrl.text, firstCtrl.text,
|
await _createUser(ctx, emailCtrl.text, firstCtrl.text,
|
||||||
lastCtrl.text, passCtrl.text, selectedRole);
|
lastCtrl.text, passCtrl.text, selectedRole);
|
||||||
},
|
},
|
||||||
child: const Text('Créer'),
|
child: Text(l.create),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -140,6 +141,7 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _showEditDialog(BuildContext context, ManagerAppContext ctx, Map<String, dynamic> user) {
|
void _showEditDialog(BuildContext context, ManagerAppContext ctx, Map<String, dynamic> user) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final callerRole = _roleToInt(ctx.role?.value);
|
final callerRole = _roleToInt(ctx.role?.value);
|
||||||
final firstCtrl = TextEditingController(text: user['firstName'] as String? ?? '');
|
final firstCtrl = TextEditingController(text: user['firstName'] as String? ?? '');
|
||||||
final lastCtrl = TextEditingController(text: user['lastName'] as String? ?? '');
|
final lastCtrl = TextEditingController(text: user['lastName'] as String? ?? '');
|
||||||
@ -149,16 +151,16 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) {
|
builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text('Modifier l\'utilisateur'),
|
title: Text(l.editUserTitle),
|
||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
TextField(controller: firstCtrl, decoration: const InputDecoration(labelText: 'Prénom')),
|
TextField(controller: firstCtrl, decoration: InputDecoration(labelText: l.firstName)),
|
||||||
TextField(controller: lastCtrl, decoration: const InputDecoration(labelText: 'Nom')),
|
TextField(controller: lastCtrl, decoration: InputDecoration(labelText: l.lastName)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('Rôle', style: TextStyle(fontSize: 12, color: Colors.grey)),
|
Text(l.role, style: const TextStyle(fontSize: 12, color: Colors.grey)),
|
||||||
DropdownButton<int>(
|
DropdownButton<int>(
|
||||||
value: selectedRole,
|
value: selectedRole,
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
@ -172,14 +174,14 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: () => Navigator.pop(ctx2), child: const Text('Annuler')),
|
TextButton(onPressed: () => Navigator.pop(ctx2), child: Text(l.cancel)),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.pop(ctx2);
|
Navigator.pop(ctx2);
|
||||||
await _updateUser(ctx, user['id'] as String, firstCtrl.text,
|
await _updateUser(ctx, user['id'] as String, firstCtrl.text,
|
||||||
lastCtrl.text, selectedRole);
|
lastCtrl.text, selectedRole);
|
||||||
},
|
},
|
||||||
child: const Text('Enregistrer'),
|
child: Text(l.save),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -188,20 +190,21 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _confirmDelete(BuildContext context, ManagerAppContext ctx, Map<String, dynamic> user) {
|
void _confirmDelete(BuildContext context, ManagerAppContext ctx, Map<String, dynamic> user) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => AlertDialog(
|
builder: (_) => AlertDialog(
|
||||||
title: const Text('Supprimer l\'utilisateur'),
|
title: Text(l.deleteUserTitle),
|
||||||
content: Text('Supprimer ${user['email']} ?'),
|
content: Text(l.deleteUserConfirm(user['email'] as String? ?? '')),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(onPressed: () => Navigator.pop(context), child: const Text('Annuler')),
|
TextButton(onPressed: () => Navigator.pop(context), child: Text(l.cancel)),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
await _deleteUser(ctx, user['id'] as String);
|
await _deleteUser(ctx, user['id'] as String);
|
||||||
},
|
},
|
||||||
child: const Text('Supprimer', style: TextStyle(color: Colors.white)),
|
child: Text(l.delete, style: const TextStyle(color: Colors.white)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -228,6 +231,7 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = AppLocalizations.of(context)!;
|
||||||
final appContext = Provider.of<AppContext>(context);
|
final appContext = Provider.of<AppContext>(context);
|
||||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||||
|
|
||||||
@ -237,19 +241,19 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('Utilisateurs', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
Text(l.usersTitle, style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: kPrimaryColor)),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () => _showCreateDialog(context, managerCtx),
|
onPressed: () => _showCreateDialog(context, managerCtx),
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: const Text('Créer un utilisateur'),
|
label: Text(l.createUserBtn),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
if (_loading)
|
if (_loading)
|
||||||
const Center(child: CircularProgressIndicator())
|
const CommonLoader()
|
||||||
else if (_users.isEmpty)
|
else if (_users.isEmpty)
|
||||||
const Center(child: Text('Aucun utilisateur'))
|
Center(child: Text(l.noUsers))
|
||||||
else
|
else
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Card(
|
child: Card(
|
||||||
@ -268,12 +272,12 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
columnSpacing: 24,
|
columnSpacing: 24,
|
||||||
headingRowColor: WidgetStateProperty.all(Colors.grey.shade50),
|
headingRowColor: WidgetStateProperty.all(Colors.grey.shade50),
|
||||||
dividerThickness: 1,
|
dividerThickness: 1,
|
||||||
columns: const [
|
columns: [
|
||||||
DataColumn(label: Text('Email', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.email, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Prénom', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.firstName, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Nom', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.lastName, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Rôle', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.role, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
DataColumn(label: Text('Actions', style: TextStyle(fontWeight: FontWeight.w600))),
|
DataColumn(label: Text(l.actions, style: const TextStyle(fontWeight: FontWeight.w600))),
|
||||||
],
|
],
|
||||||
rows: _users.map((user) {
|
rows: _users.map((user) {
|
||||||
final roleColor = _roleColor(user['role']);
|
final roleColor = _roleColor(user['role']);
|
||||||
@ -294,12 +298,12 @@ class _UsersScreenState extends State<UsersScreen> {
|
|||||||
DataCell(Row(children: [
|
DataCell(Row(children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.edit, color: kPrimaryColor, size: 20),
|
icon: Icon(Icons.edit, color: kPrimaryColor, size: 20),
|
||||||
tooltip: 'Modifier',
|
tooltip: l.tooltipEdit,
|
||||||
onPressed: () => _showEditDialog(context, managerCtx, user),
|
onPressed: () => _showEditDialog(context, managerCtx, user),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.delete_outline, color: Colors.red, size: 20),
|
icon: const Icon(Icons.delete_outline, color: Colors.red, size: 20),
|
||||||
tooltip: 'Supprimer',
|
tooltip: l.tooltipDelete,
|
||||||
onPressed: () => _confirmDelete(context, managerCtx, user),
|
onPressed: () => _confirmDelete(context, managerCtx, user),
|
||||||
),
|
),
|
||||||
])),
|
])),
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import 'package:manager_app/Components/message_notification.dart';
|
|||||||
import 'package:manager_app/Components/rounded_button.dart';
|
import 'package:manager_app/Components/rounded_button.dart';
|
||||||
import 'package:manager_app/Components/rounded_input_field.dart';
|
import 'package:manager_app/Components/rounded_input_field.dart';
|
||||||
import 'package:manager_app/Components/rounded_password_field.dart';
|
import 'package:manager_app/Components/rounded_password_field.dart';
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:manager_app/Helpers/FileHelper.dart';
|
import 'package:manager_app/Helpers/FileHelper.dart';
|
||||||
import 'package:manager_app/Models/managerContext.dart';
|
import 'package:manager_app/Models/managerContext.dart';
|
||||||
import 'package:manager_app/Models/session.dart';
|
import 'package:manager_app/Models/session.dart';
|
||||||
@ -88,7 +89,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
userRole = token.role;
|
userRole = token.role;
|
||||||
|
|
||||||
showNotification(
|
showNotification(
|
||||||
kSuccess, kWhite, 'Connexion réussie', context, null);
|
kSuccess, kWhite, AppLocalizations.of(context)!.loginSuccess, context, null);
|
||||||
|
|
||||||
if (isRememberMe) {
|
if (isRememberMe) {
|
||||||
if (!localStorage.containsKey("remember")) {
|
if (!localStorage.containsKey("remember")) {
|
||||||
@ -171,7 +172,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
(Route<dynamic> route) => false // For pushAndRemoveUntil
|
(Route<dynamic> route) => false // For pushAndRemoveUntil
|
||||||
);*/
|
);*/
|
||||||
} else {
|
} else {
|
||||||
showNotification(Colors.orange, kWhite, 'Un problème est survenu lors de la connexion', context, null);
|
showNotification(Colors.orange, kWhite, AppLocalizations.of(context)!.loginError, context, null);
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
@ -181,7 +182,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
print("error auth");
|
print("error auth");
|
||||||
print(e);
|
print(e);
|
||||||
if(fromClick) {
|
if(fromClick) {
|
||||||
showNotification(Colors.orange, kWhite, 'Un problème est survenu lors de la connexion', context, null);
|
showNotification(Colors.orange, kWhite, AppLocalizations.of(context)!.loginError, context, null);
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
});
|
});
|
||||||
@ -393,13 +394,13 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("Se souvenir de moi", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),),
|
Text(AppLocalizations.of(context)!.rememberMe, style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: size.height * 0.015),
|
SizedBox(height: size.height * 0.015),
|
||||||
!isLoading ? RoundedButton(
|
!isLoading ? RoundedButton(
|
||||||
text: "SE CONNECTER",
|
text: AppLocalizations.of(context)!.connect,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
vertical: 15,
|
vertical: 15,
|
||||||
horizontal: 30,
|
horizontal: 30,
|
||||||
|
|||||||
35
lib/Services/ai_translate_service.dart
Normal file
35
lib/Services/ai_translate_service.dart
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
class AiTranslateService {
|
||||||
|
static Future<Map<String, String>> translate({
|
||||||
|
required String host,
|
||||||
|
required String accessToken,
|
||||||
|
required String instanceId,
|
||||||
|
required String text,
|
||||||
|
required String sourceLang,
|
||||||
|
required List<String> targetLangs,
|
||||||
|
}) async {
|
||||||
|
final uri = Uri.parse('$host/api/Ai/translate?instanceId=$instanceId');
|
||||||
|
final response = await http.post(
|
||||||
|
uri,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer $accessToken',
|
||||||
|
},
|
||||||
|
body: jsonEncode({
|
||||||
|
'text': text,
|
||||||
|
'sourceLang': sourceLang,
|
||||||
|
'targetLangs': targetLangs,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw Exception('Erreur traduction IA : ${response.statusCode}');
|
||||||
|
}
|
||||||
|
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
final translations = data['translations'] as Map<String, dynamic>;
|
||||||
|
return translations.map((k, v) => MapEntry(k, v.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,4 +19,9 @@ class AppContext with ChangeNotifier {
|
|||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLocale(Locale locale) {
|
||||||
|
_managerContext?.locale = locale;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,9 @@ class Client {
|
|||||||
NotificationApi? _notificationApi;
|
NotificationApi? _notificationApi;
|
||||||
NotificationApi? get notificationApi => _notificationApi;
|
NotificationApi? get notificationApi => _notificationApi;
|
||||||
|
|
||||||
|
SubscriptionPlanApi? _subscriptionPlanApi;
|
||||||
|
SubscriptionPlanApi? get subscriptionPlanApi => _subscriptionPlanApi;
|
||||||
|
|
||||||
Client(String path) {
|
Client(String path) {
|
||||||
_apiClient = ApiClient(basePath: path);
|
_apiClient = ApiClient(basePath: path);
|
||||||
//basePath: "https://192.168.31.140");
|
//basePath: "https://192.168.31.140");
|
||||||
@ -70,5 +73,6 @@ class Client {
|
|||||||
_statsApi = StatsApi(_apiClient);
|
_statsApi = StatsApi(_apiClient);
|
||||||
_apiKeyApi = ApiKeyApi(_apiClient);
|
_apiKeyApi = ApiKeyApi(_apiClient);
|
||||||
_notificationApi = NotificationApi(_apiClient);
|
_notificationApi = NotificationApi(_apiClient);
|
||||||
|
_subscriptionPlanApi = SubscriptionPlanApi(_apiClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
461
lib/l10n/app_en.arb
Normal file
461
lib/l10n/app_en.arb
Normal file
@ -0,0 +1,461 @@
|
|||||||
|
{
|
||||||
|
"@@locale": "en",
|
||||||
|
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"save": "Save",
|
||||||
|
"create": "Create",
|
||||||
|
"delete": "Delete",
|
||||||
|
"close": "Close",
|
||||||
|
"edit": "Edit",
|
||||||
|
"actions": "Actions",
|
||||||
|
"status": "Status",
|
||||||
|
"no": "No",
|
||||||
|
"name": "Name",
|
||||||
|
"type": "Type",
|
||||||
|
"date": "Date",
|
||||||
|
|
||||||
|
"loginSuccess": "Login successful",
|
||||||
|
"loginError": "An error occurred during login",
|
||||||
|
"rememberMe": "Remember me",
|
||||||
|
"connect": "LOG IN",
|
||||||
|
|
||||||
|
"menuApplications": "Applications",
|
||||||
|
"menuConfigurations": "Configurations",
|
||||||
|
"menuResources": "Resources",
|
||||||
|
"menuStatistics": "Statistics",
|
||||||
|
"menuNotifications": "Notifications",
|
||||||
|
"menuUsers": "Users",
|
||||||
|
"menuApiKeys": "API Keys",
|
||||||
|
|
||||||
|
"noPlansAvailable": "No plans available. Create a plan first.",
|
||||||
|
"noPlan": "No plan (unlimited)",
|
||||||
|
"unlimitedStorage": "Unlimited storage",
|
||||||
|
"unlimitedAI": "Unlimited AI",
|
||||||
|
"aiRequestsPerMonth": "{count} AI req/month",
|
||||||
|
"@aiRequestsPerMonth": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storageLabel": "Storage",
|
||||||
|
"aiThisMonthLabel": "AI this month",
|
||||||
|
"unlimited": "Unlimited",
|
||||||
|
"requestsAbbr": "req",
|
||||||
|
"planUpdated": "Plan updated",
|
||||||
|
"errorMessage": "Error: {error}",
|
||||||
|
"@errorMessage": {
|
||||||
|
"placeholders": {
|
||||||
|
"error": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"switchInstance": "Switch instance",
|
||||||
|
"noInstanceFound": "No instance found",
|
||||||
|
"configurePlan": "Configure plan",
|
||||||
|
"tooltipSwitchInstance": "Switch instance",
|
||||||
|
|
||||||
|
"usersTitle": "Users",
|
||||||
|
"createUserBtn": "Create user",
|
||||||
|
"createUserTitle": "Create user",
|
||||||
|
"editUserTitle": "Edit user",
|
||||||
|
"deleteUserTitle": "Delete user",
|
||||||
|
"deleteUserConfirm": "Delete {email}?",
|
||||||
|
"@deleteUserConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"email": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"noUsers": "No users",
|
||||||
|
"email": "Email",
|
||||||
|
"firstName": "First name",
|
||||||
|
"lastName": "Last name",
|
||||||
|
"password": "Password",
|
||||||
|
"role": "Role",
|
||||||
|
"tooltipEdit": "Edit",
|
||||||
|
"tooltipDelete": "Delete",
|
||||||
|
|
||||||
|
"notificationsTitle": "Notifications",
|
||||||
|
"newMessage": "New message",
|
||||||
|
"messageTitle": "Title",
|
||||||
|
"messageBody": "Message",
|
||||||
|
"schedule": "Schedule",
|
||||||
|
"time": "Time",
|
||||||
|
"send": "Send",
|
||||||
|
"cancelNotification": "Cancel notification",
|
||||||
|
"cancelNotificationConfirm": "Cancel « {title} »?",
|
||||||
|
"@cancelNotificationConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"title": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allNotifications": "All",
|
||||||
|
"sentNotifications": "Sent",
|
||||||
|
"scheduledNotifications": "Scheduled",
|
||||||
|
"failedNotifications": "Failed",
|
||||||
|
"noNotifications": "No notifications sent",
|
||||||
|
"noNotificationsForFilter": "No notifications for this filter",
|
||||||
|
"topic": "Topic",
|
||||||
|
"tooltipCancelNotification": "Cancel",
|
||||||
|
"resultsCount": "{count, plural, one{{count} result} other{{count} results}}",
|
||||||
|
"@resultsCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"apiKeysTitle": "API Keys",
|
||||||
|
"createApiKey": "Create API key",
|
||||||
|
"createKeyBtn": "Create key",
|
||||||
|
"appType": "Application type",
|
||||||
|
"noExpiration": "No expiration",
|
||||||
|
"expiresOn": "Expires on {date}",
|
||||||
|
"@expiresOn": {
|
||||||
|
"placeholders": {
|
||||||
|
"date": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"choose": "Choose",
|
||||||
|
"removeExpiration": "Remove expiration",
|
||||||
|
"apiKeyCreatedTitle": "API key created",
|
||||||
|
"copyKeyWarning": "Copy this key now — it won't be shown again.",
|
||||||
|
"copy": "Copy",
|
||||||
|
"copiedKey": "I've copied the key",
|
||||||
|
"revokeApiKeyTitle": "Revoke API key",
|
||||||
|
"revokeApiKeyConfirm": "Revoke « {name} »? Apps using this key will lose access.",
|
||||||
|
"@revokeApiKeyConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"name": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"revoke": "Revoke",
|
||||||
|
"noApiKeys": "No API keys",
|
||||||
|
"createdOn": "Created on",
|
||||||
|
"expiration": "Expiration",
|
||||||
|
"activeKey": "Active",
|
||||||
|
"revokedKey": "Revoked",
|
||||||
|
"tooltipRevoke": "Revoke",
|
||||||
|
|
||||||
|
"statisticsTitle": "Statistics",
|
||||||
|
"statsLoadError": "Unable to load statistics",
|
||||||
|
"statsNoData": "No data yet for this period",
|
||||||
|
"statsNoDataForType": "No events received for type \"{type}\"",
|
||||||
|
"@statsNoDataForType": {
|
||||||
|
"placeholders": {
|
||||||
|
"type": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statsSessions": "Sessions",
|
||||||
|
"statsAvgDuration": "Avg. duration",
|
||||||
|
"statsTopApp": "Top app",
|
||||||
|
"statsTopLang": "Top language",
|
||||||
|
"statsVisitsByDay": "Visits per day",
|
||||||
|
"statsAll": "All",
|
||||||
|
"statsTopSections": "Top sections",
|
||||||
|
"statsApps": "Apps",
|
||||||
|
"statsLanguages": "Languages",
|
||||||
|
"statsTopPOI": "Top POI",
|
||||||
|
"statsPOI": "POI",
|
||||||
|
"statsTaps": "Taps",
|
||||||
|
"statsTopAgenda": "Top agenda events",
|
||||||
|
"statsEvent": "Event",
|
||||||
|
"statsQuiz": "Quiz",
|
||||||
|
"statsSection": "Section",
|
||||||
|
"statsAvgScore": "Avg. score",
|
||||||
|
"statsCompletions": "Completions",
|
||||||
|
"statsGames": "Games",
|
||||||
|
"statsGameType": "Type",
|
||||||
|
"statsArticles": "Articles read",
|
||||||
|
"statsReadings": "Reads",
|
||||||
|
"statsMenuTitle": "Menu",
|
||||||
|
"statsMenuItem": "Item",
|
||||||
|
"statsQrScans": "QR Scans",
|
||||||
|
"statsTotal": "Total",
|
||||||
|
"statsValid": "Valid",
|
||||||
|
"statsInvalid": "Invalid",
|
||||||
|
"statsViews": "Views",
|
||||||
|
|
||||||
|
"noData": "No data",
|
||||||
|
"errorOccurred": "An error occurred",
|
||||||
|
"yes": "Yes",
|
||||||
|
|
||||||
|
"newConfiguration": "New configuration",
|
||||||
|
"configNameLabel": "Name:",
|
||||||
|
"orText": "or",
|
||||||
|
"importLabel": "Import",
|
||||||
|
"configNameRequired": "Please specify a name for the new visit",
|
||||||
|
"configCreatedSuccess": "Configuration created successfully",
|
||||||
|
"configExportSuccess": "Configuration exported successfully, file is at: {path}",
|
||||||
|
"@configExportSuccess": {
|
||||||
|
"placeholders": {
|
||||||
|
"path": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"configExportFailed": "Configuration export failed",
|
||||||
|
"configDeletedSuccess": "Configuration deleted successfully",
|
||||||
|
"configSavedSuccess": "Configuration saved successfully",
|
||||||
|
"configDeleteConfirm": "Are you sure you want to delete this configuration?",
|
||||||
|
|
||||||
|
"newSection": "New section",
|
||||||
|
"newSubSection": "New sub section",
|
||||||
|
"sectionNameLabel": "Name:",
|
||||||
|
"sectionTypeLabel": "Type:",
|
||||||
|
"sectionNameRequired": "Please specify a name for the new section",
|
||||||
|
"sectionCreatedSuccess": "Section created successfully!",
|
||||||
|
"sectionDeleteConfirm": "Are you sure you want to delete this section?",
|
||||||
|
"sectionSavedSuccess": "Section saved successfully",
|
||||||
|
"sectionTranslationSaved": "Section translations saved successfully",
|
||||||
|
"sectionLoadError": "An error occurred while loading the section",
|
||||||
|
"qrCodeCopied": "This QR code has been copied to the clipboard",
|
||||||
|
"beaconLabel": "Beacon:",
|
||||||
|
"beaconIdLabel": "Beacon ID:",
|
||||||
|
"beaconMustBeNumber": "This must be a number",
|
||||||
|
"identifierLabel": "Identifier:",
|
||||||
|
"displayTitleLabel": "Display title:",
|
||||||
|
"imageLabel": "Image:",
|
||||||
|
"backgroundImageLabel": "Background image:",
|
||||||
|
"questionInputLabel": "Question:",
|
||||||
|
"videoUrlLabel": "Video URL:",
|
||||||
|
"webUrlLabel": "Website URL:",
|
||||||
|
|
||||||
|
"subSectionUpdatedSuccess": "Sub section updated successfully",
|
||||||
|
"subSectionUpdateError": "An error occurred while updating the sub section",
|
||||||
|
"subSectionDeletedSuccess": "Sub section deleted successfully",
|
||||||
|
"subSectionDeleteError": "An error occurred while deleting the sub section",
|
||||||
|
"subSectionOrderUpdatedSuccess": "Sub section order updated successfully",
|
||||||
|
"subSectionOrderUpdateError": "An error occurred while updating the sub section order",
|
||||||
|
"subSectionCreatedSuccess": "Sub section created successfully",
|
||||||
|
"subSectionCreateError": "An error occurred while creating the sub section",
|
||||||
|
|
||||||
|
"questionsLabel": "Questions",
|
||||||
|
"questionLabel": "Question",
|
||||||
|
"editQuestion": "Edit question",
|
||||||
|
"questionDeleteConfirm": "Are you sure you want to delete this question?",
|
||||||
|
"questionsLoadError": "An error occurred while loading the questions",
|
||||||
|
"quizBadScore": "Bad score",
|
||||||
|
"quizMediumScore": "Medium score",
|
||||||
|
"quizGoodScore": "Good score",
|
||||||
|
"quizExcellentScore": "Excellent score",
|
||||||
|
"quizBadScoreMsg": "Message for a bad score",
|
||||||
|
"quizMediumScoreMsg": "Message for a medium score",
|
||||||
|
"quizGoodScoreMsg": "Message for a good score",
|
||||||
|
"quizExcellentScoreMsg": "Message for an excellent score",
|
||||||
|
"questionOrderUpdatedSuccess": "Question order updated successfully",
|
||||||
|
"questionOrderUpdateError": "An error occurred while updating the question order",
|
||||||
|
"questionCreatedSuccess": "Question created successfully",
|
||||||
|
"questionCreateError": "An error occurred while creating the question",
|
||||||
|
"questionUpdatedSuccess": "Question updated successfully",
|
||||||
|
"questionUpdateError": "An error occurred while updating the question",
|
||||||
|
"questionDeletedSuccess": "Question deleted successfully",
|
||||||
|
"questionDeleteError": "An error occurred while deleting the question",
|
||||||
|
"translationIncomplete": "Translation is incomplete",
|
||||||
|
|
||||||
|
"geopointCreatedSuccess": "Point created successfully",
|
||||||
|
"geopointCreateError": "An error occurred while creating the point",
|
||||||
|
"geopointUpdatedSuccess": "Point updated successfully",
|
||||||
|
"geopointUpdateError": "An error occurred while updating the point",
|
||||||
|
"geopointDeletedSuccess": "Point deleted successfully",
|
||||||
|
"geopointDeleteError": "An error occurred while deleting the point",
|
||||||
|
"categoryCreatedSuccess": "Category created successfully",
|
||||||
|
"categoryCreateError": "An error occurred while creating the category",
|
||||||
|
"categoryUpdatedSuccess": "Category updated successfully",
|
||||||
|
"categoryUpdateError": "An error occurred while updating the category",
|
||||||
|
|
||||||
|
"eventCreatedSuccess": "Event created successfully",
|
||||||
|
"eventCreateError": "An error occurred while creating the event",
|
||||||
|
"eventUpdatedSuccess": "Event updated successfully",
|
||||||
|
"eventUpdateError": "An error occurred while updating the event",
|
||||||
|
"eventDeletedSuccess": "Event deleted successfully",
|
||||||
|
"eventDeleteError": "An error occurred while deleting the event",
|
||||||
|
"annotationCreatedSuccess": "Annotation created successfully",
|
||||||
|
"annotationCreateError": "An error occurred while creating the annotation",
|
||||||
|
"annotationUpdatedSuccess": "Annotation updated successfully",
|
||||||
|
"annotationUpdateError": "An error occurred while updating the annotation",
|
||||||
|
"programmeBlockCreatedSuccess": "Block created successfully",
|
||||||
|
"programmeBlockCreateError": "An error occurred while creating the block",
|
||||||
|
"programmeBlockUpdatedSuccess": "Block updated successfully",
|
||||||
|
"programmeBlockUpdateError": "An error occurred while updating the block",
|
||||||
|
|
||||||
|
"pathCreatedSuccess": "Path created successfully",
|
||||||
|
"pathCreateError": "An error occurred while creating the path",
|
||||||
|
"pathUpdatedSuccess": "Path updated successfully",
|
||||||
|
"pathUpdateError": "An error occurred while updating the path",
|
||||||
|
"stepCreatedSuccess": "Step created successfully",
|
||||||
|
"stepCreateError": "An error occurred while creating the step",
|
||||||
|
"stepUpdatedSuccess": "Step updated successfully",
|
||||||
|
"stepUpdateError": "An error occurred while updating the step",
|
||||||
|
|
||||||
|
"agendaEventsLabel": "Events",
|
||||||
|
"agendaEventFallback": "Event",
|
||||||
|
"addEvent": "Add an event",
|
||||||
|
"noEvents": "No events",
|
||||||
|
"noAddress": "No address",
|
||||||
|
"onlineLabel": "Online:",
|
||||||
|
"mapViewLabel": "Map view:",
|
||||||
|
"mapServiceLabel": "Map service:",
|
||||||
|
"jsonFilesLabel": "JSON files:",
|
||||||
|
"jsonLabel": "JSON",
|
||||||
|
|
||||||
|
"guidedPathsLabel": "Guided Paths",
|
||||||
|
"addPath": "Add a path",
|
||||||
|
"noPathConfigured": "No path configured",
|
||||||
|
"pathOrderUpdateError": "Error updating order",
|
||||||
|
"pathNoTitle": "Untitled path",
|
||||||
|
"pathDeletedSuccess": "Path deleted successfully",
|
||||||
|
"pathDeleteError": "Error deleting path",
|
||||||
|
"pathsLabel": "Paths",
|
||||||
|
|
||||||
|
"pointsOfInterestLabel": "Points of Interest",
|
||||||
|
"geopointsLabel": "Geographic points",
|
||||||
|
"searchLabel": "Search:",
|
||||||
|
"geopointsLoadError": "Error loading geographic points",
|
||||||
|
"geopointDeleteConfirm": "Are you sure you want to delete this geographic point?",
|
||||||
|
"serviceLabel": "Service:",
|
||||||
|
"centerPointLabel": "Center point:",
|
||||||
|
"iconLabel": "Icon:",
|
||||||
|
"listViewLabel": "List view:",
|
||||||
|
"typeLabel": "Type:",
|
||||||
|
"zoomLabel": "Zoom:",
|
||||||
|
"categoriesLabel": "Categories:",
|
||||||
|
|
||||||
|
"startDateLabel": "Start date",
|
||||||
|
"notDefined": "Not defined",
|
||||||
|
"endDateLabel": "End date",
|
||||||
|
"programmeLabel": "Programme",
|
||||||
|
"addBlock": "Add a block",
|
||||||
|
"blockFallback": "Block",
|
||||||
|
"noBlocks": "No programme blocks defined",
|
||||||
|
"programmeBlockDeletedSuccess": "Block deleted successfully",
|
||||||
|
"programmeBlockDeleteError": "Error deleting block",
|
||||||
|
"baseMapLabel": "Base map",
|
||||||
|
"mapLabel": "Map:",
|
||||||
|
"globalAnnotationsLabel": "Global annotations",
|
||||||
|
"addAnnotation": "Add an annotation",
|
||||||
|
"noAnnotations": "No global annotations",
|
||||||
|
"annotationFallback": "Annotation",
|
||||||
|
"annotationDeletedSuccess": "Annotation deleted",
|
||||||
|
"annotationDeleteError": "Error deleting",
|
||||||
|
|
||||||
|
"agendaEventCreatedSuccess": "Event created successfully",
|
||||||
|
"agendaEventCreateError": "An error occurred while creating the event",
|
||||||
|
"agendaEventUpdatedSuccess": "Event updated successfully",
|
||||||
|
"agendaEventUpdateError": "An error occurred while updating the event",
|
||||||
|
"agendaEventDeletedSuccess": "Event deleted successfully",
|
||||||
|
"agendaEventDeleteError": "An error occurred while deleting the event",
|
||||||
|
|
||||||
|
"newResource": "New resource",
|
||||||
|
"resourceCreatedSuccess": "Resource created successfully",
|
||||||
|
"resourceCreateError": "An error occurred while creating the resource",
|
||||||
|
"resourceUpdatedSuccess": "Resource updated successfully",
|
||||||
|
"resourceNoFileLoaded": "No file has been loaded",
|
||||||
|
"resourceNameRequired": "Please give the resource a name",
|
||||||
|
"resourceTooLarge": "Error: resource size must be under 1.5MB",
|
||||||
|
"resourceInvalidUrl": "The URL is invalid",
|
||||||
|
"resourceUrlRequired": "Please fill in the URL field",
|
||||||
|
|
||||||
|
"generalInfo": "General information",
|
||||||
|
"mainImageLabel": "Main image:",
|
||||||
|
"loaderLabel": "Loader:",
|
||||||
|
"primaryColorLabel": "Primary color:",
|
||||||
|
"secondaryColorLabel": "Secondary color:",
|
||||||
|
"layoutLabel": "Layout:",
|
||||||
|
"layoutGrid": "Grid",
|
||||||
|
"languagesLabel": "Languages:",
|
||||||
|
"featuredEventLabel": "Featured event:",
|
||||||
|
"chooseEvent": "Choose an event",
|
||||||
|
"noneOption": "None",
|
||||||
|
"aiAssistantLabel": "AI assistant:",
|
||||||
|
"appUpdatedSuccess": "Mobile application updated",
|
||||||
|
"configActivatedSuccess": "Configuration activated successfully",
|
||||||
|
"configDeactivatedSuccess": "Configuration deactivated successfully",
|
||||||
|
"configRemoveConfirm": "Are you sure you want to remove this configuration from the application?",
|
||||||
|
"configRemovedSuccess": "Configuration removed from application successfully",
|
||||||
|
"configRemoveError": "An error occurred while removing the configuration",
|
||||||
|
"phoneConfigTitle": "Configurations per device",
|
||||||
|
"addConfig": "Add a configuration",
|
||||||
|
"selectConfigToAdd": "Select a configuration to add",
|
||||||
|
"noItems": "No items to display",
|
||||||
|
"add": "Add",
|
||||||
|
|
||||||
|
"pinCode": "Pin code: {code}",
|
||||||
|
"@pinCode": {
|
||||||
|
"placeholders": {
|
||||||
|
"code": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tablets": "Tablets",
|
||||||
|
|
||||||
|
"stepsCount": "{count} steps",
|
||||||
|
"@stepsCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"displayedDescriptionLabel": "Displayed description:",
|
||||||
|
"displayedContentLabel": "Displayed content:",
|
||||||
|
"displayedNameLabel": "Display name:",
|
||||||
|
"startTimeLabel": "Start time",
|
||||||
|
"noAnnotationConfigured": "No annotations configured.",
|
||||||
|
"newStepTitle": "New step",
|
||||||
|
"editStepTitle": "Edit step",
|
||||||
|
"stepTitleLabel": "Step title",
|
||||||
|
"stepDescriptionLabel": "Step description",
|
||||||
|
"stepLocationLabel": "Step location:",
|
||||||
|
"initiallyHiddenLabel": "Initially hidden",
|
||||||
|
"lockedLabel": "Locked",
|
||||||
|
"durationSecondsLabel": "Duration (seconds):",
|
||||||
|
"triggerGeopointLabel": "Trigger GeoPoint (ID):",
|
||||||
|
"questionsChallengesLabel": "Questions / Challenges",
|
||||||
|
"noQuestionsConfigured": "No questions configured.",
|
||||||
|
"newAgendaEventTitle": "New event",
|
||||||
|
"editAgendaEventTitle": "Edit event",
|
||||||
|
"eventTitleLabel": "Event title",
|
||||||
|
"eventDescriptionLabel": "Event description",
|
||||||
|
"startDateColonLabel": "Start date:",
|
||||||
|
"videoResourceLabel": "Video:",
|
||||||
|
"directVideoLinkLabel": "Direct video link:",
|
||||||
|
"phoneLabel": "Phone:",
|
||||||
|
"locationGeometryLabel": "Location / Geometry",
|
||||||
|
"geometryLabel": "Geometry:",
|
||||||
|
"materialIconLabel": "Icon (material):",
|
||||||
|
"linearLabel": "Linear:",
|
||||||
|
"requiredSuccessLabel": "Required success:",
|
||||||
|
"pathStepsLabel": "Path steps",
|
||||||
|
"noStepConfigured": "No point/step configured.",
|
||||||
|
"stepFallback": "Step",
|
||||||
|
"questionAskedLabel": "Question asked:",
|
||||||
|
"questionTitleLabel": "Question title",
|
||||||
|
"expectedAnswerLabel": "Expected answer:",
|
||||||
|
"expectedAnswerModalLabel": "Expected answer",
|
||||||
|
"validationNote": "Validation is done by comparison (case-insensitive).",
|
||||||
|
"possibleAnswersLabel": "Possible answers:",
|
||||||
|
"noAnswerDefined": "No answer defined. Add at least one.",
|
||||||
|
"correctAnswer": "Correct answer ✓",
|
||||||
|
"wrongAnswer": "Wrong answer",
|
||||||
|
"answerNote": "✓ = correct answer. Multiple can be correct.",
|
||||||
|
"geopointZoneTitle": "Geographic point / Zone",
|
||||||
|
"geometryTypeLabel": "Geometry (Point/Line/Zone):",
|
||||||
|
"phoneModalLabel": "Phone",
|
||||||
|
"categoryLabel": "Category:",
|
||||||
|
"startMessageLabel": "Start message:",
|
||||||
|
"startMessageModalLabel": "Start message",
|
||||||
|
"createCategoryTitle": "Create category",
|
||||||
|
"editCategoryTitle": "Edit category",
|
||||||
|
"categoryIconLabel": "Category icon:",
|
||||||
|
"selectResource": "Select a resource",
|
||||||
|
"createPdfTitle": "Create PDF",
|
||||||
|
"answersLabel": "Answers",
|
||||||
|
"answerLabel": "Answer",
|
||||||
|
"createAnswerTitle": "Create answer",
|
||||||
|
"editAnswerTitle": "Edit answer",
|
||||||
|
"answerValidNote": "If checked, the answer is valid",
|
||||||
|
"selectConfiguration": "Select a configuration",
|
||||||
|
"noConfigFound": "No configuration found",
|
||||||
|
"backgroundColorLabel": "Background color:",
|
||||||
|
"updateTabletBtn": "Update tablet",
|
||||||
|
"kioskUpdatedSuccess": "Kiosk updated",
|
||||||
|
"webViewError": "The web page cannot be displayed, the URL is incorrect or empty",
|
||||||
|
"download": "Download",
|
||||||
|
"resourceDeleteConfirm": "Are you sure you want to delete this resource?",
|
||||||
|
"categoriesTitle": "Categories",
|
||||||
|
"endTimeLabel": "End time",
|
||||||
|
"annotationsLabel": "Annotations"
|
||||||
|
}
|
||||||
461
lib/l10n/app_fr.arb
Normal file
461
lib/l10n/app_fr.arb
Normal file
@ -0,0 +1,461 @@
|
|||||||
|
{
|
||||||
|
"@@locale": "fr",
|
||||||
|
|
||||||
|
"cancel": "Annuler",
|
||||||
|
"save": "Enregistrer",
|
||||||
|
"create": "Créer",
|
||||||
|
"delete": "Supprimer",
|
||||||
|
"close": "Fermer",
|
||||||
|
"edit": "Modifier",
|
||||||
|
"actions": "Actions",
|
||||||
|
"status": "Statut",
|
||||||
|
"no": "Non",
|
||||||
|
"name": "Nom",
|
||||||
|
"type": "Type",
|
||||||
|
"date": "Date",
|
||||||
|
|
||||||
|
"loginSuccess": "Connexion réussie",
|
||||||
|
"loginError": "Un problème est survenu lors de la connexion",
|
||||||
|
"rememberMe": "Se souvenir de moi",
|
||||||
|
"connect": "SE CONNECTER",
|
||||||
|
|
||||||
|
"menuApplications": "Applications",
|
||||||
|
"menuConfigurations": "Configurations",
|
||||||
|
"menuResources": "Ressources",
|
||||||
|
"menuStatistics": "Statistiques",
|
||||||
|
"menuNotifications": "Notifications",
|
||||||
|
"menuUsers": "Utilisateurs",
|
||||||
|
"menuApiKeys": "Clés API",
|
||||||
|
|
||||||
|
"noPlansAvailable": "Aucun plan disponible. Créez d'abord un plan.",
|
||||||
|
"noPlan": "Aucun plan (illimité)",
|
||||||
|
"unlimitedStorage": "Stockage illimité",
|
||||||
|
"unlimitedAI": "IA illimitée",
|
||||||
|
"aiRequestsPerMonth": "{count} req IA/mois",
|
||||||
|
"@aiRequestsPerMonth": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storageLabel": "Stockage",
|
||||||
|
"aiThisMonthLabel": "IA ce mois",
|
||||||
|
"unlimited": "Illimité",
|
||||||
|
"requestsAbbr": "req",
|
||||||
|
"planUpdated": "Plan mis à jour",
|
||||||
|
"errorMessage": "Erreur : {error}",
|
||||||
|
"@errorMessage": {
|
||||||
|
"placeholders": {
|
||||||
|
"error": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"switchInstance": "Changer d'instance",
|
||||||
|
"noInstanceFound": "Aucune instance trouvée",
|
||||||
|
"configurePlan": "Configurer le plan",
|
||||||
|
"tooltipSwitchInstance": "Changer d'instance",
|
||||||
|
|
||||||
|
"usersTitle": "Utilisateurs",
|
||||||
|
"createUserBtn": "Créer un utilisateur",
|
||||||
|
"createUserTitle": "Créer un utilisateur",
|
||||||
|
"editUserTitle": "Modifier l'utilisateur",
|
||||||
|
"deleteUserTitle": "Supprimer l'utilisateur",
|
||||||
|
"deleteUserConfirm": "Supprimer {email} ?",
|
||||||
|
"@deleteUserConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"email": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"noUsers": "Aucun utilisateur",
|
||||||
|
"email": "Email",
|
||||||
|
"firstName": "Prénom",
|
||||||
|
"lastName": "Nom",
|
||||||
|
"password": "Mot de passe",
|
||||||
|
"role": "Rôle",
|
||||||
|
"tooltipEdit": "Modifier",
|
||||||
|
"tooltipDelete": "Supprimer",
|
||||||
|
|
||||||
|
"notificationsTitle": "Notifications",
|
||||||
|
"newMessage": "Nouveau message",
|
||||||
|
"messageTitle": "Titre",
|
||||||
|
"messageBody": "Message",
|
||||||
|
"schedule": "Planifier",
|
||||||
|
"time": "Heure",
|
||||||
|
"send": "Envoyer",
|
||||||
|
"cancelNotification": "Annuler la notification",
|
||||||
|
"cancelNotificationConfirm": "Annuler « {title} » ?",
|
||||||
|
"@cancelNotificationConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"title": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allNotifications": "Toutes",
|
||||||
|
"sentNotifications": "Envoyées",
|
||||||
|
"scheduledNotifications": "Planifiées",
|
||||||
|
"failedNotifications": "Échouées",
|
||||||
|
"noNotifications": "Aucune notification envoyée",
|
||||||
|
"noNotificationsForFilter": "Aucune notification pour ce filtre",
|
||||||
|
"topic": "Topic",
|
||||||
|
"tooltipCancelNotification": "Annuler",
|
||||||
|
"resultsCount": "{count, plural, one{{count} résultat} other{{count} résultats}}",
|
||||||
|
"@resultsCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"apiKeysTitle": "Clés API",
|
||||||
|
"createApiKey": "Créer une clé API",
|
||||||
|
"createKeyBtn": "Créer une clé",
|
||||||
|
"appType": "Type d'application",
|
||||||
|
"noExpiration": "Pas d'expiration",
|
||||||
|
"expiresOn": "Expire le {date}",
|
||||||
|
"@expiresOn": {
|
||||||
|
"placeholders": {
|
||||||
|
"date": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"choose": "Choisir",
|
||||||
|
"removeExpiration": "Supprimer l'expiration",
|
||||||
|
"apiKeyCreatedTitle": "Clé API créée",
|
||||||
|
"copyKeyWarning": "Copiez cette clé maintenant — elle ne sera plus affichée.",
|
||||||
|
"copy": "Copier",
|
||||||
|
"copiedKey": "J'ai copié la clé",
|
||||||
|
"revokeApiKeyTitle": "Révoquer la clé API",
|
||||||
|
"revokeApiKeyConfirm": "Révoquer « {name} » ? Les apps utilisant cette clé perdront l'accès.",
|
||||||
|
"@revokeApiKeyConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"name": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"revoke": "Révoquer",
|
||||||
|
"noApiKeys": "Aucune clé API",
|
||||||
|
"createdOn": "Créée le",
|
||||||
|
"expiration": "Expiration",
|
||||||
|
"activeKey": "Active",
|
||||||
|
"revokedKey": "Révoquée",
|
||||||
|
"tooltipRevoke": "Révoquer",
|
||||||
|
|
||||||
|
"statisticsTitle": "Statistiques",
|
||||||
|
"statsLoadError": "Impossible de charger les statistiques",
|
||||||
|
"statsNoData": "Pas encore de données pour cette période",
|
||||||
|
"statsNoDataForType": "Aucun event reçu pour le type \"{type}\"",
|
||||||
|
"@statsNoDataForType": {
|
||||||
|
"placeholders": {
|
||||||
|
"type": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statsSessions": "Sessions",
|
||||||
|
"statsAvgDuration": "Durée moy.",
|
||||||
|
"statsTopApp": "App top",
|
||||||
|
"statsTopLang": "Langue top",
|
||||||
|
"statsVisitsByDay": "Visites par jour",
|
||||||
|
"statsAll": "Tous",
|
||||||
|
"statsTopSections": "Top sections",
|
||||||
|
"statsApps": "Apps",
|
||||||
|
"statsLanguages": "Langues",
|
||||||
|
"statsTopPOI": "Top POI",
|
||||||
|
"statsPOI": "POI",
|
||||||
|
"statsTaps": "Taps",
|
||||||
|
"statsTopAgenda": "Top événements agenda",
|
||||||
|
"statsEvent": "Événement",
|
||||||
|
"statsQuiz": "Quiz",
|
||||||
|
"statsSection": "Section",
|
||||||
|
"statsAvgScore": "Score moy",
|
||||||
|
"statsCompletions": "Complétions",
|
||||||
|
"statsGames": "Jeux",
|
||||||
|
"statsGameType": "Type",
|
||||||
|
"statsArticles": "Articles lus",
|
||||||
|
"statsReadings": "Lectures",
|
||||||
|
"statsMenuTitle": "Menu",
|
||||||
|
"statsMenuItem": "Item",
|
||||||
|
"statsQrScans": "QR Scans",
|
||||||
|
"statsTotal": "Total",
|
||||||
|
"statsValid": "Valides",
|
||||||
|
"statsInvalid": "Invalides",
|
||||||
|
"statsViews": "Vues",
|
||||||
|
|
||||||
|
"noData": "Aucune donnée",
|
||||||
|
"errorOccurred": "Une erreur est survenue",
|
||||||
|
"yes": "Oui",
|
||||||
|
|
||||||
|
"newConfiguration": "Nouvelle configuration",
|
||||||
|
"configNameLabel": "Nom :",
|
||||||
|
"orText": "ou",
|
||||||
|
"importLabel": "Importer",
|
||||||
|
"configNameRequired": "Veuillez spécifier un nom pour la nouvelle visite",
|
||||||
|
"configCreatedSuccess": "La configuration a été créée avec succès",
|
||||||
|
"configExportSuccess": "L'export de la configuration a réussi, le document se trouve à cet endroit : {path}",
|
||||||
|
"@configExportSuccess": {
|
||||||
|
"placeholders": {
|
||||||
|
"path": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"configExportFailed": "L'export de la configuration a échoué",
|
||||||
|
"configDeletedSuccess": "La configuration a été supprimée avec succès",
|
||||||
|
"configSavedSuccess": "La configuration a été sauvegardée avec succès",
|
||||||
|
"configDeleteConfirm": "Êtes-vous sûr de vouloir supprimer cette configuration ?",
|
||||||
|
|
||||||
|
"newSection": "Nouvelle section",
|
||||||
|
"newSubSection": "Nouvelle sous section",
|
||||||
|
"sectionNameLabel": "Nom :",
|
||||||
|
"sectionTypeLabel": "Type:",
|
||||||
|
"sectionNameRequired": "Veuillez spécifier un nom pour la nouvelle section",
|
||||||
|
"sectionCreatedSuccess": "La section a été créée avec succès !",
|
||||||
|
"sectionDeleteConfirm": "Êtes-vous sûr de vouloir supprimer cette section ?",
|
||||||
|
"sectionSavedSuccess": "La section a été sauvegardée avec succès",
|
||||||
|
"sectionTranslationSaved": "Les traductions de la section ont été sauvegardées avec succès",
|
||||||
|
"sectionLoadError": "Une erreur est survenue lors de la récupération de la section",
|
||||||
|
"qrCodeCopied": "Ce QR code a été copié dans le presse papier",
|
||||||
|
"beaconLabel": "Beacon :",
|
||||||
|
"beaconIdLabel": "Identifiant Beacon :",
|
||||||
|
"beaconMustBeNumber": "Cela doit être un chiffre",
|
||||||
|
"identifierLabel": "Identifiant :",
|
||||||
|
"displayTitleLabel": "Titre affiché:",
|
||||||
|
"imageLabel": "Image :",
|
||||||
|
"backgroundImageLabel": "Image fond d'écran :",
|
||||||
|
"questionInputLabel": "Question :",
|
||||||
|
"videoUrlLabel": "Url de la vidéo:",
|
||||||
|
"webUrlLabel": "Url du site web:",
|
||||||
|
|
||||||
|
"subSectionUpdatedSuccess": "La sous section a été mis à jour avec succès",
|
||||||
|
"subSectionUpdateError": "Une erreur est survenue lors de la mise à jour de la sous section",
|
||||||
|
"subSectionDeletedSuccess": "La sous section a été supprimée avec succès",
|
||||||
|
"subSectionDeleteError": "Une erreur est survenue lors de la suppression de la sous section",
|
||||||
|
"subSectionOrderUpdatedSuccess": "L'ordre des sous sections a été mis à jour avec succès",
|
||||||
|
"subSectionOrderUpdateError": "Une erreur est survenue lors de la mise à jour de l'ordre des sous sections",
|
||||||
|
"subSectionCreatedSuccess": "La sous section a été créée avec succès",
|
||||||
|
"subSectionCreateError": "Une erreur est survenue lors de la création de la sous section",
|
||||||
|
|
||||||
|
"questionsLabel": "Questions",
|
||||||
|
"questionLabel": "Question",
|
||||||
|
"editQuestion": "Modifier la question",
|
||||||
|
"questionDeleteConfirm": "Êtes-vous sûr de vouloir supprimer cette question ?",
|
||||||
|
"questionsLoadError": "Une erreur est survenue lors de la récupération des questions",
|
||||||
|
"quizBadScore": "Mauvais score",
|
||||||
|
"quizMediumScore": "Moyen score",
|
||||||
|
"quizGoodScore": "Bon score",
|
||||||
|
"quizExcellentScore": "Excellent score",
|
||||||
|
"quizBadScoreMsg": "Message pour un mauvais score",
|
||||||
|
"quizMediumScoreMsg": "Message pour un score moyen",
|
||||||
|
"quizGoodScoreMsg": "Message pour un bon score",
|
||||||
|
"quizExcellentScoreMsg": "Message pour un excellent score",
|
||||||
|
"questionOrderUpdatedSuccess": "L'ordre des questions a été mis à jour avec succès",
|
||||||
|
"questionOrderUpdateError": "Une erreur est survenue lors de la mise à jour de l'ordre des questions",
|
||||||
|
"questionCreatedSuccess": "La question a été créée avec succès",
|
||||||
|
"questionCreateError": "Une erreur est survenue lors de la création de la question",
|
||||||
|
"questionUpdatedSuccess": "La question a été mis à jour avec succès",
|
||||||
|
"questionUpdateError": "Une erreur est survenue lors de la mise à jour de la question",
|
||||||
|
"questionDeletedSuccess": "La question a été supprimée avec succès",
|
||||||
|
"questionDeleteError": "Une erreur est survenue lors de la suppression de la question",
|
||||||
|
"translationIncomplete": "La traduction n'est pas complète",
|
||||||
|
|
||||||
|
"geopointCreatedSuccess": "Le point a été créé avec succès",
|
||||||
|
"geopointCreateError": "Une erreur est survenue lors de la création du point",
|
||||||
|
"geopointUpdatedSuccess": "Le point a été mis à jour avec succès",
|
||||||
|
"geopointUpdateError": "Une erreur est survenue lors de la mise à jour du point",
|
||||||
|
"geopointDeletedSuccess": "Le point a été supprimé avec succès",
|
||||||
|
"geopointDeleteError": "Une erreur est survenue lors de la suppression du point",
|
||||||
|
"categoryCreatedSuccess": "La catégorie a été créée avec succès",
|
||||||
|
"categoryCreateError": "Une erreur est survenue lors de la création de la catégorie",
|
||||||
|
"categoryUpdatedSuccess": "La catégorie a été mise à jour avec succès",
|
||||||
|
"categoryUpdateError": "Une erreur est survenue lors de la mise à jour de la catégorie",
|
||||||
|
|
||||||
|
"eventCreatedSuccess": "L'événement a été créé avec succès",
|
||||||
|
"eventCreateError": "Une erreur est survenue lors de la création de l'événement",
|
||||||
|
"eventUpdatedSuccess": "L'événement a été mis à jour avec succès",
|
||||||
|
"eventUpdateError": "Une erreur est survenue lors de la mise à jour de l'événement",
|
||||||
|
"eventDeletedSuccess": "L'événement a été supprimé avec succès",
|
||||||
|
"eventDeleteError": "Une erreur est survenue lors de la suppression de l'événement",
|
||||||
|
"annotationCreatedSuccess": "L'annotation a été créée avec succès",
|
||||||
|
"annotationCreateError": "Une erreur est survenue lors de la création de l'annotation",
|
||||||
|
"annotationUpdatedSuccess": "L'annotation a été mise à jour avec succès",
|
||||||
|
"annotationUpdateError": "Une erreur est survenue lors de la mise à jour de l'annotation",
|
||||||
|
"programmeBlockCreatedSuccess": "Le bloc a été créé avec succès",
|
||||||
|
"programmeBlockCreateError": "Une erreur est survenue lors de la création du bloc",
|
||||||
|
"programmeBlockUpdatedSuccess": "Le bloc a été mis à jour avec succès",
|
||||||
|
"programmeBlockUpdateError": "Une erreur est survenue lors de la mise à jour du bloc",
|
||||||
|
|
||||||
|
"pathCreatedSuccess": "Le parcours a été créé avec succès",
|
||||||
|
"pathCreateError": "Une erreur est survenue lors de la création du parcours",
|
||||||
|
"pathUpdatedSuccess": "Le parcours a été mis à jour avec succès",
|
||||||
|
"pathUpdateError": "Une erreur est survenue lors de la mise à jour du parcours",
|
||||||
|
"stepCreatedSuccess": "L'étape a été créée avec succès",
|
||||||
|
"stepCreateError": "Une erreur est survenue lors de la création de l'étape",
|
||||||
|
"stepUpdatedSuccess": "L'étape a été mise à jour avec succès",
|
||||||
|
"stepUpdateError": "Une erreur est survenue lors de la mise à jour de l'étape",
|
||||||
|
|
||||||
|
"agendaEventsLabel": "Évènements",
|
||||||
|
"agendaEventFallback": "Évènement",
|
||||||
|
"addEvent": "Ajouter un évènement",
|
||||||
|
"noEvents": "Aucun évènement",
|
||||||
|
"noAddress": "Pas d'adresse",
|
||||||
|
"onlineLabel": "En ligne :",
|
||||||
|
"mapViewLabel": "Vue carte :",
|
||||||
|
"mapServiceLabel": "Service carte :",
|
||||||
|
"jsonFilesLabel": "Fichiers json :",
|
||||||
|
"jsonLabel": "JSON",
|
||||||
|
|
||||||
|
"guidedPathsLabel": "Parcours Guidés",
|
||||||
|
"addPath": "Ajouter un parcours",
|
||||||
|
"noPathConfigured": "Aucun parcours configuré",
|
||||||
|
"pathOrderUpdateError": "Erreur lors de la mise à jour de l'ordre",
|
||||||
|
"pathNoTitle": "Parcours sans titre",
|
||||||
|
"pathDeletedSuccess": "Parcours supprimé avec succès",
|
||||||
|
"pathDeleteError": "Erreur lors de la suppression du parcours",
|
||||||
|
"pathsLabel": "Parcours",
|
||||||
|
|
||||||
|
"pointsOfInterestLabel": "Points d'Intérêt",
|
||||||
|
"geopointsLabel": "Points géographiques",
|
||||||
|
"searchLabel": "Recherche :",
|
||||||
|
"geopointsLoadError": "Une erreur est survenue lors de la récupération des points géographiques",
|
||||||
|
"geopointDeleteConfirm": "Êtes-vous sûr de vouloir supprimer ce point géographique ?",
|
||||||
|
"serviceLabel": "Service :",
|
||||||
|
"centerPointLabel": "Point de centrage :",
|
||||||
|
"iconLabel": "Icône :",
|
||||||
|
"listViewLabel": "Vue liste :",
|
||||||
|
"typeLabel": "Type :",
|
||||||
|
"zoomLabel": "Zoom :",
|
||||||
|
"categoriesLabel": "Catégories :",
|
||||||
|
|
||||||
|
"startDateLabel": "Date de début",
|
||||||
|
"notDefined": "Non définie",
|
||||||
|
"endDateLabel": "Date de fin",
|
||||||
|
"programmeLabel": "Programme",
|
||||||
|
"addBlock": "Ajouter un bloc",
|
||||||
|
"blockFallback": "Bloc",
|
||||||
|
"noBlocks": "Aucun bloc de programme défini",
|
||||||
|
"programmeBlockDeletedSuccess": "Bloc supprimé avec succès",
|
||||||
|
"programmeBlockDeleteError": "Erreur lors de la suppression du bloc",
|
||||||
|
"baseMapLabel": "Carte de base",
|
||||||
|
"mapLabel": "Carte :",
|
||||||
|
"globalAnnotationsLabel": "Annotations globales",
|
||||||
|
"addAnnotation": "Ajouter une annotation",
|
||||||
|
"noAnnotations": "Aucune annotation globale",
|
||||||
|
"annotationFallback": "Annotation",
|
||||||
|
"annotationDeletedSuccess": "Annotation supprimée",
|
||||||
|
"annotationDeleteError": "Erreur lors de la suppression",
|
||||||
|
|
||||||
|
"agendaEventCreatedSuccess": "L'événement a été créé avec succès",
|
||||||
|
"agendaEventCreateError": "Une erreur est survenue lors de la création de l'événement",
|
||||||
|
"agendaEventUpdatedSuccess": "L'événement a été mis à jour avec succès",
|
||||||
|
"agendaEventUpdateError": "Une erreur est survenue lors de la mise à jour de l'événement",
|
||||||
|
"agendaEventDeletedSuccess": "L'événement a été supprimé avec succès",
|
||||||
|
"agendaEventDeleteError": "Une erreur est survenue lors de la suppression de l'événement",
|
||||||
|
|
||||||
|
"newResource": "Nouvelle ressource",
|
||||||
|
"resourceCreatedSuccess": "La ressource a été créée avec succès",
|
||||||
|
"resourceCreateError": "Une erreur est survenue lors de la création de la ressource",
|
||||||
|
"resourceUpdatedSuccess": "La ressource a été mise à jour avec succès",
|
||||||
|
"resourceNoFileLoaded": "Aucun fichier n'a été chargé",
|
||||||
|
"resourceNameRequired": "Veuillez donner un nom à la ressource",
|
||||||
|
"resourceTooLarge": "Erreur, attention, la taille de la ressource doit être inférieure à 1.5Mb",
|
||||||
|
"resourceInvalidUrl": "L'url est invalide",
|
||||||
|
"resourceUrlRequired": "Veuillez remplir le champ URL",
|
||||||
|
|
||||||
|
"generalInfo": "Informations générales",
|
||||||
|
"mainImageLabel": "Image principale :",
|
||||||
|
"loaderLabel": "Loader :",
|
||||||
|
"primaryColorLabel": "Couleur principale :",
|
||||||
|
"secondaryColorLabel": "Couleur secondaire :",
|
||||||
|
"layoutLabel": "Affichage :",
|
||||||
|
"layoutGrid": "Grille",
|
||||||
|
"languagesLabel": "Langues :",
|
||||||
|
"featuredEventLabel": "Evènement à l'affiche :",
|
||||||
|
"chooseEvent": "Choisir un évènement",
|
||||||
|
"noneOption": "Aucun",
|
||||||
|
"aiAssistantLabel": "Assistant IA :",
|
||||||
|
"appUpdatedSuccess": "Application mobile mise à jour",
|
||||||
|
"configActivatedSuccess": "Configuration activée avec succès",
|
||||||
|
"configDeactivatedSuccess": "Configuration désactivée avec succès",
|
||||||
|
"configRemoveConfirm": "Êtes-vous sûr de vouloir retirer cette configuration de l'application ?",
|
||||||
|
"configRemovedSuccess": "La configuration a été retirée de l'application avec succès",
|
||||||
|
"configRemoveError": "Une erreur est survenue lors du retrait de la configuration",
|
||||||
|
"phoneConfigTitle": "Configurations par appareil",
|
||||||
|
"addConfig": "Ajouter une configuration",
|
||||||
|
"selectConfigToAdd": "Sélectionner une configuration à ajouter",
|
||||||
|
"noItems": "Aucun élément à afficher",
|
||||||
|
"add": "Ajouter",
|
||||||
|
|
||||||
|
"pinCode": "Code pin: {code}",
|
||||||
|
"@pinCode": {
|
||||||
|
"placeholders": {
|
||||||
|
"code": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tablets": "Tablettes",
|
||||||
|
|
||||||
|
"stepsCount": "{count} étapes",
|
||||||
|
"@stepsCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"displayedDescriptionLabel": "Description affichée:",
|
||||||
|
"displayedContentLabel": "Contenu affiché :",
|
||||||
|
"displayedNameLabel": "Nom affiché :",
|
||||||
|
"startTimeLabel": "Heure de début",
|
||||||
|
"noAnnotationConfigured": "Aucune annotation configurée.",
|
||||||
|
"newStepTitle": "Nouvelle Étape",
|
||||||
|
"editStepTitle": "Modifier l'Étape",
|
||||||
|
"stepTitleLabel": "Titre de l'étape",
|
||||||
|
"stepDescriptionLabel": "Description de l'étape",
|
||||||
|
"stepLocationLabel": "Emplacement de l'étape :",
|
||||||
|
"initiallyHiddenLabel": "Cachée initialement",
|
||||||
|
"lockedLabel": "Verrouillée",
|
||||||
|
"durationSecondsLabel": "Durée (secondes) :",
|
||||||
|
"triggerGeopointLabel": "GeoPoint de déclenchement (ID) :",
|
||||||
|
"questionsChallengesLabel": "Questions / Défis",
|
||||||
|
"noQuestionsConfigured": "Aucune question configurée.",
|
||||||
|
"newAgendaEventTitle": "Nouvel Évènement",
|
||||||
|
"editAgendaEventTitle": "Modifier l'Évènement",
|
||||||
|
"eventTitleLabel": "Titre de l'évènement",
|
||||||
|
"eventDescriptionLabel": "Description de l'évènement",
|
||||||
|
"startDateColonLabel": "Date de début :",
|
||||||
|
"videoResourceLabel": "Vidéo :",
|
||||||
|
"directVideoLinkLabel": "Lien vidéo direct :",
|
||||||
|
"phoneLabel": "Téléphone :",
|
||||||
|
"locationGeometryLabel": "Localisation / Géométrie",
|
||||||
|
"geometryLabel": "Géométrie :",
|
||||||
|
"materialIconLabel": "Icône (material) :",
|
||||||
|
"linearLabel": "Linéaire :",
|
||||||
|
"requiredSuccessLabel": "Réussite requise :",
|
||||||
|
"pathStepsLabel": "Étapes du parcours",
|
||||||
|
"noStepConfigured": "Aucun point/étape configuré.",
|
||||||
|
"stepFallback": "Étape",
|
||||||
|
"questionAskedLabel": "Question posée :",
|
||||||
|
"questionTitleLabel": "Intitulé de la question",
|
||||||
|
"expectedAnswerLabel": "Réponse attendue :",
|
||||||
|
"expectedAnswerModalLabel": "Réponse attendue",
|
||||||
|
"validationNote": "La validation se fait par comparaison (insensible à la casse).",
|
||||||
|
"possibleAnswersLabel": "Réponses possibles :",
|
||||||
|
"noAnswerDefined": "Aucune réponse définie. Ajoutez-en au moins une.",
|
||||||
|
"correctAnswer": "Bonne réponse ✓",
|
||||||
|
"wrongAnswer": "Mauvaise réponse",
|
||||||
|
"answerNote": "✓ = bonne réponse. Plusieurs peuvent être correctes.",
|
||||||
|
"geopointZoneTitle": "Point géographique / Zone",
|
||||||
|
"geometryTypeLabel": "Géométrie (Point/Ligne/Zone) :",
|
||||||
|
"phoneModalLabel": "Téléphone",
|
||||||
|
"categoryLabel": "Catégorie :",
|
||||||
|
"startMessageLabel": "Message départ :",
|
||||||
|
"startMessageModalLabel": "Message départ",
|
||||||
|
"createCategoryTitle": "Création catégorie",
|
||||||
|
"editCategoryTitle": "Modification catégorie",
|
||||||
|
"categoryIconLabel": "Icône catégorie :",
|
||||||
|
"selectResource": "Sélectionner une ressource",
|
||||||
|
"createPdfTitle": "Création PDF",
|
||||||
|
"answersLabel": "Réponses",
|
||||||
|
"answerLabel": "Réponse",
|
||||||
|
"createAnswerTitle": "Créer la réponse",
|
||||||
|
"editAnswerTitle": "Modifier la réponse",
|
||||||
|
"answerValidNote": "Si coché, la réponse est valide",
|
||||||
|
"selectConfiguration": "Sélectionner une configuration",
|
||||||
|
"noConfigFound": "Aucune configuration trouvée",
|
||||||
|
"backgroundColorLabel": "Couleur fond d'écran :",
|
||||||
|
"updateTabletBtn": "Mettre à jour la tablette",
|
||||||
|
"kioskUpdatedSuccess": "Le kiosk a été mis à jour",
|
||||||
|
"webViewError": "La page internet ne peut pas être affichée, l'url est incorrecte ou vide",
|
||||||
|
"download": "Télécharger",
|
||||||
|
"resourceDeleteConfirm": "Êtes-vous sûr de vouloir supprimer cette ressource ?",
|
||||||
|
"categoriesTitle": "Catégories",
|
||||||
|
"endTimeLabel": "Heure de fin",
|
||||||
|
"annotationsLabel": "Annotations"
|
||||||
|
}
|
||||||
2405
lib/l10n/app_localizations.dart
Normal file
2405
lib/l10n/app_localizations.dart
Normal file
File diff suppressed because it is too large
Load Diff
1208
lib/l10n/app_localizations_en.dart
Normal file
1208
lib/l10n/app_localizations_en.dart
Normal file
File diff suppressed because it is too large
Load Diff
1239
lib/l10n/app_localizations_fr.dart
Normal file
1239
lib/l10n/app_localizations_fr.dart
Normal file
File diff suppressed because it is too large
Load Diff
1220
lib/l10n/app_localizations_nl.dart
Normal file
1220
lib/l10n/app_localizations_nl.dart
Normal file
File diff suppressed because it is too large
Load Diff
461
lib/l10n/app_nl.arb
Normal file
461
lib/l10n/app_nl.arb
Normal file
@ -0,0 +1,461 @@
|
|||||||
|
{
|
||||||
|
"@@locale": "nl",
|
||||||
|
|
||||||
|
"cancel": "Annuleren",
|
||||||
|
"save": "Opslaan",
|
||||||
|
"create": "Aanmaken",
|
||||||
|
"delete": "Verwijderen",
|
||||||
|
"close": "Sluiten",
|
||||||
|
"edit": "Bewerken",
|
||||||
|
"actions": "Acties",
|
||||||
|
"status": "Status",
|
||||||
|
"no": "Nee",
|
||||||
|
"name": "Naam",
|
||||||
|
"type": "Type",
|
||||||
|
"date": "Datum",
|
||||||
|
|
||||||
|
"loginSuccess": "Inloggen geslaagd",
|
||||||
|
"loginError": "Er is een probleem opgetreden bij het inloggen",
|
||||||
|
"rememberMe": "Onthoud mij",
|
||||||
|
"connect": "INLOGGEN",
|
||||||
|
|
||||||
|
"menuApplications": "Applicaties",
|
||||||
|
"menuConfigurations": "Configuraties",
|
||||||
|
"menuResources": "Bronnen",
|
||||||
|
"menuStatistics": "Statistieken",
|
||||||
|
"menuNotifications": "Meldingen",
|
||||||
|
"menuUsers": "Gebruikers",
|
||||||
|
"menuApiKeys": "API-sleutels",
|
||||||
|
|
||||||
|
"noPlansAvailable": "Geen plannen beschikbaar. Maak eerst een plan aan.",
|
||||||
|
"noPlan": "Geen plan (onbeperkt)",
|
||||||
|
"unlimitedStorage": "Onbeperkte opslag",
|
||||||
|
"unlimitedAI": "Onbeperkte AI",
|
||||||
|
"aiRequestsPerMonth": "{count} AI-verz./maand",
|
||||||
|
"@aiRequestsPerMonth": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storageLabel": "Opslag",
|
||||||
|
"aiThisMonthLabel": "AI deze maand",
|
||||||
|
"unlimited": "Onbeperkt",
|
||||||
|
"requestsAbbr": "verz.",
|
||||||
|
"planUpdated": "Plan bijgewerkt",
|
||||||
|
"errorMessage": "Fout: {error}",
|
||||||
|
"@errorMessage": {
|
||||||
|
"placeholders": {
|
||||||
|
"error": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"switchInstance": "Instantie wisselen",
|
||||||
|
"noInstanceFound": "Geen instantie gevonden",
|
||||||
|
"configurePlan": "Plan configureren",
|
||||||
|
"tooltipSwitchInstance": "Instantie wisselen",
|
||||||
|
|
||||||
|
"usersTitle": "Gebruikers",
|
||||||
|
"createUserBtn": "Gebruiker aanmaken",
|
||||||
|
"createUserTitle": "Gebruiker aanmaken",
|
||||||
|
"editUserTitle": "Gebruiker bewerken",
|
||||||
|
"deleteUserTitle": "Gebruiker verwijderen",
|
||||||
|
"deleteUserConfirm": "{email} verwijderen?",
|
||||||
|
"@deleteUserConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"email": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"noUsers": "Geen gebruikers",
|
||||||
|
"email": "E-mail",
|
||||||
|
"firstName": "Voornaam",
|
||||||
|
"lastName": "Naam",
|
||||||
|
"password": "Wachtwoord",
|
||||||
|
"role": "Rol",
|
||||||
|
"tooltipEdit": "Bewerken",
|
||||||
|
"tooltipDelete": "Verwijderen",
|
||||||
|
|
||||||
|
"notificationsTitle": "Meldingen",
|
||||||
|
"newMessage": "Nieuw bericht",
|
||||||
|
"messageTitle": "Titel",
|
||||||
|
"messageBody": "Bericht",
|
||||||
|
"schedule": "Plannen",
|
||||||
|
"time": "Tijd",
|
||||||
|
"send": "Versturen",
|
||||||
|
"cancelNotification": "Melding annuleren",
|
||||||
|
"cancelNotificationConfirm": "« {title} » annuleren?",
|
||||||
|
"@cancelNotificationConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"title": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allNotifications": "Alle",
|
||||||
|
"sentNotifications": "Verzonden",
|
||||||
|
"scheduledNotifications": "Gepland",
|
||||||
|
"failedNotifications": "Mislukt",
|
||||||
|
"noNotifications": "Geen meldingen verzonden",
|
||||||
|
"noNotificationsForFilter": "Geen meldingen voor dit filter",
|
||||||
|
"topic": "Onderwerp",
|
||||||
|
"tooltipCancelNotification": "Annuleren",
|
||||||
|
"resultsCount": "{count, plural, one{{count} resultaat} other{{count} resultaten}}",
|
||||||
|
"@resultsCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"apiKeysTitle": "API-sleutels",
|
||||||
|
"createApiKey": "API-sleutel aanmaken",
|
||||||
|
"createKeyBtn": "Sleutel aanmaken",
|
||||||
|
"appType": "Applicatietype",
|
||||||
|
"noExpiration": "Geen vervaldatum",
|
||||||
|
"expiresOn": "Verloopt op {date}",
|
||||||
|
"@expiresOn": {
|
||||||
|
"placeholders": {
|
||||||
|
"date": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"choose": "Kiezen",
|
||||||
|
"removeExpiration": "Vervaldatum verwijderen",
|
||||||
|
"apiKeyCreatedTitle": "API-sleutel aangemaakt",
|
||||||
|
"copyKeyWarning": "Kopieer deze sleutel nu — hij wordt niet meer weergegeven.",
|
||||||
|
"copy": "Kopiëren",
|
||||||
|
"copiedKey": "Ik heb de sleutel gekopieerd",
|
||||||
|
"revokeApiKeyTitle": "API-sleutel intrekken",
|
||||||
|
"revokeApiKeyConfirm": "« {name} » intrekken? Apps die deze sleutel gebruiken verliezen toegang.",
|
||||||
|
"@revokeApiKeyConfirm": {
|
||||||
|
"placeholders": {
|
||||||
|
"name": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"revoke": "Intrekken",
|
||||||
|
"noApiKeys": "Geen API-sleutels",
|
||||||
|
"createdOn": "Aangemaakt op",
|
||||||
|
"expiration": "Vervaldatum",
|
||||||
|
"activeKey": "Actief",
|
||||||
|
"revokedKey": "Ingetrokken",
|
||||||
|
"tooltipRevoke": "Intrekken",
|
||||||
|
|
||||||
|
"statisticsTitle": "Statistieken",
|
||||||
|
"statsLoadError": "Statistieken kunnen niet worden geladen",
|
||||||
|
"statsNoData": "Nog geen gegevens voor deze periode",
|
||||||
|
"statsNoDataForType": "Geen events ontvangen voor type \"{type}\"",
|
||||||
|
"@statsNoDataForType": {
|
||||||
|
"placeholders": {
|
||||||
|
"type": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statsSessions": "Sessies",
|
||||||
|
"statsAvgDuration": "Gem. duur",
|
||||||
|
"statsTopApp": "Top app",
|
||||||
|
"statsTopLang": "Top taal",
|
||||||
|
"statsVisitsByDay": "Bezoeken per dag",
|
||||||
|
"statsAll": "Alle",
|
||||||
|
"statsTopSections": "Top secties",
|
||||||
|
"statsApps": "Apps",
|
||||||
|
"statsLanguages": "Talen",
|
||||||
|
"statsTopPOI": "Top POI",
|
||||||
|
"statsPOI": "POI",
|
||||||
|
"statsTaps": "Taps",
|
||||||
|
"statsTopAgenda": "Top agenda-evenementen",
|
||||||
|
"statsEvent": "Evenement",
|
||||||
|
"statsQuiz": "Quiz",
|
||||||
|
"statsSection": "Sectie",
|
||||||
|
"statsAvgScore": "Gem. score",
|
||||||
|
"statsCompletions": "Voltooiingen",
|
||||||
|
"statsGames": "Spellen",
|
||||||
|
"statsGameType": "Type",
|
||||||
|
"statsArticles": "Gelezen artikelen",
|
||||||
|
"statsReadings": "Lezingen",
|
||||||
|
"statsMenuTitle": "Menu",
|
||||||
|
"statsMenuItem": "Item",
|
||||||
|
"statsQrScans": "QR-scans",
|
||||||
|
"statsTotal": "Totaal",
|
||||||
|
"statsValid": "Geldig",
|
||||||
|
"statsInvalid": "Ongeldig",
|
||||||
|
"statsViews": "Weergaven",
|
||||||
|
|
||||||
|
"noData": "Geen gegevens",
|
||||||
|
"errorOccurred": "Er is een fout opgetreden",
|
||||||
|
"yes": "Ja",
|
||||||
|
|
||||||
|
"newConfiguration": "Nieuwe configuratie",
|
||||||
|
"configNameLabel": "Naam:",
|
||||||
|
"orText": "of",
|
||||||
|
"importLabel": "Importeren",
|
||||||
|
"configNameRequired": "Geef een naam op voor het nieuwe bezoek",
|
||||||
|
"configCreatedSuccess": "Configuratie succesvol aangemaakt",
|
||||||
|
"configExportSuccess": "Configuratie succesvol geëxporteerd, bestand op: {path}",
|
||||||
|
"@configExportSuccess": {
|
||||||
|
"placeholders": {
|
||||||
|
"path": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"configExportFailed": "Export van configuratie mislukt",
|
||||||
|
"configDeletedSuccess": "Configuratie succesvol verwijderd",
|
||||||
|
"configSavedSuccess": "Configuratie succesvol opgeslagen",
|
||||||
|
"configDeleteConfirm": "Weet u zeker dat u deze configuratie wilt verwijderen?",
|
||||||
|
|
||||||
|
"newSection": "Nieuwe sectie",
|
||||||
|
"newSubSection": "Nieuwe subsectie",
|
||||||
|
"sectionNameLabel": "Naam:",
|
||||||
|
"sectionTypeLabel": "Type:",
|
||||||
|
"sectionNameRequired": "Geef een naam op voor de nieuwe sectie",
|
||||||
|
"sectionCreatedSuccess": "Sectie succesvol aangemaakt!",
|
||||||
|
"sectionDeleteConfirm": "Weet u zeker dat u deze sectie wilt verwijderen?",
|
||||||
|
"sectionSavedSuccess": "Sectie succesvol opgeslagen",
|
||||||
|
"sectionTranslationSaved": "Sectievertaling succesvol opgeslagen",
|
||||||
|
"sectionLoadError": "Er is een fout opgetreden bij het laden van de sectie",
|
||||||
|
"qrCodeCopied": "Deze QR-code is naar het klembord gekopieerd",
|
||||||
|
"beaconLabel": "Beacon:",
|
||||||
|
"beaconIdLabel": "Beacon-ID:",
|
||||||
|
"beaconMustBeNumber": "Dit moet een getal zijn",
|
||||||
|
"identifierLabel": "Identificator:",
|
||||||
|
"displayTitleLabel": "Weergegeven titel:",
|
||||||
|
"imageLabel": "Afbeelding:",
|
||||||
|
"backgroundImageLabel": "Achtergrondafbeelding:",
|
||||||
|
"questionInputLabel": "Vraag:",
|
||||||
|
"videoUrlLabel": "Video-URL:",
|
||||||
|
"webUrlLabel": "Website-URL:",
|
||||||
|
|
||||||
|
"subSectionUpdatedSuccess": "Subsectie succesvol bijgewerkt",
|
||||||
|
"subSectionUpdateError": "Er is een fout opgetreden bij het bijwerken van de subsectie",
|
||||||
|
"subSectionDeletedSuccess": "Subsectie succesvol verwijderd",
|
||||||
|
"subSectionDeleteError": "Er is een fout opgetreden bij het verwijderen van de subsectie",
|
||||||
|
"subSectionOrderUpdatedSuccess": "Volgorde van subsecties succesvol bijgewerkt",
|
||||||
|
"subSectionOrderUpdateError": "Er is een fout opgetreden bij het bijwerken van de volgorde",
|
||||||
|
"subSectionCreatedSuccess": "Subsectie succesvol aangemaakt",
|
||||||
|
"subSectionCreateError": "Er is een fout opgetreden bij het aanmaken van de subsectie",
|
||||||
|
|
||||||
|
"questionsLabel": "Vragen",
|
||||||
|
"questionLabel": "Vraag",
|
||||||
|
"editQuestion": "Vraag bewerken",
|
||||||
|
"questionDeleteConfirm": "Weet u zeker dat u deze vraag wilt verwijderen?",
|
||||||
|
"questionsLoadError": "Er is een fout opgetreden bij het laden van de vragen",
|
||||||
|
"quizBadScore": "Slechte score",
|
||||||
|
"quizMediumScore": "Gemiddelde score",
|
||||||
|
"quizGoodScore": "Goede score",
|
||||||
|
"quizExcellentScore": "Uitstekende score",
|
||||||
|
"quizBadScoreMsg": "Bericht voor een slechte score",
|
||||||
|
"quizMediumScoreMsg": "Bericht voor een gemiddelde score",
|
||||||
|
"quizGoodScoreMsg": "Bericht voor een goede score",
|
||||||
|
"quizExcellentScoreMsg": "Bericht voor een uitstekende score",
|
||||||
|
"questionOrderUpdatedSuccess": "Vraagvolgorde succesvol bijgewerkt",
|
||||||
|
"questionOrderUpdateError": "Er is een fout opgetreden bij het bijwerken van de vraagvolgorde",
|
||||||
|
"questionCreatedSuccess": "Vraag succesvol aangemaakt",
|
||||||
|
"questionCreateError": "Er is een fout opgetreden bij het aanmaken van de vraag",
|
||||||
|
"questionUpdatedSuccess": "Vraag succesvol bijgewerkt",
|
||||||
|
"questionUpdateError": "Er is een fout opgetreden bij het bijwerken van de vraag",
|
||||||
|
"questionDeletedSuccess": "Vraag succesvol verwijderd",
|
||||||
|
"questionDeleteError": "Er is een fout opgetreden bij het verwijderen van de vraag",
|
||||||
|
"translationIncomplete": "De vertaling is niet volledig",
|
||||||
|
|
||||||
|
"geopointCreatedSuccess": "Punt succesvol aangemaakt",
|
||||||
|
"geopointCreateError": "Er is een fout opgetreden bij het aanmaken van het punt",
|
||||||
|
"geopointUpdatedSuccess": "Punt succesvol bijgewerkt",
|
||||||
|
"geopointUpdateError": "Er is een fout opgetreden bij het bijwerken van het punt",
|
||||||
|
"geopointDeletedSuccess": "Punt succesvol verwijderd",
|
||||||
|
"geopointDeleteError": "Er is een fout opgetreden bij het verwijderen van het punt",
|
||||||
|
"categoryCreatedSuccess": "Categorie succesvol aangemaakt",
|
||||||
|
"categoryCreateError": "Er is een fout opgetreden bij het aanmaken van de categorie",
|
||||||
|
"categoryUpdatedSuccess": "Categorie succesvol bijgewerkt",
|
||||||
|
"categoryUpdateError": "Er is een fout opgetreden bij het bijwerken van de categorie",
|
||||||
|
|
||||||
|
"eventCreatedSuccess": "Evenement succesvol aangemaakt",
|
||||||
|
"eventCreateError": "Er is een fout opgetreden bij het aanmaken van het evenement",
|
||||||
|
"eventUpdatedSuccess": "Evenement succesvol bijgewerkt",
|
||||||
|
"eventUpdateError": "Er is een fout opgetreden bij het bijwerken van het evenement",
|
||||||
|
"eventDeletedSuccess": "Evenement succesvol verwijderd",
|
||||||
|
"eventDeleteError": "Er is een fout opgetreden bij het verwijderen van het evenement",
|
||||||
|
"annotationCreatedSuccess": "Annotatie succesvol aangemaakt",
|
||||||
|
"annotationCreateError": "Er is een fout opgetreden bij het aanmaken van de annotatie",
|
||||||
|
"annotationUpdatedSuccess": "Annotatie succesvol bijgewerkt",
|
||||||
|
"annotationUpdateError": "Er is een fout opgetreden bij het bijwerken van de annotatie",
|
||||||
|
"programmeBlockCreatedSuccess": "Blok succesvol aangemaakt",
|
||||||
|
"programmeBlockCreateError": "Er is een fout opgetreden bij het aanmaken van het blok",
|
||||||
|
"programmeBlockUpdatedSuccess": "Blok succesvol bijgewerkt",
|
||||||
|
"programmeBlockUpdateError": "Er is een fout opgetreden bij het bijwerken van het blok",
|
||||||
|
|
||||||
|
"pathCreatedSuccess": "Parcours succesvol aangemaakt",
|
||||||
|
"pathCreateError": "Er is een fout opgetreden bij het aanmaken van het parcours",
|
||||||
|
"pathUpdatedSuccess": "Parcours succesvol bijgewerkt",
|
||||||
|
"pathUpdateError": "Er is een fout opgetreden bij het bijwerken van het parcours",
|
||||||
|
"stepCreatedSuccess": "Stap succesvol aangemaakt",
|
||||||
|
"stepCreateError": "Er is een fout opgetreden bij het aanmaken van de stap",
|
||||||
|
"stepUpdatedSuccess": "Stap succesvol bijgewerkt",
|
||||||
|
"stepUpdateError": "Er is een fout opgetreden bij het bijwerken van de stap",
|
||||||
|
|
||||||
|
"agendaEventsLabel": "Evenementen",
|
||||||
|
"agendaEventFallback": "Evenement",
|
||||||
|
"addEvent": "Evenement toevoegen",
|
||||||
|
"noEvents": "Geen evenementen",
|
||||||
|
"noAddress": "Geen adres",
|
||||||
|
"onlineLabel": "Online:",
|
||||||
|
"mapViewLabel": "Kaartweergave:",
|
||||||
|
"mapServiceLabel": "Kaartservice:",
|
||||||
|
"jsonFilesLabel": "JSON-bestanden:",
|
||||||
|
"jsonLabel": "JSON",
|
||||||
|
|
||||||
|
"guidedPathsLabel": "Begeleide parcours",
|
||||||
|
"addPath": "Parcours toevoegen",
|
||||||
|
"noPathConfigured": "Geen parcours geconfigureerd",
|
||||||
|
"pathOrderUpdateError": "Fout bij het bijwerken van de volgorde",
|
||||||
|
"pathNoTitle": "Parcours zonder titel",
|
||||||
|
"pathDeletedSuccess": "Parcours succesvol verwijderd",
|
||||||
|
"pathDeleteError": "Fout bij het verwijderen van het parcours",
|
||||||
|
"pathsLabel": "Parcours",
|
||||||
|
|
||||||
|
"pointsOfInterestLabel": "Bezienswaardigheden",
|
||||||
|
"geopointsLabel": "Geografische punten",
|
||||||
|
"searchLabel": "Zoeken:",
|
||||||
|
"geopointsLoadError": "Fout bij het laden van geografische punten",
|
||||||
|
"geopointDeleteConfirm": "Weet u zeker dat u dit geografische punt wilt verwijderen?",
|
||||||
|
"serviceLabel": "Service:",
|
||||||
|
"centerPointLabel": "Middelpunt:",
|
||||||
|
"iconLabel": "Pictogram:",
|
||||||
|
"listViewLabel": "Lijstweergave:",
|
||||||
|
"typeLabel": "Type:",
|
||||||
|
"zoomLabel": "Zoom:",
|
||||||
|
"categoriesLabel": "Categorieën:",
|
||||||
|
|
||||||
|
"startDateLabel": "Startdatum",
|
||||||
|
"notDefined": "Niet gedefinieerd",
|
||||||
|
"endDateLabel": "Einddatum",
|
||||||
|
"programmeLabel": "Programma",
|
||||||
|
"addBlock": "Blok toevoegen",
|
||||||
|
"blockFallback": "Blok",
|
||||||
|
"noBlocks": "Geen programmablokken gedefinieerd",
|
||||||
|
"programmeBlockDeletedSuccess": "Blok succesvol verwijderd",
|
||||||
|
"programmeBlockDeleteError": "Fout bij het verwijderen van het blok",
|
||||||
|
"baseMapLabel": "Basiskaart",
|
||||||
|
"mapLabel": "Kaart:",
|
||||||
|
"globalAnnotationsLabel": "Globale annotaties",
|
||||||
|
"addAnnotation": "Annotatie toevoegen",
|
||||||
|
"noAnnotations": "Geen globale annotaties",
|
||||||
|
"annotationFallback": "Annotatie",
|
||||||
|
"annotationDeletedSuccess": "Annotatie verwijderd",
|
||||||
|
"annotationDeleteError": "Fout bij verwijderen",
|
||||||
|
|
||||||
|
"agendaEventCreatedSuccess": "Evenement succesvol aangemaakt",
|
||||||
|
"agendaEventCreateError": "Er is een fout opgetreden bij het aanmaken van het evenement",
|
||||||
|
"agendaEventUpdatedSuccess": "Evenement succesvol bijgewerkt",
|
||||||
|
"agendaEventUpdateError": "Er is een fout opgetreden bij het bijwerken van het evenement",
|
||||||
|
"agendaEventDeletedSuccess": "Evenement succesvol verwijderd",
|
||||||
|
"agendaEventDeleteError": "Er is een fout opgetreden bij het verwijderen van het evenement",
|
||||||
|
|
||||||
|
"newResource": "Nieuwe bron",
|
||||||
|
"resourceCreatedSuccess": "Bron succesvol aangemaakt",
|
||||||
|
"resourceCreateError": "Er is een fout opgetreden bij het aanmaken van de bron",
|
||||||
|
"resourceUpdatedSuccess": "Bron succesvol bijgewerkt",
|
||||||
|
"resourceNoFileLoaded": "Er is geen bestand geladen",
|
||||||
|
"resourceNameRequired": "Geef de bron een naam",
|
||||||
|
"resourceTooLarge": "Fout: de bestandsgrootte moet kleiner zijn dan 1,5 MB",
|
||||||
|
"resourceInvalidUrl": "De URL is ongeldig",
|
||||||
|
"resourceUrlRequired": "Vul het URL-veld in",
|
||||||
|
|
||||||
|
"generalInfo": "Algemene informatie",
|
||||||
|
"mainImageLabel": "Hoofdafbeelding:",
|
||||||
|
"loaderLabel": "Loader:",
|
||||||
|
"primaryColorLabel": "Primaire kleur:",
|
||||||
|
"secondaryColorLabel": "Secundaire kleur:",
|
||||||
|
"layoutLabel": "Weergave:",
|
||||||
|
"layoutGrid": "Raster",
|
||||||
|
"languagesLabel": "Talen:",
|
||||||
|
"featuredEventLabel": "Uitgelicht evenement:",
|
||||||
|
"chooseEvent": "Kies een evenement",
|
||||||
|
"noneOption": "Geen",
|
||||||
|
"aiAssistantLabel": "AI-assistent:",
|
||||||
|
"appUpdatedSuccess": "Mobiele applicatie bijgewerkt",
|
||||||
|
"configActivatedSuccess": "Configuratie succesvol geactiveerd",
|
||||||
|
"configDeactivatedSuccess": "Configuratie succesvol gedeactiveerd",
|
||||||
|
"configRemoveConfirm": "Weet u zeker dat u deze configuratie uit de applicatie wilt verwijderen?",
|
||||||
|
"configRemovedSuccess": "Configuratie succesvol verwijderd uit de applicatie",
|
||||||
|
"configRemoveError": "Er is een fout opgetreden bij het verwijderen van de configuratie",
|
||||||
|
"phoneConfigTitle": "Configuraties per apparaat",
|
||||||
|
"addConfig": "Configuratie toevoegen",
|
||||||
|
"selectConfigToAdd": "Selecteer een configuratie om toe te voegen",
|
||||||
|
"noItems": "Geen items om weer te geven",
|
||||||
|
"add": "Toevoegen",
|
||||||
|
|
||||||
|
"pinCode": "Pincode: {code}",
|
||||||
|
"@pinCode": {
|
||||||
|
"placeholders": {
|
||||||
|
"code": { "type": "String" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tablets": "Tablets",
|
||||||
|
|
||||||
|
"stepsCount": "{count} stappen",
|
||||||
|
"@stepsCount": {
|
||||||
|
"placeholders": {
|
||||||
|
"count": { "type": "int" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"displayedDescriptionLabel": "Weergegeven beschrijving:",
|
||||||
|
"displayedContentLabel": "Weergegeven inhoud:",
|
||||||
|
"displayedNameLabel": "Weergavenaam:",
|
||||||
|
"startTimeLabel": "Begintijd",
|
||||||
|
"noAnnotationConfigured": "Geen annotaties geconfigureerd.",
|
||||||
|
"newStepTitle": "Nieuwe stap",
|
||||||
|
"editStepTitle": "Stap bewerken",
|
||||||
|
"stepTitleLabel": "Staptitel",
|
||||||
|
"stepDescriptionLabel": "Stapbeschrijving",
|
||||||
|
"stepLocationLabel": "Stap locatie:",
|
||||||
|
"initiallyHiddenLabel": "Aanvankelijk verborgen",
|
||||||
|
"lockedLabel": "Vergrendeld",
|
||||||
|
"durationSecondsLabel": "Duur (seconden):",
|
||||||
|
"triggerGeopointLabel": "GeoPoint trigger (ID):",
|
||||||
|
"questionsChallengesLabel": "Vragen / Uitdagingen",
|
||||||
|
"noQuestionsConfigured": "Geen vragen geconfigureerd.",
|
||||||
|
"newAgendaEventTitle": "Nieuw evenement",
|
||||||
|
"editAgendaEventTitle": "Evenement bewerken",
|
||||||
|
"eventTitleLabel": "Evenementtitel",
|
||||||
|
"eventDescriptionLabel": "Evenementbeschrijving",
|
||||||
|
"startDateColonLabel": "Begindatum:",
|
||||||
|
"videoResourceLabel": "Video:",
|
||||||
|
"directVideoLinkLabel": "Directe videolink:",
|
||||||
|
"phoneLabel": "Telefoon:",
|
||||||
|
"locationGeometryLabel": "Locatie / Geometrie",
|
||||||
|
"geometryLabel": "Geometrie:",
|
||||||
|
"materialIconLabel": "Icoon (material):",
|
||||||
|
"linearLabel": "Lineair:",
|
||||||
|
"requiredSuccessLabel": "Vereist succes:",
|
||||||
|
"pathStepsLabel": "Parcoursstappen",
|
||||||
|
"noStepConfigured": "Geen punt/stap geconfigureerd.",
|
||||||
|
"stepFallback": "Stap",
|
||||||
|
"questionAskedLabel": "Gestelde vraag:",
|
||||||
|
"questionTitleLabel": "Vraagstitel",
|
||||||
|
"expectedAnswerLabel": "Verwacht antwoord:",
|
||||||
|
"expectedAnswerModalLabel": "Verwacht antwoord",
|
||||||
|
"validationNote": "Validatie gebeurt door vergelijking (hoofdletterongevoelig).",
|
||||||
|
"possibleAnswersLabel": "Mogelijke antwoorden:",
|
||||||
|
"noAnswerDefined": "Geen antwoord gedefinieerd. Voeg er minstens één toe.",
|
||||||
|
"correctAnswer": "Correct antwoord ✓",
|
||||||
|
"wrongAnswer": "Fout antwoord",
|
||||||
|
"answerNote": "✓ = correct antwoord. Meerdere kunnen correct zijn.",
|
||||||
|
"geopointZoneTitle": "Geografisch punt / Zone",
|
||||||
|
"geometryTypeLabel": "Geometrie (Punt/Lijn/Zone):",
|
||||||
|
"phoneModalLabel": "Telefoon",
|
||||||
|
"categoryLabel": "Categorie:",
|
||||||
|
"startMessageLabel": "Startbericht:",
|
||||||
|
"startMessageModalLabel": "Startbericht",
|
||||||
|
"createCategoryTitle": "Categorie aanmaken",
|
||||||
|
"editCategoryTitle": "Categorie bewerken",
|
||||||
|
"categoryIconLabel": "Categorie-icoon:",
|
||||||
|
"selectResource": "Selecteer een resource",
|
||||||
|
"createPdfTitle": "PDF aanmaken",
|
||||||
|
"answersLabel": "Antwoorden",
|
||||||
|
"answerLabel": "Antwoord",
|
||||||
|
"createAnswerTitle": "Antwoord aanmaken",
|
||||||
|
"editAnswerTitle": "Antwoord bewerken",
|
||||||
|
"answerValidNote": "Indien aangevinkt, is het antwoord geldig",
|
||||||
|
"selectConfiguration": "Selecteer een configuratie",
|
||||||
|
"noConfigFound": "Geen configuratie gevonden",
|
||||||
|
"backgroundColorLabel": "Achtergrondkleur:",
|
||||||
|
"updateTabletBtn": "Tablet bijwerken",
|
||||||
|
"kioskUpdatedSuccess": "Kiosk bijgewerkt",
|
||||||
|
"webViewError": "De webpagina kan niet worden weergegeven, de URL is onjuist of leeg",
|
||||||
|
"download": "Downloaden",
|
||||||
|
"resourceDeleteConfirm": "Weet u zeker dat u deze resource wilt verwijderen?",
|
||||||
|
"categoriesTitle": "Categorieën",
|
||||||
|
"endTimeLabel": "Eindtijd",
|
||||||
|
"annotationsLabel": "Annotaties"
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:manager_app/l10n/app_localizations.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_quill/flutter_quill.dart';
|
import 'package:flutter_quill/flutter_quill.dart';
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
@ -234,6 +235,7 @@ class _MyAppState extends State<MyApp> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final locale = Provider.of<AppContext>(context).getContext()?.locale ?? const Locale('fr');
|
||||||
return MaterialApp.router(
|
return MaterialApp.router(
|
||||||
routerConfig: widget.router,
|
routerConfig: widget.router,
|
||||||
key: mainKey,
|
key: mainKey,
|
||||||
@ -246,9 +248,10 @@ class _MyAppState extends State<MyApp> {
|
|||||||
const Breakpoint(start: 1921, end: double.infinity, name: '4K'),
|
const Breakpoint(start: 1921, end: double.infinity, name: '4K'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
locale: const Locale('fr'),
|
locale: locale,
|
||||||
supportedLocales: const [Locale('fr')],
|
supportedLocales: const [Locale('fr'), Locale('en'), Locale('nl')],
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
|
AppLocalizations.delegate,
|
||||||
FlutterQuillLocalizations.delegate,
|
FlutterQuillLocalizations.delegate,
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
GlobalWidgetsLocalizations.delegate,
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
|||||||
@ -35,6 +35,7 @@ part 'api/authentication_api.dart';
|
|||||||
part 'api/configuration_api.dart';
|
part 'api/configuration_api.dart';
|
||||||
part 'api/device_api.dart';
|
part 'api/device_api.dart';
|
||||||
part 'api/instance_api.dart';
|
part 'api/instance_api.dart';
|
||||||
|
part 'api/subscription_plan_api.dart';
|
||||||
part 'api/resource_api.dart';
|
part 'api/resource_api.dart';
|
||||||
part 'api/section_api.dart';
|
part 'api/section_api.dart';
|
||||||
part 'api/section_agenda_api.dart';
|
part 'api/section_agenda_api.dart';
|
||||||
@ -116,6 +117,8 @@ part 'model/guided_step_guided_path.dart';
|
|||||||
part 'model/guided_step_trigger_geo_point.dart';
|
part 'model/guided_step_trigger_geo_point.dart';
|
||||||
part 'model/instance.dart';
|
part 'model/instance.dart';
|
||||||
part 'model/instance_dto.dart';
|
part 'model/instance_dto.dart';
|
||||||
|
part 'model/instance_quota_dto.dart';
|
||||||
|
part 'model/subscription_plan_dto.dart';
|
||||||
part 'model/layout_main_page_type.dart';
|
part 'model/layout_main_page_type.dart';
|
||||||
part 'model/login_dto.dart';
|
part 'model/login_dto.dart';
|
||||||
part 'model/map_annotation.dart';
|
part 'model/map_annotation.dart';
|
||||||
|
|||||||
@ -407,4 +407,54 @@ class InstanceApi {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs an HTTP 'GET /api/Instance/{id}/quota' operation and returns the [Response].
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
Future<Response> instanceGetQuotaWithHttpInfo(
|
||||||
|
String id,
|
||||||
|
) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final path = r'/api/Instance/{id}/quota'.replaceAll('{id}', id);
|
||||||
|
|
||||||
|
// ignore: prefer_final_locals
|
||||||
|
Object? postBody;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
const contentTypes = <String>[];
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
path,
|
||||||
|
'GET',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parameters:
|
||||||
|
///
|
||||||
|
/// * [String] id (required):
|
||||||
|
Future<InstanceQuotaDTO?> instanceGetQuota(
|
||||||
|
String id,
|
||||||
|
) async {
|
||||||
|
final response = await instanceGetQuotaWithHttpInfo(id);
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
if (response.body.isNotEmpty &&
|
||||||
|
response.statusCode != HttpStatus.noContent) {
|
||||||
|
return await apiClient.deserializeAsync(
|
||||||
|
await _decodeBodyBytes(response),
|
||||||
|
'InstanceQuotaDTO',
|
||||||
|
) as InstanceQuotaDTO;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
219
manager_api_new/lib/api/subscription_plan_api.dart
Normal file
219
manager_api_new/lib/api/subscription_plan_api.dart
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
//
|
||||||
|
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||||
|
//
|
||||||
|
// @dart=2.18
|
||||||
|
|
||||||
|
// ignore_for_file: unused_element, unused_import
|
||||||
|
// ignore_for_file: always_put_required_named_parameters_first
|
||||||
|
// ignore_for_file: constant_identifier_names
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
part of openapi.api;
|
||||||
|
|
||||||
|
class SubscriptionPlanApi {
|
||||||
|
SubscriptionPlanApi([ApiClient? apiClient])
|
||||||
|
: apiClient = apiClient ?? defaultApiClient;
|
||||||
|
|
||||||
|
final ApiClient apiClient;
|
||||||
|
|
||||||
|
/// Performs an HTTP 'GET /api/SubscriptionPlan' operation and returns the [Response].
|
||||||
|
Future<Response> subscriptionPlanGetWithHttpInfo() async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final path = r'/api/SubscriptionPlan';
|
||||||
|
|
||||||
|
// ignore: prefer_final_locals
|
||||||
|
Object? postBody;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
const contentTypes = <String>[];
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
path,
|
||||||
|
'GET',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<SubscriptionPlanDTO>?> subscriptionPlanGet() async {
|
||||||
|
final response = await subscriptionPlanGetWithHttpInfo();
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
if (response.body.isNotEmpty &&
|
||||||
|
response.statusCode != HttpStatus.noContent) {
|
||||||
|
final responseBody = await _decodeBodyBytes(response);
|
||||||
|
return (await apiClient.deserializeAsync(responseBody, 'List<SubscriptionPlanDTO>') as List)
|
||||||
|
.cast<SubscriptionPlanDTO>()
|
||||||
|
.toList(growable: false);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs an HTTP 'GET /api/SubscriptionPlan/{id}' operation and returns the [Response].
|
||||||
|
Future<Response> subscriptionPlanGetByIdWithHttpInfo(String id) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final path = r'/api/SubscriptionPlan/{id}'.replaceAll('{id}', id);
|
||||||
|
|
||||||
|
Object? postBody;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
const contentTypes = <String>[];
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
path,
|
||||||
|
'GET',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SubscriptionPlanDTO?> subscriptionPlanGetById(String id) async {
|
||||||
|
final response = await subscriptionPlanGetByIdWithHttpInfo(id);
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
if (response.body.isNotEmpty &&
|
||||||
|
response.statusCode != HttpStatus.noContent) {
|
||||||
|
return await apiClient.deserializeAsync(
|
||||||
|
await _decodeBodyBytes(response),
|
||||||
|
'SubscriptionPlanDTO',
|
||||||
|
) as SubscriptionPlanDTO;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs an HTTP 'POST /api/SubscriptionPlan' operation and returns the [Response].
|
||||||
|
Future<Response> subscriptionPlanCreateWithHttpInfo(
|
||||||
|
SubscriptionPlanDTO subscriptionPlanDTO,
|
||||||
|
) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final path = r'/api/SubscriptionPlan';
|
||||||
|
|
||||||
|
Object? postBody = subscriptionPlanDTO;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
const contentTypes = <String>['application/json'];
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
path,
|
||||||
|
'POST',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SubscriptionPlanDTO?> subscriptionPlanCreate(
|
||||||
|
SubscriptionPlanDTO subscriptionPlanDTO,
|
||||||
|
) async {
|
||||||
|
final response = await subscriptionPlanCreateWithHttpInfo(subscriptionPlanDTO);
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
if (response.body.isNotEmpty &&
|
||||||
|
response.statusCode != HttpStatus.noContent) {
|
||||||
|
return await apiClient.deserializeAsync(
|
||||||
|
await _decodeBodyBytes(response),
|
||||||
|
'SubscriptionPlanDTO',
|
||||||
|
) as SubscriptionPlanDTO;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs an HTTP 'PUT /api/SubscriptionPlan' operation and returns the [Response].
|
||||||
|
Future<Response> subscriptionPlanUpdateWithHttpInfo(
|
||||||
|
SubscriptionPlanDTO subscriptionPlanDTO,
|
||||||
|
) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final path = r'/api/SubscriptionPlan';
|
||||||
|
|
||||||
|
Object? postBody = subscriptionPlanDTO;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
const contentTypes = <String>['application/json'];
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
path,
|
||||||
|
'PUT',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SubscriptionPlanDTO?> subscriptionPlanUpdate(
|
||||||
|
SubscriptionPlanDTO subscriptionPlanDTO,
|
||||||
|
) async {
|
||||||
|
final response = await subscriptionPlanUpdateWithHttpInfo(subscriptionPlanDTO);
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
if (response.body.isNotEmpty &&
|
||||||
|
response.statusCode != HttpStatus.noContent) {
|
||||||
|
return await apiClient.deserializeAsync(
|
||||||
|
await _decodeBodyBytes(response),
|
||||||
|
'SubscriptionPlanDTO',
|
||||||
|
) as SubscriptionPlanDTO;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs an HTTP 'DELETE /api/SubscriptionPlan/{id}' operation and returns the [Response].
|
||||||
|
Future<Response> subscriptionPlanDeleteWithHttpInfo(String id) async {
|
||||||
|
// ignore: prefer_const_declarations
|
||||||
|
final path = r'/api/SubscriptionPlan/{id}'.replaceAll('{id}', id);
|
||||||
|
|
||||||
|
Object? postBody;
|
||||||
|
|
||||||
|
final queryParams = <QueryParam>[];
|
||||||
|
final headerParams = <String, String>{};
|
||||||
|
final formParams = <String, String>{};
|
||||||
|
|
||||||
|
const contentTypes = <String>[];
|
||||||
|
|
||||||
|
return apiClient.invokeAPI(
|
||||||
|
path,
|
||||||
|
'DELETE',
|
||||||
|
queryParams,
|
||||||
|
postBody,
|
||||||
|
headerParams,
|
||||||
|
formParams,
|
||||||
|
contentTypes.isEmpty ? null : contentTypes.first,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> subscriptionPlanDelete(String id) async {
|
||||||
|
final response = await subscriptionPlanDeleteWithHttpInfo(id);
|
||||||
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
|
}
|
||||||
|
if (response.body.isNotEmpty &&
|
||||||
|
response.statusCode != HttpStatus.noContent) {
|
||||||
|
return await _decodeBodyBytes(response);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -363,6 +363,8 @@ class ApiClient {
|
|||||||
return Instance.fromJson(value);
|
return Instance.fromJson(value);
|
||||||
case 'InstanceDTO':
|
case 'InstanceDTO':
|
||||||
return InstanceDTO.fromJson(value);
|
return InstanceDTO.fromJson(value);
|
||||||
|
case 'InstanceQuotaDTO':
|
||||||
|
return InstanceQuotaDTO.fromJson(value);
|
||||||
case 'LayoutMainPageType':
|
case 'LayoutMainPageType':
|
||||||
return LayoutMainPageTypeTypeTransformer().decode(value);
|
return LayoutMainPageTypeTypeTransformer().decode(value);
|
||||||
case 'LoginDTO':
|
case 'LoginDTO':
|
||||||
@ -457,6 +459,8 @@ class ApiClient {
|
|||||||
return Section.fromJson(value);
|
return Section.fromJson(value);
|
||||||
case 'SectionDTO':
|
case 'SectionDTO':
|
||||||
return SectionDTO.fromJson(value);
|
return SectionDTO.fromJson(value);
|
||||||
|
case 'SubscriptionPlanDTO':
|
||||||
|
return SubscriptionPlanDTO.fromJson(value);
|
||||||
case 'SectionEvent':
|
case 'SectionEvent':
|
||||||
return SectionEvent.fromJson(value);
|
return SectionEvent.fromJson(value);
|
||||||
case 'SectionEventDTO':
|
case 'SectionEventDTO':
|
||||||
|
|||||||
@ -24,6 +24,15 @@ class InstanceDTO {
|
|||||||
this.isWeb,
|
this.isWeb,
|
||||||
this.isVR,
|
this.isVR,
|
||||||
this.isAssistant,
|
this.isAssistant,
|
||||||
|
this.subscriptionPlanId,
|
||||||
|
this.subscriptionPlan,
|
||||||
|
this.aiRequestsThisMonth,
|
||||||
|
this.aiUsageMonthKey,
|
||||||
|
this.storageQuotaBytes,
|
||||||
|
this.aiRequestsPerMonth,
|
||||||
|
this.hasStats,
|
||||||
|
this.statsHistoryDays,
|
||||||
|
this.hasAdvancedStats,
|
||||||
this.applicationInstanceDTOs = const [],
|
this.applicationInstanceDTOs = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -85,6 +94,24 @@ class InstanceDTO {
|
|||||||
|
|
||||||
bool? isAssistant;
|
bool? isAssistant;
|
||||||
|
|
||||||
|
String? subscriptionPlanId;
|
||||||
|
|
||||||
|
SubscriptionPlanDTO? subscriptionPlan;
|
||||||
|
|
||||||
|
int? aiRequestsThisMonth;
|
||||||
|
|
||||||
|
String? aiUsageMonthKey;
|
||||||
|
|
||||||
|
int? storageQuotaBytes;
|
||||||
|
|
||||||
|
int? aiRequestsPerMonth;
|
||||||
|
|
||||||
|
bool? hasStats;
|
||||||
|
|
||||||
|
int? statsHistoryDays;
|
||||||
|
|
||||||
|
bool? hasAdvancedStats;
|
||||||
|
|
||||||
List<ApplicationInstanceDTO>? applicationInstanceDTOs;
|
List<ApplicationInstanceDTO>? applicationInstanceDTOs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -102,6 +129,15 @@ class InstanceDTO {
|
|||||||
other.isWeb == isWeb &&
|
other.isWeb == isWeb &&
|
||||||
other.isVR == isVR &&
|
other.isVR == isVR &&
|
||||||
other.isAssistant == isAssistant &&
|
other.isAssistant == isAssistant &&
|
||||||
|
other.subscriptionPlanId == subscriptionPlanId &&
|
||||||
|
other.subscriptionPlan == subscriptionPlan &&
|
||||||
|
other.aiRequestsThisMonth == aiRequestsThisMonth &&
|
||||||
|
other.aiUsageMonthKey == aiUsageMonthKey &&
|
||||||
|
other.storageQuotaBytes == storageQuotaBytes &&
|
||||||
|
other.aiRequestsPerMonth == aiRequestsPerMonth &&
|
||||||
|
other.hasStats == hasStats &&
|
||||||
|
other.statsHistoryDays == statsHistoryDays &&
|
||||||
|
other.hasAdvancedStats == hasAdvancedStats &&
|
||||||
_deepEquality.equals(
|
_deepEquality.equals(
|
||||||
other.applicationInstanceDTOs, applicationInstanceDTOs);
|
other.applicationInstanceDTOs, applicationInstanceDTOs);
|
||||||
|
|
||||||
@ -119,11 +155,15 @@ class InstanceDTO {
|
|||||||
(isWeb == null ? 0 : isWeb!.hashCode) +
|
(isWeb == null ? 0 : isWeb!.hashCode) +
|
||||||
(isVR == null ? 0 : isVR!.hashCode) +
|
(isVR == null ? 0 : isVR!.hashCode) +
|
||||||
(isAssistant == null ? 0 : isAssistant!.hashCode) +
|
(isAssistant == null ? 0 : isAssistant!.hashCode) +
|
||||||
|
(subscriptionPlanId == null ? 0 : subscriptionPlanId!.hashCode) +
|
||||||
|
(subscriptionPlan == null ? 0 : subscriptionPlan!.hashCode) +
|
||||||
|
(aiRequestsThisMonth == null ? 0 : aiRequestsThisMonth!.hashCode) +
|
||||||
|
(aiUsageMonthKey == null ? 0 : aiUsageMonthKey!.hashCode) +
|
||||||
(applicationInstanceDTOs == null ? 0 : applicationInstanceDTOs!.hashCode);
|
(applicationInstanceDTOs == null ? 0 : applicationInstanceDTOs!.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() =>
|
String toString() =>
|
||||||
'InstanceDTO[id=$id, name=$name, dateCreation=$dateCreation, pinCode=$pinCode, isPushNotification=$isPushNotification, isStatistic=$isStatistic, isMobile=$isMobile, isTablet=$isTablet, isWeb=$isWeb, isVR=$isVR, isAssistant=$isAssistant, applicationInstanceDTOs=$applicationInstanceDTOs]';
|
'InstanceDTO[id=$id, name=$name, dateCreation=$dateCreation, pinCode=$pinCode, isPushNotification=$isPushNotification, isStatistic=$isStatistic, isMobile=$isMobile, isTablet=$isTablet, isWeb=$isWeb, isVR=$isVR, isAssistant=$isAssistant, subscriptionPlanId=$subscriptionPlanId, subscriptionPlan=$subscriptionPlan, aiRequestsThisMonth=$aiRequestsThisMonth, aiUsageMonthKey=$aiUsageMonthKey, applicationInstanceDTOs=$applicationInstanceDTOs]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
@ -182,6 +222,51 @@ class InstanceDTO {
|
|||||||
} else {
|
} else {
|
||||||
json[r'isAssistant'] = null;
|
json[r'isAssistant'] = null;
|
||||||
}
|
}
|
||||||
|
if (this.subscriptionPlanId != null) {
|
||||||
|
json[r'subscriptionPlanId'] = this.subscriptionPlanId;
|
||||||
|
} else {
|
||||||
|
json[r'subscriptionPlanId'] = null;
|
||||||
|
}
|
||||||
|
if (this.subscriptionPlan != null) {
|
||||||
|
json[r'subscriptionPlan'] = this.subscriptionPlan;
|
||||||
|
} else {
|
||||||
|
json[r'subscriptionPlan'] = null;
|
||||||
|
}
|
||||||
|
if (this.aiRequestsThisMonth != null) {
|
||||||
|
json[r'aiRequestsThisMonth'] = this.aiRequestsThisMonth;
|
||||||
|
} else {
|
||||||
|
json[r'aiRequestsThisMonth'] = null;
|
||||||
|
}
|
||||||
|
if (this.aiUsageMonthKey != null) {
|
||||||
|
json[r'aiUsageMonthKey'] = this.aiUsageMonthKey;
|
||||||
|
} else {
|
||||||
|
json[r'aiUsageMonthKey'] = null;
|
||||||
|
}
|
||||||
|
if (this.storageQuotaBytes != null) {
|
||||||
|
json[r'storageQuotaBytes'] = this.storageQuotaBytes;
|
||||||
|
} else {
|
||||||
|
json[r'storageQuotaBytes'] = null;
|
||||||
|
}
|
||||||
|
if (this.aiRequestsPerMonth != null) {
|
||||||
|
json[r'aiRequestsPerMonth'] = this.aiRequestsPerMonth;
|
||||||
|
} else {
|
||||||
|
json[r'aiRequestsPerMonth'] = null;
|
||||||
|
}
|
||||||
|
if (this.hasStats != null) {
|
||||||
|
json[r'hasStats'] = this.hasStats;
|
||||||
|
} else {
|
||||||
|
json[r'hasStats'] = null;
|
||||||
|
}
|
||||||
|
if (this.statsHistoryDays != null) {
|
||||||
|
json[r'statsHistoryDays'] = this.statsHistoryDays;
|
||||||
|
} else {
|
||||||
|
json[r'statsHistoryDays'] = null;
|
||||||
|
}
|
||||||
|
if (this.hasAdvancedStats != null) {
|
||||||
|
json[r'hasAdvancedStats'] = this.hasAdvancedStats;
|
||||||
|
} else {
|
||||||
|
json[r'hasAdvancedStats'] = null;
|
||||||
|
}
|
||||||
if (this.applicationInstanceDTOs != null) {
|
if (this.applicationInstanceDTOs != null) {
|
||||||
json[r'applicationInstanceDTOs'] = this.applicationInstanceDTOs;
|
json[r'applicationInstanceDTOs'] = this.applicationInstanceDTOs;
|
||||||
} else {
|
} else {
|
||||||
@ -222,6 +307,15 @@ class InstanceDTO {
|
|||||||
isWeb: mapValueOfType<bool>(json, r'isWeb'),
|
isWeb: mapValueOfType<bool>(json, r'isWeb'),
|
||||||
isVR: mapValueOfType<bool>(json, r'isVR'),
|
isVR: mapValueOfType<bool>(json, r'isVR'),
|
||||||
isAssistant: mapValueOfType<bool>(json, r'isAssistant'),
|
isAssistant: mapValueOfType<bool>(json, r'isAssistant'),
|
||||||
|
subscriptionPlanId: mapValueOfType<String>(json, r'subscriptionPlanId'),
|
||||||
|
subscriptionPlan: SubscriptionPlanDTO.fromJson(json[r'subscriptionPlan']),
|
||||||
|
aiRequestsThisMonth: mapValueOfType<int>(json, r'aiRequestsThisMonth'),
|
||||||
|
aiUsageMonthKey: mapValueOfType<String>(json, r'aiUsageMonthKey'),
|
||||||
|
storageQuotaBytes: mapValueOfType<int>(json, r'storageQuotaBytes'),
|
||||||
|
aiRequestsPerMonth: mapValueOfType<int>(json, r'aiRequestsPerMonth'),
|
||||||
|
hasStats: mapValueOfType<bool>(json, r'hasStats'),
|
||||||
|
statsHistoryDays: mapValueOfType<int>(json, r'statsHistoryDays'),
|
||||||
|
hasAdvancedStats: mapValueOfType<bool>(json, r'hasAdvancedStats'),
|
||||||
applicationInstanceDTOs: ApplicationInstanceDTO.listFromJson(
|
applicationInstanceDTOs: ApplicationInstanceDTO.listFromJson(
|
||||||
json[r'applicationInstanceDTOs']),
|
json[r'applicationInstanceDTOs']),
|
||||||
);
|
);
|
||||||
|
|||||||
106
manager_api_new/lib/model/instance_quota_dto.dart
Normal file
106
manager_api_new/lib/model/instance_quota_dto.dart
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
//
|
||||||
|
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||||
|
//
|
||||||
|
// @dart=2.18
|
||||||
|
|
||||||
|
// ignore_for_file: unused_element, unused_import
|
||||||
|
// ignore_for_file: always_put_required_named_parameters_first
|
||||||
|
// ignore_for_file: constant_identifier_names
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
part of openapi.api;
|
||||||
|
|
||||||
|
class InstanceQuotaDTO {
|
||||||
|
/// Returns a new [InstanceQuotaDTO] instance.
|
||||||
|
InstanceQuotaDTO({
|
||||||
|
this.storageUsedBytes,
|
||||||
|
this.storageQuotaBytes,
|
||||||
|
this.aiRequestsUsed,
|
||||||
|
this.aiRequestsPerMonth,
|
||||||
|
});
|
||||||
|
|
||||||
|
int? storageUsedBytes;
|
||||||
|
|
||||||
|
int? storageQuotaBytes;
|
||||||
|
|
||||||
|
int? aiRequestsUsed;
|
||||||
|
|
||||||
|
int? aiRequestsPerMonth;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is InstanceQuotaDTO &&
|
||||||
|
other.storageUsedBytes == storageUsedBytes &&
|
||||||
|
other.storageQuotaBytes == storageQuotaBytes &&
|
||||||
|
other.aiRequestsUsed == aiRequestsUsed &&
|
||||||
|
other.aiRequestsPerMonth == aiRequestsPerMonth;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
(storageUsedBytes == null ? 0 : storageUsedBytes!.hashCode) +
|
||||||
|
(storageQuotaBytes == null ? 0 : storageQuotaBytes!.hashCode) +
|
||||||
|
(aiRequestsUsed == null ? 0 : aiRequestsUsed!.hashCode) +
|
||||||
|
(aiRequestsPerMonth == null ? 0 : aiRequestsPerMonth!.hashCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() =>
|
||||||
|
'InstanceQuotaDTO[storageUsedBytes=$storageUsedBytes, storageQuotaBytes=$storageQuotaBytes, aiRequestsUsed=$aiRequestsUsed, aiRequestsPerMonth=$aiRequestsPerMonth]';
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{};
|
||||||
|
if (this.storageUsedBytes != null) {
|
||||||
|
json[r'storageUsedBytes'] = this.storageUsedBytes;
|
||||||
|
} else {
|
||||||
|
json[r'storageUsedBytes'] = null;
|
||||||
|
}
|
||||||
|
if (this.storageQuotaBytes != null) {
|
||||||
|
json[r'storageQuotaBytes'] = this.storageQuotaBytes;
|
||||||
|
} else {
|
||||||
|
json[r'storageQuotaBytes'] = null;
|
||||||
|
}
|
||||||
|
if (this.aiRequestsUsed != null) {
|
||||||
|
json[r'aiRequestsUsed'] = this.aiRequestsUsed;
|
||||||
|
} else {
|
||||||
|
json[r'aiRequestsUsed'] = null;
|
||||||
|
}
|
||||||
|
if (this.aiRequestsPerMonth != null) {
|
||||||
|
json[r'aiRequestsPerMonth'] = this.aiRequestsPerMonth;
|
||||||
|
} else {
|
||||||
|
json[r'aiRequestsPerMonth'] = null;
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore: prefer_constructors_over_static_methods
|
||||||
|
static InstanceQuotaDTO? fromJson(dynamic value) {
|
||||||
|
if (value is Map) {
|
||||||
|
final json = value.cast<String, dynamic>();
|
||||||
|
return InstanceQuotaDTO(
|
||||||
|
storageUsedBytes: mapValueOfType<int>(json, r'storageUsedBytes'),
|
||||||
|
storageQuotaBytes: mapValueOfType<int>(json, r'storageQuotaBytes'),
|
||||||
|
aiRequestsUsed: mapValueOfType<int>(json, r'aiRequestsUsed'),
|
||||||
|
aiRequestsPerMonth: mapValueOfType<int>(json, r'aiRequestsPerMonth'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<InstanceQuotaDTO> listFromJson(
|
||||||
|
dynamic json, {
|
||||||
|
bool growable = false,
|
||||||
|
}) {
|
||||||
|
final result = <InstanceQuotaDTO>[];
|
||||||
|
if (json is List && json.isNotEmpty) {
|
||||||
|
for (final row in json) {
|
||||||
|
final value = InstanceQuotaDTO.fromJson(row);
|
||||||
|
if (value != null) {
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toList(growable: growable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const requiredKeys = <String>{};
|
||||||
|
}
|
||||||
@ -38,7 +38,7 @@ class MapAnnotation {
|
|||||||
///
|
///
|
||||||
GeometryType? geometryType;
|
GeometryType? geometryType;
|
||||||
|
|
||||||
MapAnnotationGeometry? geometry;
|
EventAddressDTOGeometry? geometry;
|
||||||
|
|
||||||
String? polyColor;
|
String? polyColor;
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ class MapAnnotation {
|
|||||||
type: TranslationDTO.listFromJson(json[r'type']),
|
type: TranslationDTO.listFromJson(json[r'type']),
|
||||||
label: TranslationDTO.listFromJson(json[r'label']),
|
label: TranslationDTO.listFromJson(json[r'label']),
|
||||||
geometryType: GeometryType.fromJson(json[r'geometryType']),
|
geometryType: GeometryType.fromJson(json[r'geometryType']),
|
||||||
geometry: MapAnnotationGeometry.fromJson(json[r'geometry']),
|
geometry: EventAddressDTOGeometry.fromJson(json[r'geometry']),
|
||||||
polyColor: mapValueOfType<String>(json, r'polyColor'),
|
polyColor: mapValueOfType<String>(json, r'polyColor'),
|
||||||
icon: mapValueOfType<String>(json, r'icon'),
|
icon: mapValueOfType<String>(json, r'icon'),
|
||||||
iconResourceId: mapValueOfType<String>(json, r'iconResourceId'),
|
iconResourceId: mapValueOfType<String>(json, r'iconResourceId'),
|
||||||
|
|||||||
@ -19,6 +19,7 @@ class ResourceDTO {
|
|||||||
this.url,
|
this.url,
|
||||||
this.dateCreation,
|
this.dateCreation,
|
||||||
this.instanceId,
|
this.instanceId,
|
||||||
|
this.sizeBytes,
|
||||||
});
|
});
|
||||||
|
|
||||||
String? id;
|
String? id;
|
||||||
@ -45,6 +46,8 @@ class ResourceDTO {
|
|||||||
|
|
||||||
String? instanceId;
|
String? instanceId;
|
||||||
|
|
||||||
|
int? sizeBytes;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
@ -102,6 +105,9 @@ class ResourceDTO {
|
|||||||
} else {
|
} else {
|
||||||
json[r'instanceId'] = null;
|
json[r'instanceId'] = null;
|
||||||
}
|
}
|
||||||
|
if (this.sizeBytes != null) {
|
||||||
|
json[r'sizeBytes'] = this.sizeBytes;
|
||||||
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +138,7 @@ class ResourceDTO {
|
|||||||
url: mapValueOfType<String>(json, r'url'),
|
url: mapValueOfType<String>(json, r'url'),
|
||||||
dateCreation: mapDateTime(json, r'dateCreation', r''),
|
dateCreation: mapDateTime(json, r'dateCreation', r''),
|
||||||
instanceId: mapValueOfType<String>(json, r'instanceId'),
|
instanceId: mapValueOfType<String>(json, r'instanceId'),
|
||||||
|
sizeBytes: mapValueOfType<int>(json, r'sizeBytes'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
155
manager_api_new/lib/model/subscription_plan_dto.dart
Normal file
155
manager_api_new/lib/model/subscription_plan_dto.dart
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
//
|
||||||
|
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||||
|
//
|
||||||
|
// @dart=2.18
|
||||||
|
|
||||||
|
// ignore_for_file: unused_element, unused_import
|
||||||
|
// ignore_for_file: always_put_required_named_parameters_first
|
||||||
|
// ignore_for_file: constant_identifier_names
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
part of openapi.api;
|
||||||
|
|
||||||
|
class SubscriptionPlanDTO {
|
||||||
|
/// Returns a new [SubscriptionPlanDTO] instance.
|
||||||
|
SubscriptionPlanDTO({
|
||||||
|
this.id,
|
||||||
|
required this.name,
|
||||||
|
this.storageQuotaBytes,
|
||||||
|
this.aiRequestsPerMonth,
|
||||||
|
this.statsHistoryDays,
|
||||||
|
this.hasAdvancedStats,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? id;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
int? storageQuotaBytes;
|
||||||
|
|
||||||
|
int? aiRequestsPerMonth;
|
||||||
|
|
||||||
|
int? statsHistoryDays;
|
||||||
|
|
||||||
|
bool? hasAdvancedStats;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is SubscriptionPlanDTO &&
|
||||||
|
other.id == id &&
|
||||||
|
other.name == name &&
|
||||||
|
other.storageQuotaBytes == storageQuotaBytes &&
|
||||||
|
other.aiRequestsPerMonth == aiRequestsPerMonth &&
|
||||||
|
other.statsHistoryDays == statsHistoryDays &&
|
||||||
|
other.hasAdvancedStats == hasAdvancedStats;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
(id == null ? 0 : id!.hashCode) +
|
||||||
|
(name.hashCode) +
|
||||||
|
(storageQuotaBytes == null ? 0 : storageQuotaBytes!.hashCode) +
|
||||||
|
(aiRequestsPerMonth == null ? 0 : aiRequestsPerMonth!.hashCode) +
|
||||||
|
(statsHistoryDays == null ? 0 : statsHistoryDays!.hashCode) +
|
||||||
|
(hasAdvancedStats == null ? 0 : hasAdvancedStats!.hashCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() =>
|
||||||
|
'SubscriptionPlanDTO[id=$id, name=$name, storageQuotaBytes=$storageQuotaBytes, aiRequestsPerMonth=$aiRequestsPerMonth, statsHistoryDays=$statsHistoryDays, hasAdvancedStats=$hasAdvancedStats]';
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{};
|
||||||
|
if (this.id != null) {
|
||||||
|
json[r'id'] = this.id;
|
||||||
|
} else {
|
||||||
|
json[r'id'] = null;
|
||||||
|
}
|
||||||
|
json[r'name'] = this.name;
|
||||||
|
if (this.storageQuotaBytes != null) {
|
||||||
|
json[r'storageQuotaBytes'] = this.storageQuotaBytes;
|
||||||
|
} else {
|
||||||
|
json[r'storageQuotaBytes'] = null;
|
||||||
|
}
|
||||||
|
if (this.aiRequestsPerMonth != null) {
|
||||||
|
json[r'aiRequestsPerMonth'] = this.aiRequestsPerMonth;
|
||||||
|
} else {
|
||||||
|
json[r'aiRequestsPerMonth'] = null;
|
||||||
|
}
|
||||||
|
if (this.statsHistoryDays != null) {
|
||||||
|
json[r'statsHistoryDays'] = this.statsHistoryDays;
|
||||||
|
} else {
|
||||||
|
json[r'statsHistoryDays'] = null;
|
||||||
|
}
|
||||||
|
if (this.hasAdvancedStats != null) {
|
||||||
|
json[r'hasAdvancedStats'] = this.hasAdvancedStats;
|
||||||
|
} else {
|
||||||
|
json[r'hasAdvancedStats'] = null;
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore: prefer_constructors_over_static_methods
|
||||||
|
static SubscriptionPlanDTO? fromJson(dynamic value) {
|
||||||
|
if (value is Map) {
|
||||||
|
final json = value.cast<String, dynamic>();
|
||||||
|
return SubscriptionPlanDTO(
|
||||||
|
id: mapValueOfType<String>(json, r'id'),
|
||||||
|
name: mapValueOfType<String>(json, r'name') ?? '',
|
||||||
|
storageQuotaBytes: mapValueOfType<int>(json, r'storageQuotaBytes'),
|
||||||
|
aiRequestsPerMonth: mapValueOfType<int>(json, r'aiRequestsPerMonth'),
|
||||||
|
statsHistoryDays: mapValueOfType<int>(json, r'statsHistoryDays'),
|
||||||
|
hasAdvancedStats: mapValueOfType<bool>(json, r'hasAdvancedStats'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<SubscriptionPlanDTO> listFromJson(
|
||||||
|
dynamic json, {
|
||||||
|
bool growable = false,
|
||||||
|
}) {
|
||||||
|
final result = <SubscriptionPlanDTO>[];
|
||||||
|
if (json is List && json.isNotEmpty) {
|
||||||
|
for (final row in json) {
|
||||||
|
final value = SubscriptionPlanDTO.fromJson(row);
|
||||||
|
if (value != null) {
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toList(growable: growable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, SubscriptionPlanDTO> mapFromJson(dynamic json) {
|
||||||
|
final map = <String, SubscriptionPlanDTO>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
json = json.cast<String, dynamic>();
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
final value = SubscriptionPlanDTO.fromJson(entry.value);
|
||||||
|
if (value != null) {
|
||||||
|
map[entry.key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, List<SubscriptionPlanDTO>> mapListFromJson(
|
||||||
|
dynamic json, {
|
||||||
|
bool growable = false,
|
||||||
|
}) {
|
||||||
|
final map = <String, List<SubscriptionPlanDTO>>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
json = json.cast<String, dynamic>();
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
map[entry.key] = SubscriptionPlanDTO.listFromJson(
|
||||||
|
entry.value,
|
||||||
|
growable: growable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const requiredKeys = <String>{'name'};
|
||||||
|
}
|
||||||
@ -559,7 +559,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
|||||||
@ -23,6 +23,8 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_localizations:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
rxdart:
|
rxdart:
|
||||||
provider:
|
provider:
|
||||||
@ -100,7 +102,7 @@ flutter:
|
|||||||
# The following line ensures that the Material Icons font is
|
# The following line ensures that the Material Icons font is
|
||||||
# included with your application, so that you can use the icons in
|
# included with your application, so that you can use the icons in
|
||||||
# the material Icons class.
|
# the material Icons class.
|
||||||
#generate: true
|
generate: true
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user