Wip manager app, update to support web + fix section event layout
This commit is contained in:
parent
7669f38ed8
commit
2e8b82aa80
@ -15,81 +15,95 @@ import 'flag_decoration.dart';
|
||||
|
||||
showMultiStringInput (String label, String modalLabel, bool isTitle, List<TranslationDTO> values, List<TranslationDTO> newValues, Function onGetResult, int maxLines, List<ResourceType>? resourceTypes, BuildContext context) { /*Function onSelect,*/
|
||||
showDialog(
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
builder: (BuildContext context) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
title: Center(child: Text(modalLabel)),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: getTranslations(context, Provider.of<AppContext>(context), label, isTitle, resourceTypes, newValues),
|
||||
child: SizedBox(
|
||||
width: 560,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(child: Text(modalLabel, style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500))),
|
||||
const SizedBox(height: 16),
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: getTranslations(context, Provider.of<AppContext>(context), label, isTitle, resourceTypes, newValues),
|
||||
),
|
||||
),
|
||||
),
|
||||
/*Container(
|
||||
width: 500,
|
||||
height: 200,
|
||||
child: TranslationTab(
|
||||
translations: newValues,
|
||||
maxLines: maxLines
|
||||
)
|
||||
),*/
|
||||
/*Column(
|
||||
children: showValues(newValues),
|
||||
),*/
|
||||
],
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
/*Container(
|
||||
width: 500,
|
||||
height: 200,
|
||||
child: TranslationTab(
|
||||
translations: newValues,
|
||||
maxLines: maxLines
|
||||
)
|
||||
),*/
|
||||
/*Column(
|
||||
children: showValues(newValues),
|
||||
),*/
|
||||
],
|
||||
)
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
width: 180,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
onGetResult(values);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
width: 180,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
onGetResult(values);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
width: 180,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Valider",
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
Function deepEq = const DeepCollectionEquality().equals;
|
||||
if (!deepEq(values, newValues)) {
|
||||
onGetResult(newValues);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
width: 180,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Valider",
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
Function deepEq = const DeepCollectionEquality().equals;
|
||||
if (!deepEq(values, newValues)) {
|
||||
onGetResult(newValues);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
), context: context
|
||||
);
|
||||
}
|
||||
|
||||
@ -38,28 +38,24 @@ class _ResourceTabState extends State<ResourceTab> with SingleTickerProviderStat
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
TabBar(
|
||||
unselectedLabelColor: Colors.black,
|
||||
labelColor: kPrimaryColor,
|
||||
tabs: tabsToShow,
|
||||
controller: _tabController,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicatorColor: kPrimaryColor,
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
children: getContent(widget.resourceDTO, widget.onFileUpload, widget.onFileUploadWeb),
|
||||
controller: _tabController,
|
||||
),
|
||||
),
|
||||
],
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
TabBar(
|
||||
unselectedLabelColor: Colors.black,
|
||||
labelColor: kPrimaryColor,
|
||||
tabs: tabsToShow,
|
||||
controller: _tabController,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicatorColor: kPrimaryColor,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
children: getContent(widget.resourceDTO, widget.onFileUpload, widget.onFileUploadWeb),
|
||||
controller: _tabController,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:manager_app/Components/rounded_input_field.dart';
|
||||
import 'package:manager_app/constants.dart';
|
||||
@ -28,37 +27,29 @@ class StringInputContainer extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size size = MediaQuery.of(context).size;
|
||||
|
||||
return Container(
|
||||
child: Row(
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 16,
|
||||
),
|
||||
Padding(
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
width: isUrl ? size.width *0.6 : isSmall ? size.width *0.1 : size.width *0.25,
|
||||
child: RoundedInputField(
|
||||
color: color!,
|
||||
textColor: kBlack,
|
||||
fontSize: fontSizeText,
|
||||
initialValue: initialValue,
|
||||
onChanged: onChanged,
|
||||
maxLength: maxLength,
|
||||
),
|
||||
child: RoundedInputField(
|
||||
color: color!,
|
||||
textColor: kBlack,
|
||||
fontSize: fontSizeText,
|
||||
initialValue: initialValue,
|
||||
onChanged: onChanged,
|
||||
maxLength: maxLength,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ dynamic showAddConfigurationLink (BuildContext mainContext, AppContext appContex
|
||||
future: getConfigurations(appContext),
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
List<ConfigurationDTO> configurations = snapshot.data;
|
||||
List<ConfigurationDTO> configurations = snapshot.data ?? [];
|
||||
|
||||
// filter by already linked
|
||||
configurations = configurations.where((c) => !configurationIds.contains(c.id)).toList();
|
||||
@ -61,7 +61,7 @@ dynamic showAddConfigurationLink (BuildContext mainContext, AppContext appContex
|
||||
shape: BoxShape.rectangle,
|
||||
color: kWhite,
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
image: configuration.imageId != null
|
||||
image: configuration.imageSource != null
|
||||
? DecorationImage(
|
||||
fit: BoxFit.cover,
|
||||
image: NetworkImage(configuration.imageSource!),
|
||||
@ -77,9 +77,9 @@ dynamic showAddConfigurationLink (BuildContext mainContext, AppContext appContex
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(configuration.label!, style: Theme.of(context).textTheme.titleMedium),
|
||||
subtitle: Text(configuration.dateCreation!.toString(), style: Theme.of(context).textTheme.bodyMedium),
|
||||
trailing: Text(configuration.languages!.toString(), style: Theme.of(context).textTheme.bodyMedium),
|
||||
title: Text(configuration.label ?? '', style: Theme.of(context).textTheme.titleMedium),
|
||||
subtitle: Text(configuration.dateCreation?.toString() ?? '', style: Theme.of(context).textTheme.bodyMedium),
|
||||
trailing: Text(configuration.languages?.toString() ?? '', style: Theme.of(context).textTheme.bodyMedium),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (isSelected) {
|
||||
|
||||
@ -23,7 +23,10 @@ import 'package:provider/provider.dart';
|
||||
|
||||
class AppConfigurationLinkScreen extends StatefulWidget {
|
||||
final ApplicationInstanceDTO applicationInstanceDTO;
|
||||
AppConfigurationLinkScreen({Key? key, required this.applicationInstanceDTO}) : super(key: key);
|
||||
final bool showAssistant;
|
||||
final String? configTitle;
|
||||
final String? appUpdatedLabel;
|
||||
AppConfigurationLinkScreen({Key? key, required this.applicationInstanceDTO, this.showAssistant = true, this.configTitle, this.appUpdatedLabel}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AppConfigurationLinkScreenState createState() => _AppConfigurationLinkScreenState();
|
||||
@ -43,11 +46,11 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
final appContext = Provider.of<AppContext>(context);
|
||||
Size size = MediaQuery.of(context).size;
|
||||
ManagerAppContext managerAppContext = appContext.getContext() as ManagerAppContext;
|
||||
final appUpdatedMsg = widget.appUpdatedLabel ?? AppLocalizations.of(context)!.appUpdatedSuccess;
|
||||
|
||||
_generalInfoCard() {
|
||||
|
||||
var elementWidth = 400.0;
|
||||
var elementHeight = 125.0;
|
||||
const elementHeight = 125.0;
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 8),
|
||||
@ -61,7 +64,10 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
Text(AppLocalizations.of(context)!.generalInfo, style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
|
||||
SizedBox(height: 8),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final elementWidth = (constraints.maxWidth < 420) ? constraints.maxWidth : 400.0;
|
||||
return Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
@ -92,7 +98,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
// automatic save
|
||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||
if(applicationLink != null) {
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
/*setState(() {
|
||||
|
||||
});*/
|
||||
@ -123,7 +129,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
// automatic save
|
||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||
if(applicationLink != null) {
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
/*setState(() {
|
||||
|
||||
});*/
|
||||
@ -146,7 +152,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
// automatic save
|
||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||
if(applicationLink != null) {
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
/*setState(() {
|
||||
|
||||
});*/
|
||||
@ -169,7 +175,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
// automatic save
|
||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||
if(applicationLink != null) {
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
/*setState(() {
|
||||
|
||||
});*/
|
||||
@ -194,7 +200,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
// automatic save
|
||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||
if(applicationLink != null) {
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
/*setState(() {
|
||||
|
||||
});*/
|
||||
@ -222,7 +228,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
// automatic save
|
||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||
if(applicationLink != null) {
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
/*setState(() {
|
||||
|
||||
});*/
|
||||
@ -274,7 +280,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
// automatic save
|
||||
var applicationLink = await updateApplicationInstance(appContext, _applicationInstanceDTO);
|
||||
if(applicationLink != null) {
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
//setState(() {
|
||||
_applicationInstanceDTO.sectionEventDTO = applicationLink.sectionEventDTO;
|
||||
//_applicationInstanceDTO = applicationLink;
|
||||
@ -287,7 +293,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
),
|
||||
),
|
||||
// Assistant IA — visible uniquement si l'instance a la fonctionnalité
|
||||
if (managerAppContext.instanceDTO?.isAssistant == true)
|
||||
if (widget.showAssistant && managerAppContext.instanceDTO?.isAssistant == true)
|
||||
Container(
|
||||
width: elementWidth,
|
||||
height: elementHeight,
|
||||
@ -312,7 +318,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
localSetState(() {
|
||||
_applicationInstanceDTO.isAssistant = applicationLink.isAssistant;
|
||||
});
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
}
|
||||
} catch (e) {
|
||||
showNotification(kError, kWhite, AppLocalizations.of(context)!.errorOccurred, context, null);
|
||||
@ -328,8 +334,10 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -348,7 +356,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Text(AppLocalizations.of(context)!.phoneConfigTitle, style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
|
||||
child: Text(widget.configTitle ?? AppLocalizations.of(context)!.phoneConfigTitle, style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
|
||||
),
|
||||
appConfigurationLinks != null ? Padding(
|
||||
padding: const EdgeInsets.only(left: 32, right: 32, top: 75),
|
||||
@ -376,7 +384,7 @@ class _AppConfigurationLinkScreenState extends State<AppConfigurationLinkScreen>
|
||||
// TODO use order put method
|
||||
var result = await updateAppConfigurationOrder(appContext, updatedList);
|
||||
localSetState(() {});
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.appUpdatedSuccess, context, null);
|
||||
showNotification(kSuccess, kWhite, appUpdatedMsg, context, null);
|
||||
},
|
||||
actions: [
|
||||
(BuildContext context, int index, AppConfigurationLinkDTO link) {
|
||||
|
||||
194
lib/Screens/Applications/web_app_screen.dart
Normal file
194
lib/Screens/Applications/web_app_screen.dart
Normal file
@ -0,0 +1,194 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:manager_app/Screens/Applications/app_configuration_link_screen.dart';
|
||||
import 'package:manager_app/app_context.dart';
|
||||
import 'package:manager_app/Components/message_notification.dart';
|
||||
import 'package:manager_app/constants.dart';
|
||||
import 'package:manager_app/Models/managerContext.dart';
|
||||
import 'package:manager_api_new/api.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class WebInstanceLoader extends StatefulWidget {
|
||||
const WebInstanceLoader({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<WebInstanceLoader> createState() => _WebInstanceLoaderState();
|
||||
}
|
||||
|
||||
class _WebInstanceLoaderState extends State<WebInstanceLoader> {
|
||||
bool _creating = false;
|
||||
String? _error;
|
||||
ApplicationInstanceDTO? _instance;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _init());
|
||||
}
|
||||
|
||||
void _init() {
|
||||
final appContext = Provider.of<AppContext>(context, listen: false);
|
||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||
final existing = managerCtx.instanceDTO?.applicationInstanceDTOs
|
||||
?.firstWhereOrNull((ai) => ai.appType == AppType.Web);
|
||||
if (existing != null) {
|
||||
setState(() => _instance = existing);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _create() async {
|
||||
final appContext = Provider.of<AppContext>(context, listen: false);
|
||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||
final instanceDTO = managerCtx.instanceDTO!;
|
||||
|
||||
setState(() {
|
||||
_creating = true;
|
||||
_error = null;
|
||||
});
|
||||
|
||||
try {
|
||||
final newInstance = ApplicationInstanceDTO(
|
||||
instanceId: instanceDTO.id,
|
||||
appType: AppType.Web,
|
||||
languages: ['fr'],
|
||||
layoutMainPage: LayoutMainPageType.MasonryGrid,
|
||||
isAssistant: false,
|
||||
isStatistic: false,
|
||||
);
|
||||
|
||||
final created = await managerCtx.clientAPI!.applicationInstanceApi!
|
||||
.applicationInstanceCreate(newInstance);
|
||||
|
||||
if (created != null) {
|
||||
instanceDTO.applicationInstanceDTOs = [...?instanceDTO.applicationInstanceDTOs, created];
|
||||
setState(() => _instance = created);
|
||||
} else {
|
||||
setState(() => _error = 'La création a échoué (réponse vide)');
|
||||
}
|
||||
} catch (e) {
|
||||
setState(() => _error = e.toString());
|
||||
} finally {
|
||||
setState(() => _creating = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_instance != null) {
|
||||
return WebAppScreen(applicationInstanceDTO: _instance!);
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'L\'application web n\'est pas encore initialisée.',
|
||||
style: TextStyle(color: kBodyTextColor),
|
||||
),
|
||||
if (_error != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
Text(_error!, style: TextStyle(color: kError, fontSize: 12)),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
_creating
|
||||
? const CircularProgressIndicator()
|
||||
: ElevatedButton(
|
||||
onPressed: _create,
|
||||
child: const Text('Initialiser l\'application web'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WebAppScreen extends StatelessWidget {
|
||||
final ApplicationInstanceDTO applicationInstanceDTO;
|
||||
|
||||
const WebAppScreen({Key? key, required this.applicationInstanceDTO}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appContext = Provider.of<AppContext>(context);
|
||||
final managerAppContext = appContext.getContext() as ManagerAppContext;
|
||||
final instanceDTO = managerAppContext.instanceDTO;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (instanceDTO?.webSlug != null || instanceDTO?.publicApiKey != null)
|
||||
Card(
|
||||
margin: const EdgeInsets.fromLTRB(0, 0, 0, 8),
|
||||
color: kWhite,
|
||||
elevation: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Accès web', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
|
||||
const SizedBox(height: 12),
|
||||
_InfoRow(
|
||||
label: 'URL visiteurs',
|
||||
value: 'app.myinfomate.be/${instanceDTO?.webSlug ?? '—'}',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_InfoRow(
|
||||
label: 'Clé publique API',
|
||||
value: instanceDTO?.publicApiKey ?? '—',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: AppConfigurationLinkScreen(
|
||||
applicationInstanceDTO: applicationInstanceDTO,
|
||||
showAssistant: false,
|
||||
configTitle: 'Contenu de l\'application web',
|
||||
appUpdatedLabel: 'Application web mise à jour',
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _InfoRow extends StatelessWidget {
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
const _InfoRow({required this.label, required this.value});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: TextStyle(fontSize: 12, color: kBodyTextColor)),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
value,
|
||||
style: TextStyle(fontSize: 13, fontFamily: 'monospace', color: kPrimaryColor),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.copy_outlined, size: 18, color: kPrimaryColor),
|
||||
tooltip: 'Copier',
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: value));
|
||||
showNotification(kSuccess, kWhite, 'Copié !', context, null);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -431,13 +431,14 @@ class _EventConfigState extends State<EventConfig> {
|
||||
Divider(),
|
||||
// --- Parcours ---
|
||||
if (eventDTO.id != null)
|
||||
ParcoursConfig(
|
||||
initialValue: const [],
|
||||
parentId: eventDTO.id!,
|
||||
isEvent: true,
|
||||
onChanged: (paths) {
|
||||
// parcours are managed independently, no DTO update needed here
|
||||
},
|
||||
SizedBox(
|
||||
height: 500,
|
||||
child: ParcoursConfig(
|
||||
initialValue: const [],
|
||||
parentId: eventDTO.id!,
|
||||
isEvent: true,
|
||||
onChanged: (paths) {},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@ -25,112 +25,163 @@ void showEditSubSection(SectionDTO subSectionDTO, Function getResult, AppContext
|
||||
|
||||
Size size = MediaQuery.of(context).size;
|
||||
showDialog(
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
builder: (BuildContext context) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
content: Container(
|
||||
width: size.width *0.85,
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.85,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Modifier sous section", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: StringInputContainer(
|
||||
label: "Nom :",
|
||||
initialValue: subSectionDTO.label,
|
||||
onChanged: (String name) {
|
||||
subSectionDTO.label = name;
|
||||
},
|
||||
),
|
||||
),
|
||||
ResourceInputContainer(
|
||||
label: "Image :",
|
||||
initialValue: subSectionDTO.imageId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if(resource.id == null) {
|
||||
subSectionDTO.imageId = null;
|
||||
subSectionDTO.imageSource = null;
|
||||
} else {
|
||||
subSectionDTO.imageId = resource.id;
|
||||
subSectionDTO.imageSource = resource.url;
|
||||
}
|
||||
},
|
||||
isSmall: true,
|
||||
Text("Modifier sous section", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: StringInputContainer(
|
||||
label: "Nom :",
|
||||
initialValue: subSectionDTO.label,
|
||||
onChanged: (String name) {
|
||||
subSectionDTO.label = name;
|
||||
},
|
||||
),
|
||||
),
|
||||
ResourceInputContainer(
|
||||
label: "Image :",
|
||||
initialValue: subSectionDTO.imageId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if(resource.id == null) {
|
||||
subSectionDTO.imageId = null;
|
||||
subSectionDTO.imageSource = null;
|
||||
} else {
|
||||
subSectionDTO.imageId = resource.id;
|
||||
subSectionDTO.imageSource = resource.url;
|
||||
}
|
||||
},
|
||||
isSmall: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: size.height * 0.1,
|
||||
width: double.infinity,
|
||||
constraints: BoxConstraints(minHeight: 50),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayTitleLabel,
|
||||
modalLabel: "Titre",
|
||||
fontSize: 20,
|
||||
isHTML: true,
|
||||
color: kPrimaryColor,
|
||||
initialValue: subSectionDTO.title != null ? subSectionDTO.title! : [],
|
||||
onGetResult: (value) {
|
||||
if (subSectionDTO.title != value) {
|
||||
subSectionDTO.title = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: true
|
||||
),
|
||||
),
|
||||
Container(
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayedDescriptionLabel,
|
||||
modalLabel: "Description",
|
||||
fontSize: 20,
|
||||
isHTML: true,
|
||||
color: kPrimaryColor,
|
||||
initialValue: subSectionDTO.description != null ? subSectionDTO.description! : [],
|
||||
isMandatory: false,
|
||||
onGetResult: (value) {
|
||||
if (subSectionDTO.description != value) {
|
||||
subSectionDTO.description = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: false
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: kWhite,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(width: 0.5, color: kSecond)
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: getSpecificData(
|
||||
subSectionDTO,
|
||||
rawSubSectionData,
|
||||
rawSubSectionData,
|
||||
appContext,
|
||||
(updatedData) {
|
||||
updatedRawSubSectionData = updatedData;
|
||||
}, context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: size.height * 0.1,
|
||||
width: double.infinity,
|
||||
constraints: BoxConstraints(minHeight: 50),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayTitleLabel,
|
||||
modalLabel: "Titre",
|
||||
fontSize: 20,
|
||||
isHTML: true,
|
||||
color: kPrimaryColor,
|
||||
initialValue: subSectionDTO.title != null ? subSectionDTO.title! : [],
|
||||
onGetResult: (value) {
|
||||
if (subSectionDTO.title != value) {
|
||||
subSectionDTO.title = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: true
|
||||
),
|
||||
),
|
||||
Container(
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayedDescriptionLabel,
|
||||
modalLabel: "Description",
|
||||
fontSize: 20,
|
||||
isHTML: true,
|
||||
color: kPrimaryColor,
|
||||
initialValue: subSectionDTO.description != null ? subSectionDTO.description! : [],
|
||||
isMandatory: false,
|
||||
onGetResult: (value) {
|
||||
if (subSectionDTO.description != value) {
|
||||
subSectionDTO.description = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: false
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: kWhite,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(width: 0.5, color: kSecond)
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: getSpecificData(
|
||||
subSectionDTO,
|
||||
rawSubSectionData,
|
||||
rawSubSectionData,
|
||||
appContext,
|
||||
(updatedData) {
|
||||
updatedRawSubSectionData = updatedData;
|
||||
}, context),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: subSectionDTO != null ? 220: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Sauvegarder",
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
getResult(updatedRawSubSectionData);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -139,47 +190,6 @@ void showEditSubSection(SectionDTO subSectionDTO, Function getResult, AppContext
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: subSectionDTO != null ? 220: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Sauvegarder",
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
getResult(updatedRawSubSectionData);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
), context: context
|
||||
);
|
||||
}
|
||||
|
||||
@ -45,109 +45,119 @@ Future<OrderedTranslationAndResourceDTO?> showNewOrUpdatePDFFile(OrderedTranslat
|
||||
|
||||
Size size = MediaQuery.of(context).size;
|
||||
var result = await showDialog(
|
||||
builder: (BuildContext dialogContext) => AlertDialog(
|
||||
builder: (BuildContext dialogContext) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
content: Container(
|
||||
width: size.width *0.5,
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: 560,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(text, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(text, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
height: size.height * 0.2,
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: MultiStringInputAndResourceContainer(
|
||||
label: "Fichier et titre pdf :",
|
||||
modalLabel: "Fichier et titre pdf",
|
||||
fontSize: 20,
|
||||
color: kPrimaryColor,
|
||||
initialValue: pdfFileDTO.translationAndResourceDTOs != null ? pdfFileDTO.translationAndResourceDTOs! : [],
|
||||
resourceTypes: [ResourceType.Pdf],
|
||||
onGetResult: (value) {
|
||||
if (pdfFileDTO.translationAndResourceDTOs != value) {
|
||||
pdfFileDTO.translationAndResourceDTOs = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: true
|
||||
),
|
||||
),
|
||||
/*Container(
|
||||
height: size.height * 0.2,
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: ResourceInputContainer(
|
||||
label: AppLocalizations.of(context)!.categoryIconLabel,
|
||||
initialValue: categorieDTO.iconResourceId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if(resource.id == null) {
|
||||
categorieDTO.iconResourceId = null;
|
||||
categorieDTO.iconUrl = null;
|
||||
} else {
|
||||
categorieDTO.iconResourceId = resource.id;
|
||||
categorieDTO.iconUrl = resource.url;
|
||||
print("Icône catégorieIcône catégorie");
|
||||
print(categorieDTO);
|
||||
}
|
||||
},
|
||||
isSmall: true
|
||||
),
|
||||
),*/
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
height: size.height * 0.2,
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: MultiStringInputAndResourceContainer(
|
||||
label: "Fichier et titre pdf :",
|
||||
modalLabel: "Fichier et titre pdf",
|
||||
fontSize: 20,
|
||||
color: kPrimaryColor,
|
||||
initialValue: pdfFileDTO.translationAndResourceDTOs != null ? pdfFileDTO.translationAndResourceDTOs! : [],
|
||||
resourceTypes: [ResourceType.Pdf],
|
||||
onGetResult: (value) {
|
||||
if (pdfFileDTO.translationAndResourceDTOs != value) {
|
||||
pdfFileDTO.translationAndResourceDTOs = value;
|
||||
}
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.pop(dialogContext);
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: true
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
/*Container(
|
||||
height: size.height * 0.2,
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: ResourceInputContainer(
|
||||
label: AppLocalizations.of(context)!.categoryIconLabel,
|
||||
initialValue: categorieDTO.iconResourceId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if(resource.id == null) {
|
||||
categorieDTO.iconResourceId = null;
|
||||
categorieDTO.iconUrl = null;
|
||||
} else {
|
||||
categorieDTO.iconResourceId = resource.id;
|
||||
categorieDTO.iconUrl = resource.url;
|
||||
print("Icône catégorieIcône catégorie");
|
||||
print(categorieDTO);
|
||||
}
|
||||
},
|
||||
isSmall: true
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: inputPdfFile != null ? 220: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: inputPdfFile != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if(pdfFileDTO.translationAndResourceDTOs != null && pdfFileDTO.translationAndResourceDTOs!.isNotEmpty)
|
||||
{
|
||||
Navigator.pop(dialogContext, pdfFileDTO);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),*/
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.pop(dialogContext);
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: inputPdfFile != null ? 220: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: inputPdfFile != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if(pdfFileDTO.translationAndResourceDTOs != null && pdfFileDTO.translationAndResourceDTOs!.isNotEmpty)
|
||||
{
|
||||
Navigator.pop(dialogContext, pdfFileDTO);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
), context: context
|
||||
);
|
||||
return result;
|
||||
|
||||
@ -34,88 +34,142 @@ Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO,
|
||||
|
||||
Size size = MediaQuery.of(context).size;
|
||||
var result = await showDialog(
|
||||
builder: (BuildContext dialogContext) => AlertDialog(
|
||||
builder: (BuildContext dialogContext) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
content: Container(
|
||||
width: size.width *0.5,
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: 560,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(text, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: size.height*0.25,
|
||||
constraints: BoxConstraints(minHeight: 100, maxHeight: 150),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
ResourceInputContainer(
|
||||
label: AppLocalizations.of(context)!.backgroundImageLabel,
|
||||
initialValue: questionDTO.imageBackgroundResourceId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if(resource.id == null) {
|
||||
questionDTO.imageBackgroundResourceId = null;
|
||||
questionDTO.imageBackgroundResourceUrl = null;
|
||||
questionDTO.imageBackgroundResourceType = null;
|
||||
} else {
|
||||
questionDTO.imageBackgroundResourceId = resource.id;
|
||||
questionDTO.imageBackgroundResourceUrl = resource.url;
|
||||
questionDTO.imageBackgroundResourceType = resource.type;
|
||||
}
|
||||
},
|
||||
isSmall: true
|
||||
),
|
||||
Container(
|
||||
//color: Colors.orangeAccent,
|
||||
height: size.height * 0.15,
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: MultiStringInputAndResourceContainer(
|
||||
label: AppLocalizations.of(context)!.questionInputLabel,
|
||||
modalLabel: AppLocalizations.of(context)!.questionLabel,
|
||||
fontSize: 20,
|
||||
color: kPrimaryColor,
|
||||
resourceTypes: [ResourceType.Image, ResourceType.ImageUrl, ResourceType.Video, ResourceType.VideoUrl, ResourceType.Audio],
|
||||
initialValue: questionDTO.label != null ? questionDTO.label! : [],
|
||||
onGetResult: (value) {
|
||||
if (questionDTO.label != value) {
|
||||
questionDTO.label = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: true
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(text, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: size.height*0.25,
|
||||
constraints: BoxConstraints(minHeight: 100, maxHeight: 150),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
ResourceInputContainer(
|
||||
label: AppLocalizations.of(context)!.backgroundImageLabel,
|
||||
initialValue: questionDTO.imageBackgroundResourceId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if(resource.id == null) {
|
||||
questionDTO.imageBackgroundResourceId = null;
|
||||
questionDTO.imageBackgroundResourceUrl = null;
|
||||
questionDTO.imageBackgroundResourceType = null;
|
||||
} else {
|
||||
questionDTO.imageBackgroundResourceId = resource.id;
|
||||
questionDTO.imageBackgroundResourceUrl = resource.url;
|
||||
questionDTO.imageBackgroundResourceType = resource.type;
|
||||
}
|
||||
},
|
||||
isSmall: true
|
||||
),
|
||||
Container(
|
||||
//color: Colors.orangeAccent,
|
||||
height: size.height * 0.15,
|
||||
constraints: BoxConstraints(minHeight: 50, maxHeight: 80),
|
||||
child: MultiStringInputAndResourceContainer(
|
||||
label: AppLocalizations.of(context)!.questionInputLabel,
|
||||
modalLabel: AppLocalizations.of(context)!.questionLabel,
|
||||
fontSize: 20,
|
||||
color: kPrimaryColor,
|
||||
resourceTypes: [ResourceType.Image, ResourceType.ImageUrl, ResourceType.Video, ResourceType.VideoUrl, ResourceType.Audio],
|
||||
initialValue: questionDTO.label != null ? questionDTO.label! : [],
|
||||
onGetResult: (value) {
|
||||
if (questionDTO.label != value) {
|
||||
questionDTO.label = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: true
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Container(
|
||||
height: size.height * 0.33,
|
||||
decoration: BoxDecoration(
|
||||
color: kWhite,
|
||||
//color: Colors.green,
|
||||
shape: BoxShape.rectangle,
|
||||
border: Border.all(width: 1.5, color: kSecond),
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
child: QuizzResponseList(
|
||||
responses: questionDTO.responses!,
|
||||
onChanged: (List<ResponseDTO> responsesOutput) {
|
||||
questionDTO.responses = responsesOutput;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.cancel,
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.pop(dialogContext);
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: size.height * 0.33,
|
||||
decoration: BoxDecoration(
|
||||
color: kWhite,
|
||||
//color: Colors.green,
|
||||
shape: BoxShape.rectangle,
|
||||
border: Border.all(width: 1.5, color: kSecond),
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
child: QuizzResponseList(
|
||||
responses: questionDTO.responses!,
|
||||
onChanged: (List<ResponseDTO> responsesOutput) {
|
||||
questionDTO.responses = responsesOutput;
|
||||
},
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: inputQuestionDTO != null ? 220: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: inputQuestionDTO != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if(!questionDTO.label!.any((label) => label.value == null || label.value!.trim() == "")) {
|
||||
Navigator.pop(dialogContext, questionDTO);
|
||||
} else {
|
||||
showNotification(kPrimaryColor, kWhite, AppLocalizations.of(context)!.translationIncomplete, context, null);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -124,50 +178,6 @@ Future<QuestionDTO?> showNewOrUpdateQuestionQuizz(QuestionDTO? inputQuestionDTO,
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.cancel,
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.pop(dialogContext);
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: inputQuestionDTO != null ? 220: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: inputQuestionDTO != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if(!questionDTO.label!.any((label) => label.value == null || label.value!.trim() == "")) {
|
||||
Navigator.pop(dialogContext, questionDTO);
|
||||
} else {
|
||||
showNotification(kPrimaryColor, kWhite, AppLocalizations.of(context)!.translationIncomplete, context, null);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
), context: context
|
||||
);
|
||||
return result;
|
||||
|
||||
@ -34,129 +34,138 @@ Future<ContentDTO?> showNewOrUpdateContentSlider(ContentDTO? inputContentDTO, Ap
|
||||
|
||||
Size size = MediaQuery.of(context).size;
|
||||
var result = await showDialog(
|
||||
builder: (BuildContext dialogContext) => AlertDialog(
|
||||
builder: (BuildContext dialogContext) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
content: Container(
|
||||
width: size.width *0.35,
|
||||
constraints: BoxConstraints(minWidth: 300),
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: 480,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Ressource", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text("Ressource", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Center(
|
||||
child: ResourceInputContainer(
|
||||
label: "Ressource :",
|
||||
initialValue: contentDTO.resourceId,
|
||||
color: kPrimaryColor,
|
||||
fontSize: 20,
|
||||
inResourceTypes: [ResourceType.Image, ResourceType.ImageUrl, ResourceType.Video, ResourceType.VideoUrl, ResourceType.Audio],
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if(resource.id == null) {
|
||||
contentDTO.resourceId = null;
|
||||
contentDTO.resource = null;
|
||||
} else {
|
||||
contentDTO.resourceId = resource.id;
|
||||
contentDTO.resource = resource;
|
||||
}
|
||||
},
|
||||
isSmall: true
|
||||
),
|
||||
),
|
||||
if(showTitle || showDescription)
|
||||
Container(
|
||||
height: size.height * 0.3,
|
||||
width: double.infinity,
|
||||
constraints: BoxConstraints(minHeight: 200),
|
||||
child: Column(
|
||||
children: [
|
||||
MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayTitleLabel,
|
||||
modalLabel: "Titre",
|
||||
fontSize: 20,
|
||||
isHTML: true,
|
||||
color: kPrimaryColor,
|
||||
initialValue: contentDTO.title != null ? contentDTO.title! : [],
|
||||
onGetResult: (value) {
|
||||
if (contentDTO.title != value) {
|
||||
contentDTO.title = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: true
|
||||
),
|
||||
MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayedDescriptionLabel,
|
||||
modalLabel: "Description",
|
||||
fontSize: 20,
|
||||
isHTML: true,
|
||||
color: kPrimaryColor,
|
||||
initialValue: contentDTO.description != null ? contentDTO.description! : [],
|
||||
isMandatory: false,
|
||||
onGetResult: (value) {
|
||||
if (contentDTO.description != value) {
|
||||
contentDTO.description = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: false
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Center(
|
||||
child: ResourceInputContainer(
|
||||
label: "Ressource :",
|
||||
initialValue: contentDTO.resourceId,
|
||||
color: kPrimaryColor,
|
||||
fontSize: 20,
|
||||
inResourceTypes: [ResourceType.Image, ResourceType.ImageUrl, ResourceType.Video, ResourceType.VideoUrl, ResourceType.Audio],
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if(resource.id == null) {
|
||||
contentDTO.resourceId = null;
|
||||
contentDTO.resource = null;
|
||||
} else {
|
||||
contentDTO.resourceId = resource.id;
|
||||
contentDTO.resource = resource;
|
||||
}
|
||||
},
|
||||
isSmall: true
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.pop(dialogContext);
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
if(showTitle || showDescription)
|
||||
Container(
|
||||
height: size.height * 0.3,
|
||||
width: double.infinity,
|
||||
constraints: BoxConstraints(minHeight: 200),
|
||||
child: Column(
|
||||
children: [
|
||||
MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayTitleLabel,
|
||||
modalLabel: "Titre",
|
||||
fontSize: 20,
|
||||
isHTML: true,
|
||||
color: kPrimaryColor,
|
||||
initialValue: contentDTO.title != null ? contentDTO.title! : [],
|
||||
onGetResult: (value) {
|
||||
if (contentDTO.title != value) {
|
||||
contentDTO.title = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: true
|
||||
),
|
||||
MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayedDescriptionLabel,
|
||||
modalLabel: "Description",
|
||||
fontSize: 20,
|
||||
isHTML: true,
|
||||
color: kPrimaryColor,
|
||||
initialValue: contentDTO.description != null ? contentDTO.description! : [],
|
||||
isMandatory: false,
|
||||
onGetResult: (value) {
|
||||
if (contentDTO.description != value) {
|
||||
contentDTO.description = value;
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isTitle: false
|
||||
),
|
||||
],
|
||||
)
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: inputContentDTO != null ? 220: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: inputContentDTO != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if (contentDTO.resourceId != null) {
|
||||
Navigator.pop(dialogContext, contentDTO);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.pop(dialogContext);
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: inputContentDTO != null ? 220: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: inputContentDTO != null ? AppLocalizations.of(context)!.save : AppLocalizations.of(context)!.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if (contentDTO.resourceId != null) {
|
||||
Navigator.pop(dialogContext, contentDTO);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
), context: context
|
||||
);
|
||||
|
||||
|
||||
@ -68,6 +68,7 @@ class _SliderConfigState extends State<SliderConfig> {
|
||||
children: [
|
||||
Container(
|
||||
width: size.width * 0.95,
|
||||
height: 300,
|
||||
child: ReorderableListView(
|
||||
onReorder: _onReorder,
|
||||
scrollDirection: Axis.horizontal,
|
||||
|
||||
@ -13,7 +13,6 @@ 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/number_input_container.dart';
|
||||
import 'package:manager_app/Components/rounded_button.dart';
|
||||
import 'package:manager_app/Components/string_input_container.dart';
|
||||
import 'package:manager_app/Models/managerContext.dart';
|
||||
import 'package:manager_app/Screens/Configurations/Section/SubSection/Video/video_config.dart';
|
||||
@ -82,366 +81,351 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appContext = Provider.of<AppContext>(context);
|
||||
Size size = MediaQuery.of(context).size;
|
||||
|
||||
Object? rawSectionData;
|
||||
|
||||
return FutureBuilder(
|
||||
future: _sectionFuture,
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
rawSectionData = snapshot.data;
|
||||
future: _sectionFuture,
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
Object? rawSectionData = snapshot.data;
|
||||
var nullableSection = SectionDTO.fromJson(rawSectionData);
|
||||
|
||||
var nullableSection = SectionDTO.fromJson(rawSectionData);
|
||||
if (nullableSection != null) {
|
||||
sectionDTO = nullableSection;
|
||||
|
||||
if (nullableSection != null) {
|
||||
sectionDTO = nullableSection;
|
||||
|
||||
// Only initialize sectionDetailDTO if it's not already loaded for this section
|
||||
if (sectionDetailDTO == null ||
|
||||
lastLoadedSectionId != widget.id) {
|
||||
_initializeSectionDetail(rawSectionData);
|
||||
lastLoadedSectionId = widget.id;
|
||||
}
|
||||
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
bodySection(
|
||||
rawSectionData, size, appContext, context),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
child: Container(
|
||||
height: 80,
|
||||
child: getButtons(sectionDTO, appContext),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Center(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.sectionLoadError));
|
||||
if (sectionDetailDTO == null || lastLoadedSectionId != widget.id) {
|
||||
_initializeSectionDetail(rawSectionData);
|
||||
lastLoadedSectionId = widget.id;
|
||||
}
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Text(AppLocalizations.of(context)!.noData);
|
||||
|
||||
return _buildBody(rawSectionData, appContext);
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: size.height * 0.2, child: CommonLoader()));
|
||||
return Center(child: Text(AppLocalizations.of(context)!.sectionLoadError));
|
||||
}
|
||||
});
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Center(child: Text(AppLocalizations.of(context)!.noData));
|
||||
}
|
||||
return const Center(child: CommonLoader());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget bodySection(Object? rawSectionDTO, Size size, AppContext appContext,
|
||||
BuildContext context) {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
//SectionDTO? sectionDTO = SectionDTO.fromJson(rawSectionDTO);
|
||||
// ── Main layout ──
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
//mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
//color: Colors.orangeAccent,
|
||||
height: 82,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
Widget _buildBody(Object? rawSectionData, AppContext appContext) {
|
||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||
final canEdit = managerCtx.canEdit;
|
||||
final l = AppLocalizations.of(context)!;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
_buildHeader(appContext, l),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomStart,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
getSectionIcon(sectionDTO.type),
|
||||
color: kPrimaryColor,
|
||||
size: 25,
|
||||
),
|
||||
),
|
||||
Text(sectionDTO.label!,
|
||||
style: TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.w400)),
|
||||
//if((appContext.getContext() as ManagerAppContext).selectedConfiguration!.isMobile!)
|
||||
DownloadPDF(sections: [sectionDTO]),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Text(
|
||||
DateFormat('dd/MM/yyyy')
|
||||
.format(sectionDTO.dateCreation!),
|
||||
style: TextStyle(
|
||||
fontSize: 15, fontWeight: FontWeight.w200)),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
ManagerAppContext managerAppContext =
|
||||
appContext.getContext();
|
||||
managerAppContext.selectedSection = null;
|
||||
appContext.setContext(managerAppContext);
|
||||
},
|
||||
child: Container(
|
||||
child: Icon(
|
||||
Icons.arrow_back,
|
||||
color: kPrimaryColor,
|
||||
size: 50.0,
|
||||
))),
|
||||
),
|
||||
)
|
||||
_cardIdentity(appContext, l),
|
||||
const SizedBox(height: 12),
|
||||
_cardQR(appContext, l),
|
||||
const SizedBox(height: 12),
|
||||
_cardTypeConfig(rawSectionData, appContext),
|
||||
const SizedBox(height: 80),
|
||||
],
|
||||
),
|
||||
), // TITLE
|
||||
Container(
|
||||
//color: Colors.blue,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Container(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
//if((appContext.getContext() as ManagerAppContext).selectedConfiguration!.isMobile!)
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
var image = await _captureAndSharePng(
|
||||
globalKey, sectionDTO.id!);
|
||||
await readAndWriteFiles(image);
|
||||
showNotification(
|
||||
kSuccess,
|
||||
kWhite,
|
||||
AppLocalizations.of(context)!.qrCodeCopied,
|
||||
context,
|
||||
null);
|
||||
},
|
||||
child: Container(
|
||||
width: size.width * 0.1,
|
||||
height: 125,
|
||||
child: RepaintBoundary(
|
||||
key: globalKey,
|
||||
child: QrImageView(
|
||||
padding: EdgeInsets.only(
|
||||
left: 5.0,
|
||||
top: 5.0,
|
||||
bottom: 5.0,
|
||||
right: 5.0),
|
||||
data:
|
||||
"${managerAppContext.host!.replaceFirst("api", "web")}/${managerAppContext.instanceId}/${managerAppContext.selectedConfiguration!.id}/${sectionDTO.id!}",
|
||||
version: QrVersions.auto,
|
||||
size: 50.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SelectableText(sectionDTO.id!,
|
||||
style: new TextStyle(fontSize: 15))
|
||||
],
|
||||
),
|
||||
CheckInputContainer(
|
||||
label: AppLocalizations.of(context)!.beaconLabel,
|
||||
isChecked: sectionDTO.isBeacon!,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
sectionDTO.isBeacon = value;
|
||||
save(false, appContext);
|
||||
});
|
||||
},
|
||||
),
|
||||
if (sectionDTO.isBeacon!)
|
||||
NumberInputContainer(
|
||||
label: AppLocalizations.of(context)!.beaconIdLabel,
|
||||
initialValue: sectionDTO.beaconId != null
|
||||
? sectionDTO.beaconId!
|
||||
: 0,
|
||||
isSmall: true,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
sectionDTO.beaconId = int.parse(value);
|
||||
} catch (e) {
|
||||
print('BeaconId not a number');
|
||||
showNotification(
|
||||
Colors.orange,
|
||||
kWhite,
|
||||
AppLocalizations.of(context)!.beaconMustBeNumber,
|
||||
context,
|
||||
null);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: StringInputContainer(
|
||||
label: AppLocalizations.of(context)!.identifierLabel,
|
||||
initialValue: sectionDTO.label,
|
||||
onChanged: (String value) {
|
||||
sectionDTO.label = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: MultiStringInputContainer(
|
||||
label: AppLocalizations.of(context)!.displayTitleLabel,
|
||||
modalLabel: AppLocalizations.of(context)!.messageTitle,
|
||||
color: kPrimaryColor,
|
||||
initialValue: sectionDTO.title!,
|
||||
onGetResult: (value) {
|
||||
if (sectionDTO.title! != value) {
|
||||
sectionDTO.title = value;
|
||||
save(true, appContext);
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isHTML: true,
|
||||
isTitle: true,
|
||||
),
|
||||
),
|
||||
/*if(!(appContext.getContext() as ManagerAppContext).selectedConfiguration!.isMobile!)
|
||||
MultiStringInputContainer(
|
||||
label: "Description affichée:",
|
||||
modalLabel: "Description",
|
||||
color: kPrimaryColor,
|
||||
isHTML: true,
|
||||
initialValue: sectionDTO.description!,
|
||||
isMandatory: false,
|
||||
onGetResult: (value) {
|
||||
if (sectionDTO.description != value) {
|
||||
sectionDTO.description = value!;
|
||||
save(true, appContext);
|
||||
}
|
||||
},
|
||||
maxLines: 2,
|
||||
isTitle: true,
|
||||
),*/
|
||||
],
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ResourceInputContainer(
|
||||
label: AppLocalizations.of(context)!.imageLabel,
|
||||
initialValue: sectionDTO.imageId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if (resource.id == null) {
|
||||
sectionDTO.imageId = null;
|
||||
sectionDTO.imageSource = null;
|
||||
} else {
|
||||
sectionDTO.imageId = resource.id;
|
||||
sectionDTO.imageSource = resource.url;
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
), // FIELDS SECTION
|
||||
Container(
|
||||
//width: size.width * 0.8,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: getSpecificData(rawSectionDTO, appContext),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
//color: Colors.lightGreen,
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
border: Border.all(width: 1.5, color: kSecond)),
|
||||
),
|
||||
),
|
||||
_buildFooter(appContext, canEdit, l),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// ── Header ──
|
||||
|
||||
Widget _buildHeader(AppContext appContext, AppLocalizations l) {
|
||||
final typeName = sectionDTO.type?.toString().split('.').last ?? '';
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: kWhite,
|
||||
border: Border(bottom: BorderSide(color: kSecond, width: 1)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: kPrimaryColor),
|
||||
onPressed: () {
|
||||
ManagerAppContext ctx = appContext.getContext();
|
||||
ctx.selectedSection = null;
|
||||
appContext.setContext(ctx);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(getSectionIcon(sectionDTO.type), color: kPrimaryColor, size: 22),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
sectionDTO.label ?? '',
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
Text(
|
||||
DateFormat('dd/MM/yyyy').format(sectionDTO.dateCreation!),
|
||||
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w300, color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Chip(
|
||||
label: Text(typeName.toUpperCase()),
|
||||
backgroundColor: kPrimaryColor.withValues(alpha: 0.1),
|
||||
labelStyle: const TextStyle(color: kPrimaryColor, fontWeight: FontWeight.w600, fontSize: 11),
|
||||
side: BorderSide.none,
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
DownloadPDF(sections: [sectionDTO]),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
getButtons(SectionDTO sectionDTO, AppContext appContext) {
|
||||
final canEdit = (appContext.getContext() as ManagerAppContext).canEdit;
|
||||
return Align(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
// ── Footer ──
|
||||
|
||||
Widget _buildFooter(AppContext appContext, bool canEdit, AppLocalizations l) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
decoration: const BoxDecoration(
|
||||
color: kWhite,
|
||||
boxShadow: [BoxShadow(color: kSecond, blurRadius: 8, offset: Offset(0, -2))],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.cancel,
|
||||
icon: Icons.undo,
|
||||
color: Colors.grey,
|
||||
textColor: Colors.white,
|
||||
fontSize: 15,
|
||||
press: () {
|
||||
cancel(appContext);
|
||||
},
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
icon: const Icon(Icons.undo, size: 16),
|
||||
label: Text(l.cancel),
|
||||
onPressed: () => cancel(appContext),
|
||||
),
|
||||
if (canEdit) Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.delete,
|
||||
icon: Icons.delete,
|
||||
color: kError,
|
||||
textColor: Colors.white,
|
||||
fontSize: 15,
|
||||
press: () {
|
||||
delete(appContext);
|
||||
},
|
||||
if (canEdit) ...[
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton.icon(
|
||||
icon: const Icon(Icons.delete, size: 16, color: kWhite),
|
||||
label: Text(l.delete, style: const TextStyle(color: kWhite)),
|
||||
style: ElevatedButton.styleFrom(backgroundColor: kError),
|
||||
onPressed: () => delete(appContext),
|
||||
),
|
||||
),
|
||||
if (canEdit) Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.save,
|
||||
icon: Icons.done,
|
||||
color: kSuccess,
|
||||
textColor: Colors.white,
|
||||
fontSize: 15,
|
||||
press: () {
|
||||
save(false, appContext);
|
||||
},
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton.icon(
|
||||
icon: const Icon(Icons.done, size: 16, color: kWhite),
|
||||
label: Text(l.save, style: const TextStyle(color: kWhite)),
|
||||
style: ElevatedButton.styleFrom(backgroundColor: kPrimaryColor),
|
||||
onPressed: () => save(false, appContext),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Card Identité ──
|
||||
|
||||
Widget _cardIdentity(AppContext appContext, AppLocalizations l) {
|
||||
return Card(
|
||||
elevation: 0,
|
||||
color: kWhite,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l.identifierLabel.replaceAll(':', '').trim(),
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: kTitleTextColor)),
|
||||
const SizedBox(height: 12),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final isWide = constraints.maxWidth > kBreakpointMobile;
|
||||
|
||||
final fields = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
StringInputContainer(
|
||||
label: l.identifierLabel,
|
||||
initialValue: sectionDTO.label,
|
||||
onChanged: (String value) => sectionDTO.label = value,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
MultiStringInputContainer(
|
||||
label: l.displayTitleLabel,
|
||||
modalLabel: l.messageTitle,
|
||||
color: kPrimaryColor,
|
||||
initialValue: sectionDTO.title!,
|
||||
onGetResult: (value) {
|
||||
if (sectionDTO.title! != value) {
|
||||
sectionDTO.title = value;
|
||||
save(true, appContext);
|
||||
}
|
||||
},
|
||||
maxLines: 1,
|
||||
isHTML: true,
|
||||
isTitle: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
final image = ResourceInputContainer(
|
||||
label: l.imageLabel,
|
||||
initialValue: sectionDTO.imageId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if (resource.id == null) {
|
||||
sectionDTO.imageId = null;
|
||||
sectionDTO.imageSource = null;
|
||||
} else {
|
||||
sectionDTO.imageId = resource.id;
|
||||
sectionDTO.imageSource = resource.url;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (isWide) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(flex: 3, child: fields),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(flex: 2, child: image),
|
||||
],
|
||||
);
|
||||
}
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
fields,
|
||||
const SizedBox(height: 12),
|
||||
image,
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Card QR / Beacon ──
|
||||
|
||||
Widget _cardQR(AppContext appContext, AppLocalizations l) {
|
||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||
final qrData = "${managerCtx.host!.replaceFirst("api", "web")}/${managerCtx.instanceId}/${managerCtx.selectedConfiguration!.id}/${sectionDTO.id!}";
|
||||
|
||||
return Card(
|
||||
elevation: 0,
|
||||
color: kWhite,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
child: Theme(
|
||||
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
|
||||
child: ExpansionTile(
|
||||
leading: const Icon(Icons.qr_code_2, color: kPrimaryColor),
|
||||
title: const Text("QR Code / Identifiant",
|
||||
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: kTitleTextColor)),
|
||||
childrenPadding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: 24,
|
||||
runSpacing: 12,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
var image = await _captureAndSharePng(globalKey, sectionDTO.id!);
|
||||
await readAndWriteFiles(image);
|
||||
if (context.mounted) {
|
||||
showNotification(kSuccess, kWhite, l.qrCodeCopied, context, null);
|
||||
}
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 120,
|
||||
height: 120,
|
||||
child: RepaintBoundary(
|
||||
key: globalKey,
|
||||
child: QrImageView(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
data: qrData,
|
||||
version: QrVersions.auto,
|
||||
size: 50.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SelectableText(sectionDTO.id!, style: const TextStyle(fontSize: 13)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
CheckInputContainer(
|
||||
label: l.beaconLabel,
|
||||
isChecked: sectionDTO.isBeacon!,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
sectionDTO.isBeacon = value;
|
||||
save(false, appContext);
|
||||
});
|
||||
},
|
||||
),
|
||||
if (sectionDTO.isBeacon!)
|
||||
NumberInputContainer(
|
||||
label: l.beaconIdLabel,
|
||||
initialValue: sectionDTO.beaconId ?? 0,
|
||||
isSmall: true,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
sectionDTO.beaconId = int.parse(value);
|
||||
} catch (e) {
|
||||
showNotification(Colors.orange, kWhite, l.beaconMustBeNumber, context, null);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Card Type Config ──
|
||||
|
||||
Widget _cardTypeConfig(Object? rawSectionData, AppContext appContext) {
|
||||
final typeName = sectionDTO.type?.toString().split('.').last ?? 'Section';
|
||||
return Card(
|
||||
elevation: 0,
|
||||
color: kWhite,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("Configuration $typeName",
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: kTitleTextColor)),
|
||||
const SizedBox(height: 12),
|
||||
getSpecificData(rawSectionData, appContext),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Actions ──
|
||||
|
||||
Future<void> cancel(AppContext appContext) async {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
Object? rawData = await (appContext.getContext() as ManagerAppContext)
|
||||
@ -480,18 +464,16 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
appContext.setContext(managerAppContext);
|
||||
|
||||
if (isTraduction) {
|
||||
showNotification(
|
||||
kSuccess,
|
||||
kWhite,
|
||||
AppLocalizations.of(context)!.sectionTranslationSaved,
|
||||
context,
|
||||
null);
|
||||
showNotification(kSuccess, kWhite,
|
||||
AppLocalizations.of(context)!.sectionTranslationSaved, context, null);
|
||||
} else {
|
||||
showNotification(kSuccess, kWhite,
|
||||
AppLocalizations.of(context)!.sectionSavedSuccess, context, null);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Type-specific config widget ──
|
||||
|
||||
getSpecificData(Object? rawSectionData, AppContext appContext) {
|
||||
switch (sectionDTO.type) {
|
||||
case SectionType.Map:
|
||||
@ -527,9 +509,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
case SectionType.Menu:
|
||||
return MenuConfig(
|
||||
initialValue: sectionDetailDTO as MenuDTO,
|
||||
onChanged: (String data) {
|
||||
//sectionDTO.data = data;
|
||||
},
|
||||
onChanged: (String data) {},
|
||||
);
|
||||
case SectionType.Quiz:
|
||||
return QuizzConfig(
|
||||
@ -584,6 +564,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Section detail initialization ──
|
||||
|
||||
_initializeSectionDetail(Object? rawSectionData) {
|
||||
if (rawSectionData == null) return;
|
||||
switch (sectionDTO.type) {
|
||||
@ -626,6 +608,8 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Sync sectionDTO fields back to detail DTO before save ──
|
||||
|
||||
updateSectionDetail() {
|
||||
switch (sectionDTO.type) {
|
||||
case SectionType.Map:
|
||||
@ -634,8 +618,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as MapDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as MapDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as MapDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as MapDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as MapDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as MapDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as MapDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as MapDTO).label = sectionDTO.label;
|
||||
@ -655,8 +638,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as SliderDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as SliderDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as SliderDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as SliderDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as SliderDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as SliderDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as SliderDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as SliderDTO).label = sectionDTO.label;
|
||||
@ -676,8 +658,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as VideoDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as VideoDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as VideoDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as VideoDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as VideoDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as VideoDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as VideoDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as VideoDTO).label = sectionDTO.label;
|
||||
@ -697,8 +678,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as WebDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as WebDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as WebDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as WebDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as WebDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as WebDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as WebDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as WebDTO).label = sectionDTO.label;
|
||||
@ -718,8 +698,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as MenuDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as MenuDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as MenuDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as MenuDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as MenuDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as MenuDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as MenuDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as MenuDTO).label = sectionDTO.label;
|
||||
@ -739,8 +718,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as QuizDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as QuizDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as QuizDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as QuizDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as QuizDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as QuizDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as QuizDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as QuizDTO).label = sectionDTO.label;
|
||||
@ -760,8 +738,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as ArticleDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as ArticleDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as ArticleDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as ArticleDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as ArticleDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as ArticleDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as ArticleDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as ArticleDTO).label = sectionDTO.label;
|
||||
@ -781,8 +758,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as PdfDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as PdfDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as PdfDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as PdfDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as PdfDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as PdfDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as PdfDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as PdfDTO).label = sectionDTO.label;
|
||||
@ -802,8 +778,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as GameDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as GameDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as GameDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as GameDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as GameDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as GameDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as GameDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as GameDTO).label = sectionDTO.label;
|
||||
@ -823,8 +798,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as AgendaDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as AgendaDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as AgendaDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as AgendaDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as AgendaDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as AgendaDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as AgendaDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as AgendaDTO).label = sectionDTO.label;
|
||||
@ -844,8 +818,7 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
(sectionDetailDTO as WeatherDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as WeatherDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as WeatherDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as WeatherDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as WeatherDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as WeatherDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as WeatherDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as WeatherDTO).label = sectionDTO.label;
|
||||
@ -862,29 +835,22 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
|
||||
case SectionType.Event:
|
||||
(sectionDetailDTO as SectionEventDTO).id = sectionDTO.id;
|
||||
(sectionDetailDTO as SectionEventDTO).order = sectionDTO.order;
|
||||
(sectionDetailDTO as SectionEventDTO).dateCreation =
|
||||
sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as SectionEventDTO).dateCreation = sectionDTO.dateCreation;
|
||||
(sectionDetailDTO as SectionEventDTO).type = sectionDTO.type;
|
||||
(sectionDetailDTO as SectionEventDTO).instanceId =
|
||||
sectionDTO.instanceId;
|
||||
(sectionDetailDTO as SectionEventDTO).configurationId =
|
||||
sectionDTO.configurationId;
|
||||
(sectionDetailDTO as SectionEventDTO).isSubSection =
|
||||
sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as SectionEventDTO).instanceId = sectionDTO.instanceId;
|
||||
(sectionDetailDTO as SectionEventDTO).configurationId = sectionDTO.configurationId;
|
||||
(sectionDetailDTO as SectionEventDTO).isSubSection = sectionDTO.isSubSection;
|
||||
(sectionDetailDTO as SectionEventDTO).parentId = sectionDTO.parentId;
|
||||
(sectionDetailDTO as SectionEventDTO).label = sectionDTO.label;
|
||||
(sectionDetailDTO as SectionEventDTO).title = sectionDTO.title;
|
||||
(sectionDetailDTO as SectionEventDTO).description =
|
||||
sectionDTO.description;
|
||||
(sectionDetailDTO as SectionEventDTO).description = sectionDTO.description;
|
||||
(sectionDetailDTO as SectionEventDTO).imageId = sectionDTO.imageId;
|
||||
(sectionDetailDTO as SectionEventDTO).imageSource =
|
||||
sectionDTO.imageSource;
|
||||
(sectionDetailDTO as SectionEventDTO).imageSource = sectionDTO.imageSource;
|
||||
(sectionDetailDTO as SectionEventDTO).isBeacon = sectionDTO.isBeacon;
|
||||
(sectionDetailDTO as SectionEventDTO).beaconId = sectionDTO.beaconId;
|
||||
(sectionDetailDTO as SectionEventDTO).latitude = sectionDTO.latitude;
|
||||
(sectionDetailDTO as SectionEventDTO).longitude = sectionDTO.longitude;
|
||||
(sectionDetailDTO as SectionEventDTO).meterZoneGPS =
|
||||
sectionDTO.meterZoneGPS;
|
||||
(sectionDetailDTO as SectionEventDTO).meterZoneGPS = sectionDTO.meterZoneGPS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,23 +1,17 @@
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:manager_app/Components/check_input_container.dart';
|
||||
import 'package:manager_app/Components/color_picker_input_container.dart';
|
||||
import 'package:manager_app/Components/confirmation_dialog.dart';
|
||||
import 'package:manager_app/Components/number_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/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_string_input_container.dart';
|
||||
import 'package:manager_app/Components/rounded_button.dart';
|
||||
import 'package:manager_app/Components/string_input_container.dart';
|
||||
import 'package:manager_app/Helpers/FileHelper.dart';
|
||||
import 'package:manager_app/Helpers/PDFHelper.dart';
|
||||
import 'package:manager_app/Models/managerContext.dart';
|
||||
import 'package:manager_app/Screens/Configurations/section_reorderList.dart';
|
||||
import 'package:manager_app/app_context.dart';
|
||||
@ -38,450 +32,387 @@ class ConfigurationDetailScreen extends StatefulWidget {
|
||||
|
||||
class _ConfigurationDetailScreenState extends State<ConfigurationDetailScreen> {
|
||||
ConfigurationDTO? configurationDTO;
|
||||
SectionDTO? selectedSection;
|
||||
List<SectionDTO>? sections;
|
||||
Future<ConfigurationDTO?>? _configFuture;
|
||||
Future<List<SectionDTO>?>? _sectionsFuture;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appContext = Provider.of<AppContext>(context);
|
||||
Size size = MediaQuery.of(context).size;
|
||||
return FutureBuilder(
|
||||
future: getConfiguration(this.widget, (appContext.getContext() as ManagerAppContext).clientAPI!),
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
return bodyConfiguration(snapshot.data, size, appContext, context);
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Text(AppLocalizations.of(context)!.noData);
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: size.height * 0.2,
|
||||
child: CommonLoader()
|
||||
)
|
||||
);
|
||||
}
|
||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||
|
||||
_configFuture ??= getConfiguration(widget, managerCtx.clientAPI!);
|
||||
|
||||
return FutureBuilder<ConfigurationDTO?>(
|
||||
future: _configFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.data == null) return Center(child: Text(AppLocalizations.of(context)!.noData));
|
||||
return _buildBody(snapshot.data!, appContext);
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Center(child: Text(AppLocalizations.of(context)!.noData));
|
||||
}
|
||||
return const Center(child: CommonLoader());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget bodyConfiguration(ConfigurationDTO configurationDTO, Size size, AppContext appContext, BuildContext context) {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
return Column(
|
||||
//mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
//color: Colors.cyanAccent,
|
||||
height: size.height *0.1,
|
||||
child: SingleChildScrollView(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomStart,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(configurationDTO.label!, style: TextStyle(fontSize: 30, fontWeight: FontWeight.w400)),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
try {
|
||||
// Export config
|
||||
Client clientAPI = (appContext.getContext() as ManagerAppContext).clientAPI!;
|
||||
ExportConfigurationDTO export = await clientAPI.configurationApi!.configurationExport(configurationDTO.id!);
|
||||
Widget _buildBody(ConfigurationDTO config, AppContext appContext) {
|
||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||
final canEdit = managerCtx.canEdit;
|
||||
final l = AppLocalizations.of(context)!;
|
||||
|
||||
if (kIsWeb) {
|
||||
html.AnchorElement anchorElement = new html.AnchorElement();
|
||||
var uri = (Uri.parse((appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.apiClient.basePath+'/api/Configuration/${configurationDTO.id}/export'));
|
||||
anchorElement.href = uri.toString();
|
||||
anchorElement.download = '${configurationDTO.label}.json';
|
||||
anchorElement.click();
|
||||
} else {
|
||||
File test = await FileHelper().storeConfiguration(export);
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configExportSuccess(test.path), context, 3000);
|
||||
}
|
||||
} catch(e) {
|
||||
log(e.toString());
|
||||
showNotification(kPrimaryColor, kWhite, AppLocalizations.of(context)!.configExportFailed, context, null);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 5.0),
|
||||
child: Icon(Icons.cloud_download, color: kPrimaryColor)
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Text(DateFormat('dd/MM/yyyy').format(configurationDTO.dateCreation!), style: TextStyle(fontSize: 15, fontWeight: FontWeight.w200)),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.selectedConfiguration = null;
|
||||
appContext.setContext(managerAppContext);
|
||||
},
|
||||
child: Container(
|
||||
child: Icon(
|
||||
Icons.arrow_back,
|
||||
color: kPrimaryColor,
|
||||
size: 50.0,
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
return Column(
|
||||
children: [
|
||||
_buildHeader(config, appContext, l),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
_cardGeneral(config, l),
|
||||
const SizedBox(height: 12),
|
||||
_cardImages(config, l),
|
||||
const SizedBox(height: 12),
|
||||
_cardSections(config, appContext),
|
||||
],
|
||||
),
|
||||
),
|
||||
), // TITLE
|
||||
Container(
|
||||
height: size.height *0.78,
|
||||
//color: Colors.red,
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Container(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final isWide = constraints.maxWidth > 700;
|
||||
|
||||
final fields = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 70,
|
||||
child: StringInputContainer(
|
||||
label: AppLocalizations.of(context)!.identifierLabel,
|
||||
fontSize: 20,
|
||||
fontSizeText: 20,
|
||||
initialValue: configurationDTO.label,
|
||||
onChanged: (value) {
|
||||
configurationDTO.label = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
spacing: 24,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
MultiSelectDropdownLanguageContainer(
|
||||
label: AppLocalizations.of(context)!.languagesLabel,
|
||||
initialValue: configurationDTO.languages != null ? configurationDTO.languages! : [],
|
||||
values: languages,
|
||||
isMultiple: true,
|
||||
fontSize: 20,
|
||||
isAtLeastOne: true,
|
||||
onChanged: (value) {
|
||||
var tempOutput = new List<String>.from(value);
|
||||
configurationDTO.languages = tempOutput;
|
||||
},
|
||||
),
|
||||
CheckInputContainer(
|
||||
icon: Icons.signal_wifi_off,
|
||||
label: "Hors ligne :", // no ARB key for this one yet, leave as-is
|
||||
fontSize: 20,
|
||||
isChecked: configurationDTO.isOffline,
|
||||
onChanged: (value) {
|
||||
configurationDTO.isOffline = value;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
final images = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ResourceInputContainer(
|
||||
label: AppLocalizations.of(context)!.mainImageLabel,
|
||||
fontSize: 20,
|
||||
initialValue: configurationDTO.imageId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if (resource.id == null) {
|
||||
configurationDTO.imageId = null;
|
||||
configurationDTO.imageSource = null;
|
||||
} else {
|
||||
configurationDTO.imageId = resource.id;
|
||||
configurationDTO.imageSource = resource.url;
|
||||
}
|
||||
},
|
||||
),
|
||||
ResourceInputContainer(
|
||||
label: AppLocalizations.of(context)!.loaderLabel,
|
||||
fontSize: 20,
|
||||
initialValue: configurationDTO.loaderImageId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if (resource.id == null) {
|
||||
configurationDTO.loaderImageId = null;
|
||||
configurationDTO.loaderImageUrl = null;
|
||||
} else {
|
||||
configurationDTO.loaderImageId = resource.id;
|
||||
configurationDTO.loaderImageUrl = resource.url;
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
if (isWide) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(flex: 3, child: fields),
|
||||
SizedBox(width: 24),
|
||||
Expanded(flex: 2, child: images),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 70,
|
||||
child: StringInputContainer(
|
||||
label: "Identifiant :",
|
||||
fontSize: 20,
|
||||
fontSizeText: 20,
|
||||
initialValue: configurationDTO.label,
|
||||
onChanged: (value) {
|
||||
configurationDTO.label = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
MultiSelectDropdownLanguageContainer(
|
||||
label: "Langues :",
|
||||
initialValue: configurationDTO.languages != null ? configurationDTO.languages! : [],
|
||||
values: languages,
|
||||
isMultiple: true,
|
||||
fontSize: 20,
|
||||
isAtLeastOne: true,
|
||||
onChanged: (value) {
|
||||
var tempOutput = new List<String>.from(value);
|
||||
configurationDTO.languages = tempOutput;
|
||||
},
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
CheckInputContainer(
|
||||
icon: Icons.signal_wifi_off,
|
||||
label: "Hors ligne :",
|
||||
fontSize: 20,
|
||||
isChecked: configurationDTO.isOffline,
|
||||
onChanged: (value) {
|
||||
configurationDTO.isOffline = value;
|
||||
},
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
images,
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
border: Border.all(width: 0.5, color: kSecond)
|
||||
),
|
||||
child: FutureBuilder(
|
||||
future: getSections(configurationDTO, (appContext.getContext() as ManagerAppContext).clientAPI!),
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done)
|
||||
{
|
||||
sections = new List<SectionDTO>.from(snapshot.data).where((section) => !section.isSubSection!).toList();
|
||||
return bodyGrid(configurationDTO, size, appContext);
|
||||
}
|
||||
else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Text("No data");
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: size.height * 0.15,
|
||||
child: CommonLoader()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),// FIELDS SECTION
|
||||
Container(
|
||||
height: size.height *0.08,
|
||||
//color: Colors.greenAccent,
|
||||
child: SingleChildScrollView(
|
||||
child: getButtons(configurationDTO, appContext)
|
||||
)
|
||||
)
|
||||
),
|
||||
_buildFooter(config, appContext, canEdit, l),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
getButtons(ConfigurationDTO configurationDTO, AppContext appContext) {
|
||||
final canEdit = (appContext.getContext() as ManagerAppContext).canEdit;
|
||||
return Align(
|
||||
alignment: AlignmentDirectional.bottomCenter,
|
||||
// ── Header ──
|
||||
|
||||
Widget _buildHeader(ConfigurationDTO config, AppContext appContext, AppLocalizations l) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: kWhite,
|
||||
border: Border(bottom: BorderSide(color: kSecond, width: 1)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.cancel,
|
||||
icon: Icons.undo,
|
||||
color: Colors.grey,
|
||||
textColor: Colors.white,
|
||||
fontSize: 15,
|
||||
press: () {
|
||||
cancel(configurationDTO, appContext);
|
||||
},
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_back, color: kPrimaryColor),
|
||||
onPressed: () {
|
||||
ManagerAppContext ctx = appContext.getContext();
|
||||
ctx.selectedConfiguration = null;
|
||||
appContext.setContext(ctx);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
config.label ?? '',
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
Text(
|
||||
DateFormat('dd/MM/yyyy').format(config.dateCreation!),
|
||||
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w300, color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (canEdit) Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.delete,
|
||||
icon: Icons.delete,
|
||||
color: kError,
|
||||
textColor: Colors.white,
|
||||
fontSize: 15,
|
||||
press: () {
|
||||
delete(configurationDTO, appContext);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (canEdit) Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.save,
|
||||
icon: Icons.done,
|
||||
color: kSuccess,
|
||||
textColor: Colors.white,
|
||||
fontSize: 15,
|
||||
press: () {
|
||||
save(configurationDTO, appContext);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.download_outlined, color: kPrimaryColor),
|
||||
tooltip: l.configExportSuccess(''),
|
||||
onPressed: () => _export(config, appContext),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget bodyGrid(ConfigurationDTO configurationDTO, Size size, AppContext appContext) {
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
height: size.height *0.40,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SectionReorderList(
|
||||
sectionsIn: sections!,
|
||||
configurationId: configurationDTO.id!,
|
||||
onChangedOrder: (List<SectionDTO> sectionsOut) async {
|
||||
sections = sectionsOut;
|
||||
// ── Footer ──
|
||||
|
||||
// Update section order
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
await managerAppContext.clientAPI!.sectionApi!.sectionUpdateOrder(sections!);
|
||||
},
|
||||
askReload: () {
|
||||
setState(() {
|
||||
// refresh UI
|
||||
});
|
||||
},
|
||||
),
|
||||
Widget _buildFooter(ConfigurationDTO config, AppContext appContext, bool canEdit, AppLocalizations l) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||
decoration: const BoxDecoration(
|
||||
color: kWhite,
|
||||
boxShadow: [BoxShadow(color: kSecond, blurRadius: 8, offset: Offset(0, -2))],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
OutlinedButton.icon(
|
||||
icon: const Icon(Icons.undo, size: 16),
|
||||
label: Text(l.cancel),
|
||||
onPressed: () => cancel(config, appContext),
|
||||
),
|
||||
if (canEdit) ...[
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton.icon(
|
||||
icon: const Icon(Icons.delete, size: 16, color: kWhite),
|
||||
label: Text(l.delete, style: const TextStyle(color: kWhite)),
|
||||
style: ElevatedButton.styleFrom(backgroundColor: kError),
|
||||
onPressed: () => delete(config, appContext),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton.icon(
|
||||
icon: const Icon(Icons.done, size: 16, color: kWhite),
|
||||
label: Text(l.save, style: const TextStyle(color: kWhite)),
|
||||
style: ElevatedButton.styleFrom(backgroundColor: kPrimaryColor),
|
||||
onPressed: () => save(config, appContext),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Card Général ──
|
||||
|
||||
Widget _cardGeneral(ConfigurationDTO config, AppLocalizations l) {
|
||||
return Card(
|
||||
elevation: 0,
|
||||
color: kWhite,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l.identifierLabel.replaceAll(':', '').trim(),
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: kTitleTextColor)),
|
||||
const SizedBox(height: 12),
|
||||
StringInputContainer(
|
||||
label: l.identifierLabel,
|
||||
fontSize: 16,
|
||||
fontSizeText: 16,
|
||||
initialValue: config.label,
|
||||
onChanged: (value) => config.label = value,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 24,
|
||||
runSpacing: 12,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
MultiSelectDropdownLanguageContainer(
|
||||
label: l.languagesLabel,
|
||||
initialValue: config.languages ?? [],
|
||||
values: languages,
|
||||
isMultiple: true,
|
||||
fontSize: 16,
|
||||
isAtLeastOne: true,
|
||||
onChanged: (value) {
|
||||
config.languages = List<String>.from(value);
|
||||
},
|
||||
),
|
||||
CheckInputContainer(
|
||||
icon: Icons.signal_wifi_off,
|
||||
label: "Hors ligne :",
|
||||
fontSize: 16,
|
||||
isChecked: config.isOffline,
|
||||
onChanged: (value) => config.isOffline = value,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> cancel(ConfigurationDTO configurationDTO, AppContext appContext) async {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
ConfigurationDTO? configuration = await managerAppContext.clientAPI!.configurationApi!.configurationGetDetail(configurationDTO.id!);
|
||||
managerAppContext.selectedConfiguration = configuration;
|
||||
appContext.setContext(managerAppContext);
|
||||
}
|
||||
// ── Card Images ──
|
||||
|
||||
Future<void> delete(ConfigurationDTO configurationDTO, AppContext appContext) async {
|
||||
showConfirmationDialog(
|
||||
AppLocalizations.of(context)!.configDeleteConfirm,
|
||||
() {},
|
||||
() async {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
await managerAppContext.clientAPI!.configurationApi!.configurationDelete(configurationDTO.id!);
|
||||
managerAppContext.selectedConfiguration = null;
|
||||
appContext.setContext(managerAppContext);
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configDeletedSuccess, context, null);
|
||||
},
|
||||
context
|
||||
Widget _cardImages(ConfigurationDTO config, AppLocalizations l) {
|
||||
return Card(
|
||||
elevation: 0,
|
||||
color: kWhite,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Images",
|
||||
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: kTitleTextColor)),
|
||||
const SizedBox(height: 12),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final isWide = constraints.maxWidth > kBreakpointMobile;
|
||||
final children = [
|
||||
ResourceInputContainer(
|
||||
label: l.mainImageLabel,
|
||||
fontSize: 16,
|
||||
initialValue: config.imageId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if (resource.id == null) {
|
||||
config.imageId = null;
|
||||
config.imageSource = null;
|
||||
} else {
|
||||
config.imageId = resource.id;
|
||||
config.imageSource = resource.url;
|
||||
}
|
||||
},
|
||||
),
|
||||
ResourceInputContainer(
|
||||
label: l.loaderLabel,
|
||||
fontSize: 16,
|
||||
initialValue: config.loaderImageId,
|
||||
color: kPrimaryColor,
|
||||
onChanged: (ResourceDTO resource) {
|
||||
if (resource.id == null) {
|
||||
config.loaderImageId = null;
|
||||
config.loaderImageUrl = null;
|
||||
} else {
|
||||
config.loaderImageId = resource.id;
|
||||
config.loaderImageUrl = resource.url;
|
||||
}
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
if (isWide) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: children.map((c) => Expanded(child: Padding(
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
child: c,
|
||||
))).toList(),
|
||||
);
|
||||
}
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: children.map((c) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: c,
|
||||
)).toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> save(ConfigurationDTO configurationDTO, AppContext appContext) async {
|
||||
// ── Card Sections ──
|
||||
|
||||
Widget _cardSections(ConfigurationDTO config, AppContext appContext) {
|
||||
final managerCtx = appContext.getContext() as ManagerAppContext;
|
||||
_sectionsFuture ??= getSections(config, managerCtx.clientAPI!);
|
||||
|
||||
return Card(
|
||||
elevation: 0,
|
||||
color: kWhite,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("Sections",
|
||||
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: kTitleTextColor)),
|
||||
const SizedBox(height: 12),
|
||||
FutureBuilder<List<SectionDTO>?>(
|
||||
future: _sectionsFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.data == null) return const Text("No data");
|
||||
sections = List<SectionDTO>.from(snapshot.data!)
|
||||
.where((s) => !s.isSubSection!)
|
||||
.toList();
|
||||
return SectionReorderList(
|
||||
sectionsIn: sections!,
|
||||
configurationId: config.id!,
|
||||
onChangedOrder: (List<SectionDTO> sectionsOut) async {
|
||||
sections = sectionsOut;
|
||||
await managerCtx.clientAPI!.sectionApi!.sectionUpdateOrder(sections!);
|
||||
},
|
||||
askReload: () => setState(() {
|
||||
_sectionsFuture = null;
|
||||
}),
|
||||
);
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return const Text("No data");
|
||||
}
|
||||
return const Center(child: Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: CommonLoader(),
|
||||
));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ── Actions ──
|
||||
|
||||
void _export(ConfigurationDTO config, AppContext appContext) async {
|
||||
final l = AppLocalizations.of(context)!;
|
||||
try {
|
||||
Client clientAPI = (appContext.getContext() as ManagerAppContext).clientAPI!;
|
||||
await clientAPI.configurationApi!.configurationExport(config.id!);
|
||||
|
||||
if (kIsWeb) {
|
||||
html.AnchorElement anchorElement = html.AnchorElement();
|
||||
var uri = Uri.parse('${clientAPI.resourceApi!.apiClient.basePath}/api/Configuration/${config.id}/export');
|
||||
anchorElement.href = uri.toString();
|
||||
anchorElement.download = '${config.label}.json';
|
||||
anchorElement.click();
|
||||
} else {
|
||||
ExportConfigurationDTO export = await clientAPI.configurationApi!.configurationExport(config.id!);
|
||||
File test = await FileHelper().storeConfiguration(export);
|
||||
showNotification(kSuccess, kWhite, l.configExportSuccess(test.path), context, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
showNotification(kPrimaryColor, kWhite, l.configExportFailed, context, null);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> cancel(ConfigurationDTO config, AppContext appContext) async {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
ConfigurationDTO? configuration = await managerAppContext.clientAPI!.configurationApi!.configurationUpdate(configurationDTO);
|
||||
ConfigurationDTO? configuration = await managerAppContext.clientAPI!.configurationApi!.configurationGetDetail(config.id!);
|
||||
managerAppContext.selectedConfiguration = configuration;
|
||||
appContext.setContext(managerAppContext);
|
||||
}
|
||||
|
||||
Future<void> delete(ConfigurationDTO config, AppContext appContext) async {
|
||||
showConfirmationDialog(
|
||||
AppLocalizations.of(context)!.configDeleteConfirm,
|
||||
() {},
|
||||
() async {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
await managerAppContext.clientAPI!.configurationApi!.configurationDelete(config.id!);
|
||||
managerAppContext.selectedConfiguration = null;
|
||||
appContext.setContext(managerAppContext);
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configDeletedSuccess, context, null);
|
||||
},
|
||||
context,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> save(ConfigurationDTO config, AppContext appContext) async {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
ConfigurationDTO? configuration = await managerAppContext.clientAPI!.configurationApi!.configurationUpdate(config);
|
||||
managerAppContext.selectedConfiguration = configuration;
|
||||
appContext.setContext(managerAppContext);
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configSavedSuccess, context, null);
|
||||
}
|
||||
|
||||
Future<ConfigurationDTO?> getConfiguration(ConfigurationDetailScreen widget, Client client) async {
|
||||
ConfigurationDTO? configuration = await client.configurationApi!.configurationGetDetail(widget.id);
|
||||
return configuration;
|
||||
return await client.configurationApi!.configurationGetDetail(widget.id);
|
||||
}
|
||||
|
||||
Future<List<SectionDTO>?> getSections(ConfigurationDTO configurationDTO, Client client) async {
|
||||
List<SectionDTO>? sections = await client.sectionApi!.sectionGetFromConfiguration(configurationDTO.id!);
|
||||
if(sections != null) {
|
||||
Future<List<SectionDTO>?> getSections(ConfigurationDTO config, Client client) async {
|
||||
List<SectionDTO>? sections = await client.sectionApi!.sectionGetFromConfiguration(config.id!);
|
||||
if (sections != null) {
|
||||
sections.sort((a, b) => a.order!.compareTo(b.order!));
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
}
|
||||
|
||||
boxDecoration(dynamic element) {
|
||||
return BoxDecoration(
|
||||
color: element.id == null ? kSuccess : kTextLightColor,
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:manager_app/Components/common_loader.dart';
|
||||
import 'package:manager_app/Components/string_input_container.dart';
|
||||
import 'package:manager_app/l10n/app_localizations.dart';
|
||||
import 'package:manager_app/Components/message_notification.dart';
|
||||
import 'package:manager_app/Models/managerContext.dart';
|
||||
@ -23,255 +24,249 @@ class ConfigurationsScreen extends StatefulWidget {
|
||||
|
||||
class _ConfigurationsScreenState extends State<ConfigurationsScreen> {
|
||||
ConfigurationDTO? selectedConfiguration;
|
||||
String _filter = '';
|
||||
Future<List<ConfigurationDTO>?>? _future;
|
||||
|
||||
void _refresh() => setState(() => _future = null);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appContext = Provider.of<AppContext>(context);
|
||||
Size size = MediaQuery.of(context).size;
|
||||
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
final Size size = MediaQuery.of(context).size;
|
||||
final ManagerAppContext managerAppContext = appContext.getContext();
|
||||
|
||||
if (managerAppContext.selectedSection != null) {
|
||||
return SectionDetailScreen(id: managerAppContext.selectedSection!.id!);
|
||||
}
|
||||
if (managerAppContext.selectedConfiguration != null) {
|
||||
return ConfigurationDetailScreen(id: managerAppContext.selectedConfiguration!.id!);
|
||||
} else {
|
||||
return Align(
|
||||
alignment: AlignmentDirectional.topCenter,
|
||||
child: FutureBuilder(
|
||||
future: getConfigurations(managerAppContext),
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
var tempOutput = new List<ConfigurationDTO>.from(snapshot.data);
|
||||
if (managerAppContext.canEdit) tempOutput.add(ConfigurationDTO(id: null));
|
||||
return bodyGrid(tempOutput, size, appContext, context);
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Text(AppLocalizations.of(context)!.noData);
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: size.height * 0.2,
|
||||
child: CommonLoader()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget bodyGrid(data, Size size, AppContext appContext, BuildContext mainContext) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final itemWidth = 175;
|
||||
final crossAxisCount = (screenWidth / itemWidth).floor().clamp(1, 6);
|
||||
return GridView.builder(
|
||||
shrinkWrap: true,
|
||||
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: crossAxisCount),
|
||||
itemCount: data.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
if (data[index].id == null) {
|
||||
var configurationToCreate = await showNewConfiguration(appContext, (bool) {
|
||||
if (bool) {
|
||||
setState(() {
|
||||
// Thanks future builder for the refresh..
|
||||
});
|
||||
}
|
||||
}, context, mainContext);
|
||||
if(configurationToCreate != null) {
|
||||
if (configurationToCreate.label != null) {
|
||||
configurationToCreate.dateCreation = DateTime.now();
|
||||
/*configurationToCreate.isMobile = false;
|
||||
configurationToCreate.isTablet = false;*/
|
||||
configurationToCreate.isOffline = false;
|
||||
/*configurationToCreate.isDate = false;
|
||||
configurationToCreate.isHour = false;
|
||||
configurationToCreate.isSectionImageBackground = false;*/
|
||||
configurationToCreate.instanceId = (appContext.getContext() as ManagerAppContext).instanceId;
|
||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.configurationApi!.configurationCreate(configurationToCreate);
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.selectedConfiguration = null;
|
||||
await appContext.setContext(managerAppContext);
|
||||
_future ??= getConfigurations(managerAppContext);
|
||||
|
||||
showNotification(kSuccess, kWhite, AppLocalizations.of(context)!.configCreatedSuccess, context, null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setState(() {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.selectedConfiguration = data[index];
|
||||
selectedConfiguration = data[index];
|
||||
});
|
||||
}
|
||||
},
|
||||
return Align(
|
||||
alignment: AlignmentDirectional.topCenter,
|
||||
child: FutureBuilder(
|
||||
future: _future,
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
var all = List<ConfigurationDTO>.from(snapshot.data);
|
||||
if (managerAppContext.canEdit) all.add(ConfigurationDTO(id: null));
|
||||
|
||||
final filtered = _filter.isEmpty
|
||||
? all
|
||||
: all
|
||||
.where((c) =>
|
||||
c.id == null ||
|
||||
(c.label?.toLowerCase().contains(_filter.toLowerCase()) ??
|
||||
false))
|
||||
.toList();
|
||||
|
||||
return _buildGrid(filtered, size, appContext, context);
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Text(AppLocalizations.of(context)!.noData);
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
decoration: boxDecoration(data[index]),
|
||||
padding: const EdgeInsets.all(15),
|
||||
margin: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: getElement(data[index], size)
|
||||
),
|
||||
height: size.height * 0.2,
|
||||
child: CommonLoader(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
getElement(ConfigurationDTO configuration, Size size) {
|
||||
if (configuration.id != null) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Align(
|
||||
Widget _buildGrid(List<ConfigurationDTO> data, Size size, AppContext appContext,
|
||||
BuildContext mainContext) {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 4),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: AutoSizeText(
|
||||
configuration.label!,
|
||||
style: new TextStyle(fontSize: 25),
|
||||
maxLines: 1,
|
||||
child: SizedBox(
|
||||
width: 280,
|
||||
child: StringInputContainer(
|
||||
label: AppLocalizations.of(context)!.searchLabel,
|
||||
onChanged: (v) => setState(() => _filter = v),
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: AutoSizeText(
|
||||
DateFormat('dd/MM/yyyy').format(configuration.dateCreation!),
|
||||
style: new TextStyle(fontSize: 18, fontFamily: ""),
|
||||
maxLines: 1,
|
||||
),
|
||||
Expanded(
|
||||
child: GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 220,
|
||||
childAspectRatio: 1.5,
|
||||
mainAxisSpacing: 10,
|
||||
crossAxisSpacing: 10,
|
||||
),
|
||||
itemCount: data.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return _ConfigCard(
|
||||
config: data[index],
|
||||
onTap: () => _onTap(data[index], appContext, mainContext),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onTap(
|
||||
ConfigurationDTO config, AppContext appContext, BuildContext mainContext) async {
|
||||
if (config.id == null) {
|
||||
var configurationToCreate = await showNewConfiguration(
|
||||
appContext,
|
||||
(bool refresh) {
|
||||
if (refresh) _refresh();
|
||||
},
|
||||
context,
|
||||
mainContext,
|
||||
);
|
||||
if (configurationToCreate != null && configurationToCreate.label != null) {
|
||||
configurationToCreate.dateCreation = DateTime.now();
|
||||
configurationToCreate.isOffline = false;
|
||||
configurationToCreate.instanceId =
|
||||
(appContext.getContext() as ManagerAppContext).instanceId;
|
||||
await (appContext.getContext() as ManagerAppContext)
|
||||
.clientAPI!
|
||||
.configurationApi!
|
||||
.configurationCreate(configurationToCreate);
|
||||
final ctx = appContext.getContext() as ManagerAppContext;
|
||||
ctx.selectedConfiguration = null;
|
||||
await appContext.setContext(ctx);
|
||||
showNotification(
|
||||
kSuccess, kWhite, AppLocalizations.of(context)!.configCreatedSuccess, context, null);
|
||||
_refresh();
|
||||
}
|
||||
} else {
|
||||
return Icon(
|
||||
Icons.add,
|
||||
color: kTextLightColor,
|
||||
size: size.height*0.1,
|
||||
);
|
||||
setState(() {
|
||||
final ctx = appContext.getContext() as ManagerAppContext;
|
||||
ctx.selectedConfiguration = config;
|
||||
selectedConfiguration = config;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<ConfigurationDTO>?> getConfigurations(ManagerAppContext managerAppContext) async {
|
||||
List<ConfigurationDTO>? configurations = await managerAppContext.clientAPI!.configurationApi!.configurationGet(instanceId: managerAppContext.instanceId);
|
||||
//print("number of configurations " + configurations.length.toString());
|
||||
if(configurations != null) {
|
||||
configurations.forEach((element) {
|
||||
//print(element);
|
||||
});
|
||||
class _ConfigCard extends StatefulWidget {
|
||||
final ConfigurationDTO config;
|
||||
final VoidCallback onTap;
|
||||
const _ConfigCard({required this.config, required this.onTap});
|
||||
|
||||
@override
|
||||
State<_ConfigCard> createState() => _ConfigCardState();
|
||||
}
|
||||
|
||||
class _ConfigCardState extends State<_ConfigCard> {
|
||||
bool _hovered = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final config = widget.config;
|
||||
final isAdd = config.id == null;
|
||||
final hasImage = config.imageSource != null;
|
||||
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => _hovered = true),
|
||||
onExit: (_) => setState(() => _hovered = false),
|
||||
child: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: AnimatedScale(
|
||||
scale: _hovered ? 1.03 : 1.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: _hovered ? 1 : 0.5,
|
||||
blurRadius: _hovered ? 10 : 5,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// Background
|
||||
if (!isAdd && hasImage)
|
||||
Image.network(config.imageSource!, fit: BoxFit.cover)
|
||||
else
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: isAdd
|
||||
? [kSuccess, kSuccess.withOpacity(0.7)]
|
||||
: [kPrimaryColor, kPrimaryColor.withOpacity(0.6)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Gradient scrim
|
||||
if (!isAdd)
|
||||
DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
stops: const [0.35, 1.0],
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black.withOpacity(0.65),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// Content
|
||||
if (isAdd)
|
||||
const Center(
|
||||
child: Icon(Icons.add, color: kTextLightColor, size: 36),
|
||||
)
|
||||
else
|
||||
Positioned(
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 10,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
AutoSizeText(
|
||||
config.label ?? '',
|
||||
style: kCardTitleStyle,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (config.dateCreation != null)
|
||||
Text(
|
||||
DateFormat('dd/MM/yyyy').format(config.dateCreation!),
|
||||
style: kCardSubtitleStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return configurations;
|
||||
}
|
||||
|
||||
boxDecoration(ConfigurationDTO configurationDTO) {
|
||||
return BoxDecoration(
|
||||
color: configurationDTO.id == null ? kSuccess : kTextLightColor,
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
image: configurationDTO.imageSource != null ? new DecorationImage(
|
||||
fit: BoxFit.cover,
|
||||
colorFilter: new ColorFilter.mode(Colors.black.withOpacity(0.18), BlendMode.dstATop),
|
||||
image: new NetworkImage(
|
||||
configurationDTO.imageSource!,
|
||||
),
|
||||
) : null,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
);
|
||||
Future<List<ConfigurationDTO>?> getConfigurations(
|
||||
ManagerAppContext managerAppContext) async {
|
||||
return managerAppContext.clientAPI!.configurationApi!
|
||||
.configurationGet(instanceId: managerAppContext.instanceId);
|
||||
}
|
||||
|
||||
|
||||
/*Widget bodyTable(data) => DataTable(
|
||||
sortColumnIndex: 0,
|
||||
sortAscending: true,
|
||||
columns: <DataColumn>[
|
||||
DataColumn(
|
||||
label: Text("Label"),
|
||||
onSort: (_, __) {
|
||||
setState(() {
|
||||
// data.sort((a) => a.label);
|
||||
});
|
||||
},
|
||||
),
|
||||
DataColumn(
|
||||
label: Text("Primary color"),
|
||||
onSort: (_, __) {
|
||||
setState(() {
|
||||
/*data.sort((a, b) => a.data["stats"]["dividendYield"]
|
||||
.compareTo(b.data["stats"]["dividendYield"]));*/
|
||||
});
|
||||
},
|
||||
),
|
||||
DataColumn(
|
||||
label: Text("Secondary color"),
|
||||
onSort: (_, __) {
|
||||
setState(() {
|
||||
/*data.sort((a, b) => a.data["quote"]["iexBidPrice"]
|
||||
.compareTo(b.data["quote"]["iexBidPrice"]));*/
|
||||
});
|
||||
},
|
||||
),
|
||||
DataColumn(
|
||||
label: Text("Languages"),
|
||||
onSort: (_, __) {
|
||||
setState(() {
|
||||
/*data.sort((a, b) => a.data["stats"]["latestPrice"]
|
||||
.compareTo(b.data["stats"]["latestPrice"]));*/
|
||||
});
|
||||
},
|
||||
),
|
||||
DataColumn(
|
||||
label: Text("Date creation"),
|
||||
onSort: (_, __) {
|
||||
setState(() {
|
||||
/*data.sort((a, b) => a.data["stats"]["latestPrice"]
|
||||
.compareTo(b.data["stats"]["latestPrice"]));*/
|
||||
});
|
||||
},
|
||||
),
|
||||
DataColumn(
|
||||
label: Text("Actions"),
|
||||
onSort: (_, __) {
|
||||
setState(() {
|
||||
/*data.sort((a, b) => a.data["stats"]["latestPrice"]
|
||||
.compareTo(b.data["stats"]["latestPrice"]));*/
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
rows: data
|
||||
.map<DataRow>( (configuration) => DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text('${configuration.label ?? ""}'),
|
||||
),
|
||||
DataCell(
|
||||
Text('${configuration.primaryColor ?? ""}'),
|
||||
),
|
||||
DataCell(
|
||||
Text('${configuration.secondaryColor ?? ""}'),
|
||||
),
|
||||
DataCell(
|
||||
Text('${configuration.languages ?? ""}'),
|
||||
),
|
||||
DataCell(
|
||||
Text('${configuration.dateCreation ?? ""}'),
|
||||
),
|
||||
DataCell(
|
||||
Text("Todo buttons - open = edit, delete"),
|
||||
),
|
||||
],
|
||||
),
|
||||
).toList()
|
||||
);*/
|
||||
|
||||
@ -14,114 +14,101 @@ import 'package:manager_api_new/api.dart';
|
||||
Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChanged<bool> isImport, BuildContext context, BuildContext mainContext) {
|
||||
final l = AppLocalizations.of(mainContext)!;
|
||||
ConfigurationDTO configurationDTO = new ConfigurationDTO();
|
||||
Size size = MediaQuery.of(mainContext).size;
|
||||
configurationDTO.label = "";
|
||||
|
||||
var configuration = showDialog<ConfigurationDTO?>(
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
builder: (BuildContext context) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: size.width*0.35,
|
||||
height: size.height*0.3,
|
||||
child: SizedBox(
|
||||
width: 460,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(child: Text(l.newConfiguration, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400))),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
height: 100,
|
||||
child: StringInputContainer(
|
||||
label: l.configNameLabel,
|
||||
initialValue: configurationDTO.label,
|
||||
onChanged: (value) {
|
||||
configurationDTO.label = value;
|
||||
},
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Center(child: Text(l.newConfiguration, style: new TextStyle(fontSize: 22, fontWeight: FontWeight.w400))),
|
||||
SizedBox(height: 8),
|
||||
SizedBox(
|
||||
height: 90,
|
||||
child: StringInputContainer(
|
||||
label: l.configNameLabel,
|
||||
initialValue: configurationDTO.label,
|
||||
onChanged: (value) {
|
||||
configurationDTO.label = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(l.orText),
|
||||
SizedBox(height: 4),
|
||||
Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 5.0),
|
||||
child: Text(l.importLabel, style: TextStyle(fontSize: 18, fontWeight: FontWeight.w300)),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles();
|
||||
if (result != null) {
|
||||
await FileHelper().importConfiguration(result, null, (appContext.getContext() as ManagerAppContext).clientAPI!, mainContext);
|
||||
isImport(true);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Icon(Icons.file_upload, color: kPrimaryColor, size: 30),
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(l.orText),
|
||||
Column(
|
||||
const SizedBox(height: 16),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: WrapAlignment.end,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 5.0),
|
||||
child: Text(l.importLabel, style: TextStyle(fontSize: 25, fontWeight: FontWeight.w300)),
|
||||
RoundedButton(
|
||||
text: l.cancel,
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () => Navigator.of(context).pop(),
|
||||
fontSize: 16,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles();
|
||||
|
||||
//String result = filePicker();
|
||||
if (result != null) {
|
||||
|
||||
await FileHelper().importConfiguration(result, null, (appContext.getContext() as ManagerAppContext).clientAPI!, mainContext);
|
||||
isImport(true);
|
||||
Navigator.of(context).pop();
|
||||
RoundedButton(
|
||||
text: l.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if(configurationDTO.label != null && configurationDTO.label!.length > 2) {
|
||||
Navigator.of(context).pop(configurationDTO);
|
||||
} else {
|
||||
showNotification(Colors.orange, kWhite, l.configNameRequired, context, null);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Icon(
|
||||
Icons.file_upload,
|
||||
color: kPrimaryColor,
|
||||
size: 30
|
||||
),
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
fontSize: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: l.cancel,
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: l.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if(configurationDTO.label != null && configurationDTO.label!.length > 2) {
|
||||
//create(configurationDTO, appContext, context);
|
||||
Navigator.of(context).pop(configurationDTO);
|
||||
} else {
|
||||
showNotification(Colors.orange, kWhite, l.configNameRequired, context, null);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
), context: context
|
||||
);
|
||||
|
||||
@ -129,38 +116,12 @@ Future<ConfigurationDTO?> showNewConfiguration(AppContext appContext, ValueChang
|
||||
}
|
||||
|
||||
String filePicker() {
|
||||
/*final file = OpenFilePicker()
|
||||
..filterSpecification = {
|
||||
'Fichier (*.json)': '*.json',
|
||||
//'Video (*.mp4)': '*.mp4',
|
||||
//'All Files': '*.*'
|
||||
}
|
||||
..defaultFilterIndex = 0
|
||||
..title = 'Sélectionner un fichier';
|
||||
|
||||
final result = file.getFile();*/
|
||||
var result;
|
||||
|
||||
return result != null ? result.path : null;
|
||||
}
|
||||
|
||||
void create(ConfigurationDTO configurationDTO, AppContext appContext, context) async {
|
||||
if (configurationDTO.label != null) {
|
||||
/*configurationDTO.dateCreation = DateTime.now();
|
||||
configurationDTO.isMobile = false;
|
||||
configurationDTO.isTablet = false;
|
||||
configurationDTO.isOffline = false;
|
||||
configurationDTO.isDate = false;
|
||||
configurationDTO.isHour = false;
|
||||
configurationDTO.isSectionImageBackground = false;
|
||||
configurationDTO.instanceId = (appContext.getContext() as ManagerAppContext).instanceId;
|
||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.configurationApi!.configurationCreate(configurationDTO);
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.selectedConfiguration = null;
|
||||
await appContext.setContext(managerAppContext);
|
||||
|
||||
showNotification(Colors.green, kWhite, 'La configuration a été créée avec succès', context, null);*/
|
||||
|
||||
Navigator.of(context).pop(configurationDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,118 +23,130 @@ Future<SectionDTO?> showNewSection(String configurationId,
|
||||
sectionDTO.type = SectionType.Map;
|
||||
|
||||
var section = showDialog<SectionDTO?>(
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
builder: (BuildContext context) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))),
|
||||
content: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: 750,
|
||||
height: 250,
|
||||
child: Container(
|
||||
constraints: BoxConstraints(minHeight: 300, minWidth: 300),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
isSubSection
|
||||
? l.newSubSection
|
||||
: l.newSection,
|
||||
style: new TextStyle(
|
||||
fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: StringInputContainer(
|
||||
label: l.sectionNameLabel,
|
||||
initialValue: sectionDTO.label,
|
||||
onChanged: (value) {
|
||||
sectionDTO.label = value;
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 780,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
height: 250,
|
||||
child: Container(
|
||||
constraints: BoxConstraints(minHeight: 300, minWidth: 300),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
isSubSection
|
||||
? l.newSubSection
|
||||
: l.newSection,
|
||||
style: new TextStyle(
|
||||
fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: StringInputContainer(
|
||||
label: l.sectionNameLabel,
|
||||
initialValue: sectionDTO.label,
|
||||
onChanged: (value) {
|
||||
sectionDTO.label = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
DropDownInputContainer(
|
||||
label: l.sectionTypeLabel,
|
||||
values: isSubSection
|
||||
? section_types
|
||||
.where(
|
||||
(sectionType) => sectionType != "Menu")
|
||||
.toList()
|
||||
: section_types
|
||||
.toList(), // Todo get menu by enum type
|
||||
initialValue: "Map",
|
||||
onChange: (String? value) {
|
||||
sectionDTO.type = SectionType.fromJson(value);
|
||||
},
|
||||
),
|
||||
/*MultiSelectContainer(
|
||||
label: "Type:",
|
||||
initialValue: isMobile ? ["Article"] : ["Map"],
|
||||
isMultiple: false,
|
||||
values: isMobile ? section_types.where((sectionType) => sectionType == "Article" || sectionType == "Quizz").toList(): isSubSection ? section_types.where((sectionType) => sectionType != "Menu" && sectionType != "Article").toList(): section_types.where((sectionType) => sectionType != "Article").toList(), // Todo get menu by enum type
|
||||
onChanged: (value) {
|
||||
var tempOutput = new List<String>.from(value);
|
||||
sectionDTO.type = SectionType.fromJson(tempOutput[0]);
|
||||
},
|
||||
),*/
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
DropDownInputContainer(
|
||||
label: l.sectionTypeLabel,
|
||||
values: isSubSection
|
||||
? section_types
|
||||
.where(
|
||||
(sectionType) => sectionType != "Menu")
|
||||
.toList()
|
||||
: section_types
|
||||
.toList(), // Todo get menu by enum type
|
||||
initialValue: "Map",
|
||||
onChange: (String? value) {
|
||||
sectionDTO.type = SectionType.fromJson(value);
|
||||
},
|
||||
),
|
||||
/*MultiSelectContainer(
|
||||
label: "Type:",
|
||||
initialValue: isMobile ? ["Article"] : ["Map"],
|
||||
isMultiple: false,
|
||||
values: isMobile ? section_types.where((sectionType) => sectionType == "Article" || sectionType == "Quizz").toList(): isSubSection ? section_types.where((sectionType) => sectionType != "Menu" && sectionType != "Article").toList(): section_types.where((sectionType) => sectionType != "Article").toList(), // Todo get menu by enum type
|
||||
onChanged: (value) {
|
||||
var tempOutput = new List<String>.from(value);
|
||||
sectionDTO.type = SectionType.fromJson(tempOutput[0]);
|
||||
},
|
||||
),*/
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: l.cancel,
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: l.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if (sectionDTO.label != null &&
|
||||
sectionDTO.label!.length > 2) {
|
||||
//onYes();
|
||||
Navigator.of(context).pop(sectionDTO);
|
||||
//create(sectionDTO, appContext, context, isSubSection, sendSubSection);
|
||||
} else {
|
||||
showNotification(
|
||||
Colors.orange,
|
||||
kWhite,
|
||||
l.sectionNameRequired,
|
||||
context,
|
||||
null);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: l.cancel,
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: l.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if (sectionDTO.label != null &&
|
||||
sectionDTO.label!.length > 2) {
|
||||
//onYes();
|
||||
Navigator.of(context).pop(sectionDTO);
|
||||
//create(sectionDTO, appContext, context, isSubSection, sendSubSection);
|
||||
} else {
|
||||
showNotification(
|
||||
Colors.orange,
|
||||
kWhite,
|
||||
l.sectionNameRequired,
|
||||
context,
|
||||
null);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
context: contextBuild);
|
||||
|
||||
|
||||
@ -62,130 +62,92 @@ class _SectionReorderListState extends State<SectionReorderList> {
|
||||
final appContext = Provider.of<AppContext>(context);
|
||||
Size size = MediaQuery.of(context).size;
|
||||
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
ConfigurationDTO currentConfiguration = managerAppContext.selectedConfiguration!;
|
||||
|
||||
return Stack(
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0, top: 15.0),
|
||||
child: Container(
|
||||
height: size.height*0.3,
|
||||
child: ReorderableListView.builder(
|
||||
itemCount: sections.length,
|
||||
onReorder: _onReorder,
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: const EdgeInsets.symmetric(vertical: 20.0),
|
||||
itemBuilder: (context, index) {
|
||||
//final String productName = _products[index];
|
||||
return ListViewCardSections(
|
||||
sections,
|
||||
index,
|
||||
Key('$index'),
|
||||
false,
|
||||
//currentConfiguration.isMobile!,
|
||||
appContext,
|
||||
(section) {
|
||||
setState(() {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.selectedSection = section;
|
||||
appContext.setContext(managerAppContext);
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
/*children: List.generate(
|
||||
sections.length,
|
||||
(index) {
|
||||
return ListViewCardSections(
|
||||
sections,
|
||||
index,
|
||||
Key('$index'),
|
||||
appContext,
|
||||
(section) {
|
||||
setState(() {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.selectedSection = section;
|
||||
appContext.setContext(managerAppContext);
|
||||
});
|
||||
}
|
||||
);
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: StringInputContainer(
|
||||
label: "Recherche:",
|
||||
isSmall: true,
|
||||
fontSize: 15,
|
||||
fontSizeText: 15,
|
||||
onChanged: (String value) {
|
||||
setState(() {
|
||||
filterSearch = value;
|
||||
filterResource();
|
||||
});
|
||||
},
|
||||
),*/
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 10,
|
||||
left: 10,
|
||||
child: Text(
|
||||
"Sections",
|
||||
style: TextStyle(fontSize: 15),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -20,
|
||||
left: 10,
|
||||
child: Container(
|
||||
height: size.height*0.1,
|
||||
constraints: BoxConstraints(minHeight: 85),
|
||||
child: StringInputContainer(
|
||||
label: "Recherche:",
|
||||
isSmall: true,
|
||||
fontSize: 15,
|
||||
fontSizeText: 15,
|
||||
onChanged: (String value) {
|
||||
setState(() {
|
||||
filterSearch = value;
|
||||
filterResource();
|
||||
});
|
||||
const SizedBox(width: 8),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
var sectionToCreate = await showNewSection(widget.configurationId, appContext, context, false);
|
||||
if (sectionToCreate != null) {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
sectionToCreate.instanceId = managerAppContext.instanceId;
|
||||
sectionToCreate.isBeacon = false;
|
||||
sectionToCreate.dateCreation = DateTime.now();
|
||||
await managerAppContext.clientAPI!.sectionApi!.sectionCreate(sectionToCreate);
|
||||
showNotification(kSuccess, kWhite, 'La section a été créée avec succès !', context, null);
|
||||
widget.askReload();
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
height: 36,
|
||||
width: 36,
|
||||
decoration: BoxDecoration(
|
||||
color: kSuccess,
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.add,
|
||||
color: kTextLightColor,
|
||||
size: 20.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
height: size.height * 0.3,
|
||||
child: ReorderableListView.builder(
|
||||
itemCount: sections.length,
|
||||
onReorder: _onReorder,
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
itemBuilder: (context, index) {
|
||||
return ListViewCardSections(
|
||||
sections,
|
||||
index,
|
||||
Key('$index'),
|
||||
false,
|
||||
appContext,
|
||||
(section) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.selectedSection = section;
|
||||
appContext.setContext(managerAppContext);
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 10,
|
||||
right: 10,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
var sectionToCreate = await showNewSection(widget.configurationId, appContext, context, false);
|
||||
if(sectionToCreate != null)
|
||||
{
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
sectionToCreate.instanceId = managerAppContext.instanceId;
|
||||
sectionToCreate.isBeacon = false;
|
||||
sectionToCreate.dateCreation = DateTime.now();
|
||||
SectionDTO? newSection = await managerAppContext.clientAPI!.sectionApi!.sectionCreate(sectionToCreate);
|
||||
|
||||
showNotification(kSuccess, kWhite, 'La section a été créée avec succès !', context, null);
|
||||
|
||||
widget.askReload();
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
height: MediaQuery.of(context).size.width * 0.04,
|
||||
width: MediaQuery.of(context).size.width * 0.04,
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: kTextLightColor,
|
||||
size: 30.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: kSuccess,
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@ -15,236 +15,221 @@ import 'package:manager_api_new/api.dart';
|
||||
import '../../Components/resource_input_container.dart';
|
||||
import 'dropDown_configuration.dart';
|
||||
|
||||
showChangeInfo (String text, DeviceDTO inputDevice, AppConfigurationLinkDTO appConfiguration, Function onGetResult, int maxLines, BuildContext mainContext, dynamic appContext) async {
|
||||
Size size = MediaQuery.of(mainContext).size;
|
||||
|
||||
showChangeInfo(String text, DeviceDTO inputDevice, AppConfigurationLinkDTO appConfiguration, Function onGetResult, int maxLines, BuildContext mainContext, dynamic appContext) async {
|
||||
var result = await showDialog(
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
useRootNavigator: false,
|
||||
builder: (BuildContext context) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
title: Center(child: Text(text)),
|
||||
content: Container(
|
||||
width: size.width * 0.5,
|
||||
height: size.height * 0.5,
|
||||
constraints: BoxConstraints(minWidth: 400, minHeight: 500),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
width: size.width * 0.3,
|
||||
height: size.height * 0.15,
|
||||
child: StringInputContainer(
|
||||
label: "Nom:",
|
||||
initialValue: inputDevice.name,
|
||||
onChanged: (value) {
|
||||
inputDevice.name = value;
|
||||
},
|
||||
maxLength: 20,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: Text("Configuration:", style: TextStyle(fontSize: 25, fontWeight: FontWeight.w300))
|
||||
),
|
||||
Container(
|
||||
height: size.height * 0.1,
|
||||
child: FutureBuilder(
|
||||
future: getConfigurations(appContext),
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.data.length > 0) {
|
||||
return Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: DropDownConfig(
|
||||
child: SizedBox(
|
||||
width: 580,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(child: Text(text, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500))),
|
||||
const SizedBox(height: 16),
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Nom + Configuration
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 220,
|
||||
height: 90,
|
||||
child: StringInputContainer(
|
||||
label: "Nom:",
|
||||
initialValue: inputDevice.name,
|
||||
onChanged: (value) => inputDevice.name = value,
|
||||
maxLength: 20,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text("Configuration:", style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w400)),
|
||||
const SizedBox(width: 8),
|
||||
FutureBuilder(
|
||||
future: getConfigurations(appContext),
|
||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.data != null && snapshot.data.length > 0) {
|
||||
return DropDownConfig(
|
||||
configurations: snapshot.data,
|
||||
selectedConfigurationId: inputDevice.configurationId!,
|
||||
onChange: (ConfigurationDTO configurationOut) {
|
||||
inputDevice.configuration = configurationOut.label;
|
||||
inputDevice.configurationId = configurationOut.id;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Text(AppLocalizations.of(context)!.noConfigFound);
|
||||
}
|
||||
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return Text("No data");
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
child: Text("Loading..")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return Text(AppLocalizations.of(context)!.noConfigFound);
|
||||
}
|
||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||
return const Text("No data");
|
||||
} else {
|
||||
return const SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2));
|
||||
}
|
||||
}
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
ColorPickerInputContainer(
|
||||
label: "Couleur principale :",
|
||||
fontSize: 20,
|
||||
color: appConfiguration.primaryColor,
|
||||
onChanged: (value) {
|
||||
appConfiguration.primaryColor = value;
|
||||
},
|
||||
),
|
||||
ColorPickerInputContainer(
|
||||
label: AppLocalizations.of(context)!.backgroundColorLabel,
|
||||
fontSize: 20,
|
||||
color: appConfiguration.secondaryColor,
|
||||
onChanged: (value) {
|
||||
appConfiguration.secondaryColor = value;
|
||||
},
|
||||
),
|
||||
ResourceInputContainer(
|
||||
label: "Loader :",
|
||||
initialValue: appConfiguration.loaderImageId,
|
||||
color: kPrimaryColor,
|
||||
imageFit: BoxFit.fitHeight,
|
||||
onChanged: (ResourceDTO resource) async {
|
||||
if(resource.id == null) {
|
||||
appConfiguration.loaderImageId = null;
|
||||
appConfiguration.loaderImageUrl = null;
|
||||
} else {
|
||||
appConfiguration.loaderImageId = resource.id;
|
||||
appConfiguration.loaderImageUrl = resource.url;
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Container(
|
||||
height: 100,
|
||||
child: NumberInputContainer(
|
||||
label: "Place des sections (%) :",
|
||||
initialValue: appConfiguration.screenPercentageSectionsMainPage ?? 0,
|
||||
isSmall: true,
|
||||
maxLength: 3,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
appConfiguration.screenPercentageSectionsMainPage = int.parse(value);
|
||||
} catch (e) {
|
||||
print('Screen percentage value not a number');
|
||||
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
|
||||
}
|
||||
},
|
||||
const SizedBox(height: 12),
|
||||
// Couleurs + Loader
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
ColorPickerInputContainer(
|
||||
label: "Couleur principale :",
|
||||
fontSize: 16,
|
||||
color: appConfiguration.primaryColor,
|
||||
onChanged: (value) => appConfiguration.primaryColor = value,
|
||||
),
|
||||
ColorPickerInputContainer(
|
||||
label: AppLocalizations.of(context)!.backgroundColorLabel,
|
||||
fontSize: 16,
|
||||
color: appConfiguration.secondaryColor,
|
||||
onChanged: (value) => appConfiguration.secondaryColor = value,
|
||||
),
|
||||
ResourceInputContainer(
|
||||
label: "Loader :",
|
||||
initialValue: appConfiguration.loaderImageId,
|
||||
color: kPrimaryColor,
|
||||
imageFit: BoxFit.fitHeight,
|
||||
onChanged: (ResourceDTO resource) async {
|
||||
if (resource.id == null) {
|
||||
appConfiguration.loaderImageId = null;
|
||||
appConfiguration.loaderImageUrl = null;
|
||||
} else {
|
||||
appConfiguration.loaderImageId = resource.id;
|
||||
appConfiguration.loaderImageUrl = resource.url;
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Pourcentages
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 90,
|
||||
child: NumberInputContainer(
|
||||
label: "Place des sections (%) :",
|
||||
initialValue: appConfiguration.screenPercentageSectionsMainPage ?? 0,
|
||||
isSmall: true,
|
||||
maxLength: 3,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
appConfiguration.screenPercentageSectionsMainPage = int.parse(value);
|
||||
} catch (e) {
|
||||
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 90,
|
||||
child: NumberInputContainer(
|
||||
label: "Pourcentage des arrondis (0-50) :",
|
||||
initialValue: appConfiguration.roundedValue ?? 0,
|
||||
isSmall: true,
|
||||
maxLength: 2,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
appConfiguration.roundedValue = int.parse(value);
|
||||
} catch (e) {
|
||||
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Toggles
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
CheckInputContainer(
|
||||
icon: Icons.image,
|
||||
label: "Fond pour les images des sections :",
|
||||
fontSize: 16,
|
||||
isChecked: appConfiguration.isSectionImageBackground,
|
||||
onChanged: (value) => appConfiguration.isSectionImageBackground = value,
|
||||
),
|
||||
CheckInputContainer(
|
||||
icon: Icons.watch_later_outlined,
|
||||
label: "Heure :",
|
||||
fontSize: 16,
|
||||
isChecked: appConfiguration.isHour,
|
||||
onChanged: (value) => appConfiguration.isHour = value,
|
||||
),
|
||||
CheckInputContainer(
|
||||
icon: Icons.date_range,
|
||||
label: "Date :",
|
||||
fontSize: 16,
|
||||
isChecked: appConfiguration.isDate,
|
||||
onChanged: (value) => appConfiguration.isDate = value,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 100,
|
||||
child: NumberInputContainer(
|
||||
label: "Pourcentage des arrondis (0-50) :",
|
||||
initialValue: appConfiguration.roundedValue ?? 0,
|
||||
isSmall: true,
|
||||
maxLength: 2,
|
||||
onChanged: (value) {
|
||||
try {
|
||||
appConfiguration.roundedValue = int.parse(value);
|
||||
} catch (e) {
|
||||
print('Rounded value not a number');
|
||||
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: WrapAlignment.end,
|
||||
children: [
|
||||
RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () => Navigator.of(context).pop(),
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
CheckInputContainer(
|
||||
icon: Icons.image,
|
||||
label: "Fond pour les images des sections :",
|
||||
fontSize: 20,
|
||||
isChecked: appConfiguration.isSectionImageBackground,
|
||||
onChanged: (value) {
|
||||
appConfiguration.isSectionImageBackground = value;
|
||||
},
|
||||
),
|
||||
CheckInputContainer(
|
||||
icon: Icons.watch_later_outlined,
|
||||
label: "Heure :",
|
||||
fontSize: 20,
|
||||
isChecked: appConfiguration.isHour,
|
||||
onChanged: (value) {
|
||||
appConfiguration.isHour = value;
|
||||
},
|
||||
),
|
||||
CheckInputContainer(
|
||||
icon: Icons.date_range,
|
||||
label: "Date :",
|
||||
fontSize: 20,
|
||||
isChecked: appConfiguration.isDate,
|
||||
onChanged: (value) {
|
||||
appConfiguration.isDate = value;
|
||||
},
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
RoundedButton(
|
||||
text: "Changer",
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
onGetResult(inputDevice, appConfiguration);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Container(
|
||||
width: 180,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Annuler",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
width: 180,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: "Changer",
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
onGetResult(inputDevice, appConfiguration);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
), context: mainContext
|
||||
);
|
||||
}
|
||||
|
||||
getConfigurationsElement(DeviceDTO inputDevice, data, Function onGetResult) {
|
||||
List<Widget> widgets = <Widget>[];
|
||||
for(var configuration in data as List<ConfigurationDTO>) {
|
||||
for (var configuration in data as List<ConfigurationDTO>) {
|
||||
var widget = new InkWell(
|
||||
onTap: () {
|
||||
inputDevice.configuration = configuration.label;
|
||||
@ -264,15 +249,8 @@ getConfigurationsElement(DeviceDTO inputDevice, data, Function onGetResult) {
|
||||
}
|
||||
|
||||
Future<List<ConfigurationDTO>?> getConfigurations(AppContext appContext) async {
|
||||
List<ConfigurationDTO>? configurations = await (appContext.getContext() as ManagerAppContext).clientAPI!.configurationApi!.configurationGet(instanceId: (appContext.getContext() as ManagerAppContext).instanceId);
|
||||
//print("number of configurations " + configurations.length.toString());
|
||||
|
||||
if(configurations != null) {
|
||||
configurations.forEach((element) {
|
||||
//print(element);
|
||||
});
|
||||
}
|
||||
|
||||
return configurations;
|
||||
return (appContext.getContext() as ManagerAppContext)
|
||||
.clientAPI!
|
||||
.configurationApi!
|
||||
.configurationGet(instanceId: (appContext.getContext() as ManagerAppContext).instanceId);
|
||||
}
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ class _DeviceElementState extends State<DeviceElement> {
|
||||
children: [
|
||||
AutoSizeText(
|
||||
widget.deviceDTO.name != null ? widget.deviceDTO.name! : widget.deviceDTO.identifier!,
|
||||
style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w300),
|
||||
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
|
||||
maxLines: 1,
|
||||
),
|
||||
],
|
||||
@ -75,7 +75,7 @@ class _DeviceElementState extends State<DeviceElement> {
|
||||
Center(
|
||||
child: Text(
|
||||
updatedDevice?.configuration != null ? updatedDevice?.configuration! ?? "Aucune configuration" : "Aucune configuration",
|
||||
style: new TextStyle(fontSize: 20),
|
||||
style: const TextStyle(fontSize: 13),
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
|
||||
@ -60,23 +60,18 @@ class _KioskScreenState extends State<KioskScreen> {
|
||||
List<AppConfigurationLinkDTO>? appConfigurationLinks = snapshot.data;
|
||||
|
||||
if (snapshot.connectionState == ConnectionState.done && appConfigurationLinks != null) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final itemWidth = 175;
|
||||
final crossAxisCount = (screenWidth / itemWidth).floor().clamp(1, 6);
|
||||
|
||||
return GridView.builder(
|
||||
shrinkWrap: true,
|
||||
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: crossAxisCount),
|
||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 220,
|
||||
childAspectRatio: 1.5,
|
||||
mainAxisSpacing: 10,
|
||||
crossAxisSpacing: 10,
|
||||
),
|
||||
itemCount: appConfigurationLinks.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return Container(
|
||||
decoration: boxDecoration(),
|
||||
padding: const EdgeInsets.all(10),
|
||||
margin: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: DeviceElement(deviceDTO: appConfigurationLinks[index].device!, appConfigurationLinkDTO: appConfigurationLinks[index]), //getElement()
|
||||
),
|
||||
return _DeviceCard(
|
||||
deviceLink: appConfigurationLinks[index],
|
||||
);
|
||||
}
|
||||
);
|
||||
@ -243,20 +238,47 @@ class _KioskScreenState extends State<KioskScreen> {
|
||||
}*/
|
||||
}
|
||||
|
||||
boxDecoration() {
|
||||
return BoxDecoration(
|
||||
color: kTextLightColor,
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
class _DeviceCard extends StatefulWidget {
|
||||
final AppConfigurationLinkDTO deviceLink;
|
||||
const _DeviceCard({required this.deviceLink});
|
||||
|
||||
@override
|
||||
State<_DeviceCard> createState() => _DeviceCardState();
|
||||
}
|
||||
|
||||
class _DeviceCardState extends State<_DeviceCard> {
|
||||
bool _hovered = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => _hovered = true),
|
||||
onExit: (_) => setState(() => _hovered = false),
|
||||
child: AnimatedScale(
|
||||
scale: _hovered ? 1.03 : 1.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: kTextLightColor,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: _hovered ? 1 : 0.5,
|
||||
blurRadius: _hovered ? 10 : 5,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: DeviceElement(
|
||||
deviceDTO: widget.deviceLink.device!,
|
||||
appConfigurationLinkDTO: widget.deviceLink,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<DeviceDTO>?> getDevices(AppContext appContext) async {
|
||||
|
||||
@ -14,6 +14,7 @@ import 'package:manager_app/Screens/Kiosk_devices/kiosk_screen.dart';
|
||||
import 'package:manager_app/Screens/Resources/resources_screen.dart';
|
||||
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/web_app_screen.dart';
|
||||
import 'package:manager_app/Screens/Notifications/notifications_screen.dart';
|
||||
import 'package:manager_app/Screens/Users/users_screen.dart';
|
||||
import 'package:manager_app/l10n/app_localizations.dart';
|
||||
@ -430,47 +431,54 @@ class _MainScreenState extends State<MainScreen> {
|
||||
child: Column(
|
||||
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(
|
||||
(appContext.getContext() as ManagerAppContext).email ?? "",
|
||||
style: TextStyle(color: kBodyTextColor, fontSize: 16, fontWeight: FontWeight.w300, fontFamily: "Helvetica"),
|
||||
maxLines: 1,
|
||||
),
|
||||
if ((appContext.getContext() as ManagerAppContext).role == UserRole.SuperAdmin)
|
||||
IconButton(
|
||||
icon: Icon(Icons.swap_horiz, color: kPrimaryColor),
|
||||
tooltip: AppLocalizations.of(context)!.tooltipSwitchInstance,
|
||||
onPressed: () => _showSwitchInstanceDialog(context, appContext.getContext() as ManagerAppContext),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.logout, color: kPrimaryColor),
|
||||
onPressed: () async {
|
||||
var session = await loadJsonSessionFile();
|
||||
setState(() {
|
||||
Storage localStorage = window.localStorage;
|
||||
localStorage.clear();
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.accessToken = null;
|
||||
managerAppContext.instanceId = null;
|
||||
managerAppContext.instanceDTO = null;
|
||||
appContext.setContext(managerAppContext);
|
||||
Row(
|
||||
children: [
|
||||
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(width: 8),
|
||||
Expanded(
|
||||
child: AutoSizeText(
|
||||
(appContext.getContext() as ManagerAppContext).email ?? "",
|
||||
style: TextStyle(color: kBodyTextColor, fontSize: 14, fontWeight: FontWeight.w300, fontFamily: "Helvetica"),
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
if ((appContext.getContext() as ManagerAppContext).role == UserRole.SuperAdmin)
|
||||
IconButton(
|
||||
icon: Icon(Icons.swap_horiz, color: kPrimaryColor),
|
||||
tooltip: AppLocalizations.of(context)!.tooltipSwitchInstance,
|
||||
onPressed: () => _showSwitchInstanceDialog(context, appContext.getContext() as ManagerAppContext),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.logout, color: kPrimaryColor),
|
||||
tooltip: AppLocalizations.of(context)!.tooltipLogout,
|
||||
onPressed: () async {
|
||||
await loadJsonSessionFile();
|
||||
setState(() {
|
||||
Storage localStorage = window.localStorage;
|
||||
localStorage.clear();
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
managerAppContext.accessToken = null;
|
||||
managerAppContext.instanceId = null;
|
||||
managerAppContext.instanceDTO = null;
|
||||
appContext.setContext(managerAppContext);
|
||||
|
||||
context.go('/login');
|
||||
});
|
||||
},
|
||||
context.go('/login');
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
@ -597,25 +605,24 @@ class _MainScreenState extends State<MainScreen> {
|
||||
|
||||
switch (elementToShow.type) {
|
||||
case 'mobile' :
|
||||
var applicationInstanceMobile = instanceDTO.applicationInstanceDTOs!.firstWhere((ai) => ai.appType == AppType.Mobile);
|
||||
var applicationInstanceMobile = instanceDTO.applicationInstanceDTOs?.firstWhereOrNull((ai) => ai.appType == AppType.Mobile);
|
||||
if (applicationInstanceMobile == null) return const Center(child: Text('Application mobile non configurée'));
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: AppConfigurationLinkScreen(applicationInstanceDTO: applicationInstanceMobile)
|
||||
);
|
||||
case 'kiosk' :
|
||||
var applicationInstanceTablet = instanceDTO.applicationInstanceDTOs!.firstWhere((ai) => ai.appType == AppType.Tablet);
|
||||
var applicationInstanceTablet = instanceDTO.applicationInstanceDTOs?.firstWhereOrNull((ai) => ai.appType == AppType.Tablet);
|
||||
if (applicationInstanceTablet == null) return const Center(child: Text('Application kiosk non configurée'));
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: KioskScreen(applicationInstanceDTO: applicationInstanceTablet)
|
||||
);
|
||||
case 'web' :
|
||||
var applicationInstanceWeb = instanceDTO.applicationInstanceDTOs!.firstWhere((ai) => ai.appType == AppType.Web);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text("TODO web")
|
||||
);
|
||||
return const WebInstanceLoader();
|
||||
case 'vr' :
|
||||
var applicationInstanceVR = instanceDTO.applicationInstanceDTOs!.firstWhere((ai) => ai.appType == AppType.VR);
|
||||
var applicationInstanceVR = instanceDTO.applicationInstanceDTOs?.firstWhereOrNull((ai) => ai.appType == AppType.VR);
|
||||
if (applicationInstanceVR == null) return const Center(child: Text('Application VR non configurée'));
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text("TODO vr")
|
||||
|
||||
@ -275,7 +275,9 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
_KpiCard(
|
||||
label: l.allNotifications,
|
||||
@ -284,7 +286,6 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
||||
selected: _statusFilter == null,
|
||||
onTap: () => _setFilter(null),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_KpiCard(
|
||||
label: l.sentNotifications,
|
||||
count: _sentCount,
|
||||
@ -292,7 +293,6 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
||||
selected: _statusFilter == 'Sent',
|
||||
onTap: () => _setFilter('Sent'),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_KpiCard(
|
||||
label: l.scheduledNotifications,
|
||||
count: _scheduledCount,
|
||||
@ -300,7 +300,6 @@ class _NotificationsScreenState extends State<NotificationsScreen> {
|
||||
selected: _statusFilter == 'Scheduled',
|
||||
onTap: () => _setFilter('Scheduled'),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_KpiCard(
|
||||
label: l.failedNotifications,
|
||||
count: _failedCount,
|
||||
|
||||
@ -13,112 +13,89 @@ import 'package:manager_api_new/api.dart';
|
||||
|
||||
dynamic showNewResource(AppContext appContext, BuildContext context) async {
|
||||
ResourceDTO resourceDetailDTO = new ResourceDTO();
|
||||
Size size = MediaQuery.of(context).size;
|
||||
var fileName;
|
||||
List<File>? filesToSend;
|
||||
List<PlatformFile>? filesToSendWeb;
|
||||
|
||||
var result = await showDialog(
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
builder: (BuildContext context) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
content: Container(
|
||||
width: size.width *0.5,
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: 560,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(AppLocalizations.of(context)!.newResource, style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
|
||||
/*Column(
|
||||
children: [
|
||||
StringInputContainer(
|
||||
label: "Nom :",
|
||||
initialValue: resourceDetailDTO.label,
|
||||
onChanged: (value) {
|
||||
resourceDetailDTO.label = value;
|
||||
},
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context)!.newResource,
|
||||
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.w400),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
height: 400,
|
||||
child: ResourceTab(
|
||||
resourceDTO: resourceDetailDTO,
|
||||
onFileUpload: (List<File> files) {
|
||||
filesToSend = files;
|
||||
},
|
||||
onFileUploadWeb: (List<PlatformFile> files) {
|
||||
filesToSendWeb = files;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (fileName != null) new Text(fileName),
|
||||
],
|
||||
),*/
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
child: Container(
|
||||
width: size.width *0.85,
|
||||
height: size.height *0.5,
|
||||
child: ResourceTab(
|
||||
resourceDTO: resourceDetailDTO,
|
||||
onFileUpload: (List<File> files) {
|
||||
filesToSend = files;
|
||||
},
|
||||
onFileUploadWeb: (List<PlatformFile> files) {
|
||||
filesToSendWeb = files;
|
||||
},
|
||||
)
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.cancel,
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 150,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
text: AppLocalizations.of(context)!.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
//if (resourceDetailDTO.label != null && resourceDetailDTO.label!.trim() != '') {
|
||||
if(kIsWeb) {
|
||||
if(resourceDetailDTO.url != null || filesToSendWeb != null) { // TODO clarify resourceDetailDTO.data != null
|
||||
const SizedBox(height: 16),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: WrapAlignment.end,
|
||||
children: [
|
||||
RoundedButton(
|
||||
text: AppLocalizations.of(context)!.cancel,
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () => Navigator.of(context).pop(),
|
||||
fontSize: 16,
|
||||
),
|
||||
RoundedButton(
|
||||
text: AppLocalizations.of(context)!.create,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
if (kIsWeb) {
|
||||
if (resourceDetailDTO.url != null || filesToSendWeb != null) {
|
||||
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
|
||||
} else {
|
||||
showNotification(Colors.orange, kWhite, AppLocalizations.of(context)!.resourceNoFileLoaded, context, null);
|
||||
}
|
||||
} 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) {
|
||||
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
|
||||
} else {
|
||||
showNotification(Colors.orange, kWhite, AppLocalizations.of(context)!.resourceNoFileLoaded, context, null);
|
||||
}
|
||||
}
|
||||
/*} else {
|
||||
showNotification(Colors.orange, kWhite, 'Veuillez donner un nom à la ressource', context, null);
|
||||
}*/
|
||||
//Navigator.of(context).pop();
|
||||
//create(resourceDetailDTO, fileToSend, appContext, context);
|
||||
},
|
||||
fontSize: 20,
|
||||
),
|
||||
},
|
||||
fontSize: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
), context: context
|
||||
);
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:diacritic/diacritic.dart';
|
||||
|
||||
class ResourceBodyGrid extends StatefulWidget {
|
||||
final List<ResourceDTO> resources; //return ResourceDTO
|
||||
final List<ResourceDTO> resources;
|
||||
final Function onSelect;
|
||||
final bool isAddButton;
|
||||
final bool isSelectModal;
|
||||
@ -22,7 +22,7 @@ class ResourceBodyGrid extends StatefulWidget {
|
||||
required this.onSelect,
|
||||
required this.isAddButton,
|
||||
required this.resourceTypesIn,
|
||||
this.isSelectModal = false
|
||||
this.isSelectModal = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@ -39,34 +39,42 @@ class _ResourceBodyGridState extends State<ResourceBodyGrid> {
|
||||
@override
|
||||
void initState() {
|
||||
resourcesToShow = widget.resources;
|
||||
currentFilterTypes = resource_types.where((rt) => widget.resourceTypesIn.contains(rt.type)).map((rt) => rt.label).toList();//, resource_types[2]]; // resource_types[3]
|
||||
filterTypes = resource_types.where((rt) => widget.resourceTypesIn.contains(rt.type)).map((rt) => rt.label).toList();//, resource_types[2]]; // resource_types[3]
|
||||
selectedTypes = resource_types.where((rt) => widget.resourceTypesIn.contains(rt.type)).map((rt) => rt.label).toList();
|
||||
currentFilterTypes = resource_types
|
||||
.where((rt) => widget.resourceTypesIn.contains(rt.type))
|
||||
.map((rt) => rt.label)
|
||||
.toList();
|
||||
filterTypes = resource_types
|
||||
.where((rt) => widget.resourceTypesIn.contains(rt.type))
|
||||
.map((rt) => rt.label)
|
||||
.toList();
|
||||
selectedTypes = resource_types
|
||||
.where((rt) => widget.resourceTypesIn.contains(rt.type))
|
||||
.map((rt) => rt.label)
|
||||
.toList();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appContext = Provider.of<AppContext>(context);
|
||||
Size size = MediaQuery.of(context).size;
|
||||
|
||||
return bodyGrid(resourcesToShow, size, appContext);
|
||||
return bodyGrid(resourcesToShow, appContext);
|
||||
}
|
||||
|
||||
Widget bodyGrid(data, Size size, AppContext appContext) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final itemWidth = 150;
|
||||
final crossAxisCount = (screenWidth / itemWidth).floor().clamp(1, 9);
|
||||
Widget bodyGrid(List<ResourceDTO> data, AppContext appContext) {
|
||||
final canEdit = (appContext.getContext() as ManagerAppContext).canEdit;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: StringInputContainer(
|
||||
label: "Recherche:",
|
||||
// Header: search + filter + add button — Wrap pour mobile
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 8, 8, 4),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
StringInputContainer(
|
||||
label: 'Recherche:',
|
||||
onChanged: (String value) {
|
||||
setState(() {
|
||||
filterSearch = value;
|
||||
@ -74,156 +82,214 @@ class _ResourceBodyGridState extends State<ResourceBodyGrid> {
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: MultiSelectContainer(
|
||||
label: "Type:",
|
||||
MultiSelectContainer(
|
||||
label: 'Type:',
|
||||
initialValue: filterTypes,
|
||||
values: currentFilterTypes,
|
||||
isMultiple: true,
|
||||
onChanged: (result) {
|
||||
setState(() {
|
||||
selectedTypes = result as List<String>; // TO TEST
|
||||
selectedTypes = result as List<String>;
|
||||
filterResource();
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.isAddButton && (appContext.getContext() as ManagerAppContext).canEdit)
|
||||
InkWell(
|
||||
onTap: () {
|
||||
widget.onSelect(ResourceDTO(id: widget.isSelectModal ? "-1" : null));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
height: size.height *0.08,
|
||||
width: size.height *0.08,
|
||||
decoration: BoxDecoration(
|
||||
color: kSuccess,
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
),
|
||||
child:
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: LayoutBuilder(builder: (context, constraint) {
|
||||
return new Icon(Icons.add, size: constraint.biggest.height, color: kTextLightColor);
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
if (widget.isAddButton && canEdit)
|
||||
_AddButton(onTap: () {
|
||||
widget.onSelect(
|
||||
ResourceDTO(id: widget.isSelectModal ? '-1' : null));
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Grid
|
||||
Expanded(
|
||||
child: GridView.builder(
|
||||
shrinkWrap: true,
|
||||
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: crossAxisCount),
|
||||
itemCount: data.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return
|
||||
InkWell(
|
||||
onTap: () {
|
||||
widget.onSelect(resourcesToShow[index]);
|
||||
},
|
||||
child: Container(
|
||||
decoration: boxDecoration(data[index], appContext),
|
||||
padding: const EdgeInsets.all(15),
|
||||
margin: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: getElement(data[index], size, appContext)
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 160,
|
||||
childAspectRatio: 1.0,
|
||||
mainAxisSpacing: 10,
|
||||
crossAxisSpacing: 10,
|
||||
),
|
||||
itemCount: data.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return _ResourceCard(
|
||||
resource: resourcesToShow[index],
|
||||
onTap: () => widget.onSelect(resourcesToShow[index]),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
getElement(ResourceDTO resource, Size size, AppContext appContext) {
|
||||
if (resource.id != null) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: size.width *0.01,
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: AutoSizeText(
|
||||
resource.label == null ? "" : resource.label!,
|
||||
style: new TextStyle(fontSize: 20),
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Icon(
|
||||
getResourceIcon(resource.type),
|
||||
color: kPrimaryColor,
|
||||
size: 15,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Icon(
|
||||
Icons.close,
|
||||
color: kTextLightColor,
|
||||
size: 50.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void filterResource() {
|
||||
resourcesToShow = filterSearch.isEmpty ? widget.resources: widget.resources.where((ResourceDTO resource) => resource.id == null || removeDiacritics(resource.label!.toUpperCase()).contains(removeDiacritics(filterSearch.toUpperCase()))).toList();
|
||||
var getTypesInSelected = resource_types.where((ft) => selectedTypes.contains(ft.label)).map((rt) => rt.type).toList();
|
||||
resourcesToShow = resourcesToShow.where((resource) => resource.id == null || getTypesInSelected.contains(resource.type)).toList();
|
||||
resourcesToShow = filterSearch.isEmpty
|
||||
? widget.resources
|
||||
: widget.resources
|
||||
.where((ResourceDTO resource) =>
|
||||
resource.id == null ||
|
||||
removeDiacritics(resource.label!.toUpperCase())
|
||||
.contains(removeDiacritics(filterSearch.toUpperCase())))
|
||||
.toList();
|
||||
var getTypesInSelected = resource_types
|
||||
.where((ft) => selectedTypes.contains(ft.label))
|
||||
.map((rt) => rt.type)
|
||||
.toList();
|
||||
resourcesToShow = resourcesToShow
|
||||
.where((resource) =>
|
||||
resource.id == null ||
|
||||
getTypesInSelected.contains(resource.type))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
boxDecoration(dynamic resourceDetailDTO, appContext) {
|
||||
return BoxDecoration(
|
||||
color: resourceDetailDTO.id == null ? kSecond : kBackgroundColor,
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
image: resourceDetailDTO.id != null && (resourceDetailDTO.type == ResourceType.Image || resourceDetailDTO.type == ResourceType.ImageUrl) && resourceDetailDTO.url != null ? new DecorationImage(
|
||||
fit: BoxFit.cover,
|
||||
colorFilter: new ColorFilter.mode(Colors.black.withValues(alpha: 0.3), BlendMode.dstATop),
|
||||
image: new NetworkImage(
|
||||
resourceDetailDTO.url!,
|
||||
// ── Add button ────────────────────────────────────────────────────────────────
|
||||
|
||||
class _AddButton extends StatelessWidget {
|
||||
final VoidCallback onTap;
|
||||
const _AddButton({required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
width: 56,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
color: kSuccess,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: const [kDefaultShadow],
|
||||
),
|
||||
child: const Icon(Icons.add, color: kTextLightColor, size: 28),
|
||||
),
|
||||
) : null,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5), // changes position of shadow
|
||||
),
|
||||
],
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Resource card ─────────────────────────────────────────────────────────────
|
||||
|
||||
/*Future<List<ResourceDTO>> getResources(Function onGetResult, bool isImage, AppContext appContext) async {
|
||||
List<ResourceDTO> resources = await (appContext.getContext() as ManagerAppContext).clientAPI.resourceApi.resourceGet(instanceId:(appContext.getContext() as ManagerAppContext).instanceId);
|
||||
if (onGetResult != null && isImage) {
|
||||
resources = resources.where((element) => element.type == ResourceType.image || element.type == ResourceType.imageUrl).toList();
|
||||
class _ResourceCard extends StatefulWidget {
|
||||
final ResourceDTO resource;
|
||||
final VoidCallback onTap;
|
||||
const _ResourceCard({required this.resource, required this.onTap});
|
||||
|
||||
@override
|
||||
State<_ResourceCard> createState() => _ResourceCardState();
|
||||
}
|
||||
|
||||
class _ResourceCardState extends State<_ResourceCard> {
|
||||
bool _hovered = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final resource = widget.resource;
|
||||
final isRemove = resource.id == null;
|
||||
final hasImage = !isRemove &&
|
||||
(resource.type == ResourceType.Image ||
|
||||
resource.type == ResourceType.ImageUrl) &&
|
||||
resource.url != null;
|
||||
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => _hovered = true),
|
||||
onExit: (_) => setState(() => _hovered = false),
|
||||
child: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: AnimatedScale(
|
||||
scale: _hovered ? 1.03 : 1.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: _hovered ? 1 : 0.5,
|
||||
blurRadius: _hovered ? 10 : 5,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// Background
|
||||
if (hasImage)
|
||||
Image.network(resource.url!, fit: BoxFit.cover)
|
||||
else
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: isRemove
|
||||
? [kSecond, kSecond.withValues(alpha: 0.7)]
|
||||
: [kPrimaryColor, kPrimaryColor.withValues(alpha: 0.65)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Gradient scrim (only when there's an image)
|
||||
if (hasImage)
|
||||
DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
stops: const [0.35, 1.0],
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black.withValues(alpha: 0.65),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// Type icon — top right badge
|
||||
if (!isRemove)
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.35),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Icon(
|
||||
getResourceIcon(resource.type),
|
||||
color: kTextLightColor,
|
||||
size: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Label — bottom left
|
||||
if (!isRemove)
|
||||
Positioned(
|
||||
left: 8,
|
||||
right: 8,
|
||||
bottom: 8,
|
||||
child: AutoSizeText(
|
||||
resource.label ?? '',
|
||||
style: kCardTitleStyle.copyWith(fontSize: 13),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
// Remove icon
|
||||
if (isRemove)
|
||||
const Center(
|
||||
child: Icon(Icons.close, color: kTextLightColor, size: 40),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return resources;
|
||||
}*/
|
||||
}
|
||||
|
||||
@ -15,126 +15,90 @@ import 'get_element_for_resource.dart';
|
||||
|
||||
Future<ResourceDTO?> showResource(ResourceDTO resourceDTO, AppContext appContext, BuildContext context, Size size) async {
|
||||
var result = await showDialog(
|
||||
builder: (BuildContext context) => AlertDialog(
|
||||
builder: (BuildContext context) => Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.6,
|
||||
height: MediaQuery.of(context).size.height * 0.2,
|
||||
child: StringInputContainer(
|
||||
label: "Label :",
|
||||
initialValue: resourceDTO.label != null ? resourceDTO.label : "",
|
||||
onChanged: (value) {
|
||||
resourceDTO.label = value;
|
||||
},
|
||||
),
|
||||
),/*Text(
|
||||
resourceDTO.label == null ? "" : resourceDTO.label,
|
||||
style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),*/
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: resourceDTO.type == ResourceType.Audio ? size.height *0.1 : size.height *0.3,
|
||||
width: resourceDTO.type == ResourceType.Audio ? size.width *0.1 : size.width *0.3,
|
||||
child: Center(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
border: Border.all(width: 3, color: kSecond)
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: getElementForResource(resourceDTO, appContext),
|
||||
child: SizedBox(
|
||||
width: 520,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 80,
|
||||
child: StringInputContainer(
|
||||
label: "Label :",
|
||||
initialValue: resourceDTO.label != null ? resourceDTO.label : "",
|
||||
onChanged: (value) {
|
||||
resourceDTO.label = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: resourceDTO.type == ResourceType.Audio ? 80 : 300,
|
||||
maxWidth: resourceDTO.type == ResourceType.Audio ? 200 : double.infinity,
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
border: Border.all(width: 3, color: kSecond),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: getElementForResource(resourceDTO, appContext),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 175,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
const SizedBox(height: 16),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
alignment: WrapAlignment.end,
|
||||
children: [
|
||||
RoundedButton(
|
||||
text: "Retour",
|
||||
icon: Icons.undo,
|
||||
color: kSecond,
|
||||
press: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
fontSize: 20,
|
||||
press: () => Navigator.of(context).pop(),
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 200,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
RoundedButton(
|
||||
text: "Supprimer",
|
||||
icon: Icons.delete,
|
||||
color: kError,
|
||||
textColor: kWhite,
|
||||
press: () {
|
||||
delete(resourceDTO, appContext, context);
|
||||
},
|
||||
fontSize: 20,
|
||||
press: () => delete(resourceDTO, appContext, context),
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 220,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
RoundedButton(
|
||||
text: AppLocalizations.of(context)!.download,
|
||||
icon: Icons.download,
|
||||
color: kPrimaryColor,
|
||||
press: () {
|
||||
if(resourceDTO.url != null) {
|
||||
if (resourceDTO.url != null) {
|
||||
html.AnchorElement anchorElement = html.AnchorElement(href: resourceDTO.url!);
|
||||
anchorElement.download = '${resourceDTO.label}.json';
|
||||
anchorElement.target = '_blank';
|
||||
anchorElement.click();
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Align(
|
||||
alignment: AlignmentDirectional.bottomEnd,
|
||||
child: Container(
|
||||
width: 220,
|
||||
height: 70,
|
||||
child: RoundedButton(
|
||||
RoundedButton(
|
||||
text: AppLocalizations.of(context)!.save,
|
||||
icon: Icons.check,
|
||||
color: kPrimaryColor,
|
||||
@ -143,14 +107,14 @@ Future<ResourceDTO?> showResource(ResourceDTO resourceDTO, AppContext appContext
|
||||
Navigator.pop(context, resourceDTO);
|
||||
}
|
||||
},
|
||||
fontSize: 20,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
), context: context
|
||||
);
|
||||
return result;
|
||||
@ -162,11 +126,9 @@ Future<void> delete(ResourceDTO resourceDTO, AppContext appContext, context) asy
|
||||
() {},
|
||||
() async {
|
||||
await (appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceDelete(resourceDTO.id!);
|
||||
// TODO Remove from firebase storage via service or ?
|
||||
|
||||
FirebaseStorage storage = FirebaseStorage.instance;
|
||||
Reference storageReference = storage.ref().child('pictures/${appContext.getContext().instanceId}/${resourceDTO.id}');
|
||||
// Supprimer le fichier
|
||||
try {
|
||||
await storageReference.delete();
|
||||
print('Fichier supprimé avec succès');
|
||||
@ -176,7 +138,6 @@ Future<void> delete(ResourceDTO resourceDTO, AppContext appContext, context) asy
|
||||
|
||||
try {} catch (e) {}
|
||||
|
||||
// just to refresh
|
||||
ManagerAppContext managerAppContext = appContext.getContext();
|
||||
appContext.setContext(managerAppContext);
|
||||
Navigator.of(context).pop();
|
||||
|
||||
@ -16,6 +16,34 @@ const kWhite = Color(0xFFFFFFFF);
|
||||
const kBlack = Color(0xFF000000);
|
||||
const kSuccess = Color(0xFF8bc34a);
|
||||
|
||||
// Responsive
|
||||
const kBreakpointMobile = 850.0;
|
||||
|
||||
// Shadows
|
||||
const kDefaultShadow = BoxShadow(
|
||||
color: kSecond,
|
||||
spreadRadius: 0.5,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, 1.5),
|
||||
);
|
||||
|
||||
// TextStyles for cards
|
||||
const kCardTitleStyle = TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: kWhite,
|
||||
);
|
||||
const kCardSubtitleStyle = TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w300,
|
||||
color: Color(0xCCFFFFFF),
|
||||
);
|
||||
const kSectionLabelStyle = TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: kTitleTextColor,
|
||||
);
|
||||
|
||||
const List<String> section_types = ["Map", "Slider", "Video", "Web", "Menu", "Quiz", "Article", "PDF", "Game", "Agenda", "Weather", "Event"];
|
||||
const List<String> map_types = ["none", "normal", "satellite", "terrain", "hybrid"];
|
||||
const List<String> languages = ["FR", "NL", "EN", "DE", "IT", "ES", "CN", "PL", "AR", "UK"];
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
"noInstanceFound": "No instance found",
|
||||
"configurePlan": "Configure plan",
|
||||
"tooltipSwitchInstance": "Switch instance",
|
||||
"tooltipLogout": "Log out",
|
||||
|
||||
"usersTitle": "Users",
|
||||
"createUserBtn": "Create user",
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
"noInstanceFound": "Aucune instance trouvée",
|
||||
"configurePlan": "Configurer le plan",
|
||||
"tooltipSwitchInstance": "Changer d'instance",
|
||||
"tooltipLogout": "Se déconnecter",
|
||||
|
||||
"usersTitle": "Utilisateurs",
|
||||
"createUserBtn": "Créer un utilisateur",
|
||||
@ -369,7 +370,7 @@
|
||||
"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",
|
||||
"phoneConfigTitle": "Contenu de l'application mobile",
|
||||
"addConfig": "Ajouter une configuration",
|
||||
"selectConfigToAdd": "Sélectionner une configuration à ajouter",
|
||||
"noItems": "Aucun élément à afficher",
|
||||
|
||||
@ -328,6 +328,12 @@ abstract class AppLocalizations {
|
||||
/// **'Changer d\'instance'**
|
||||
String get tooltipSwitchInstance;
|
||||
|
||||
/// No description provided for @tooltipLogout.
|
||||
///
|
||||
/// In fr, this message translates to:
|
||||
/// **'Se déconnecter'**
|
||||
String get tooltipLogout;
|
||||
|
||||
/// No description provided for @usersTitle.
|
||||
///
|
||||
/// In fr, this message translates to:
|
||||
@ -1909,7 +1915,7 @@ abstract class AppLocalizations {
|
||||
/// No description provided for @phoneConfigTitle.
|
||||
///
|
||||
/// In fr, this message translates to:
|
||||
/// **'Configurations par appareil'**
|
||||
/// **'Contenu de l\'application mobile'**
|
||||
String get phoneConfigTitle;
|
||||
|
||||
/// No description provided for @addConfig.
|
||||
|
||||
@ -126,6 +126,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get tooltipSwitchInstance => 'Switch instance';
|
||||
|
||||
@override
|
||||
String get tooltipLogout => 'Log out';
|
||||
|
||||
@override
|
||||
String get usersTitle => 'Users';
|
||||
|
||||
|
||||
@ -127,6 +127,9 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
@override
|
||||
String get tooltipSwitchInstance => 'Changer d\'instance';
|
||||
|
||||
@override
|
||||
String get tooltipLogout => 'Se déconnecter';
|
||||
|
||||
@override
|
||||
String get usersTitle => 'Utilisateurs';
|
||||
|
||||
@ -998,7 +1001,7 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
'Une erreur est survenue lors du retrait de la configuration';
|
||||
|
||||
@override
|
||||
String get phoneConfigTitle => 'Configurations par appareil';
|
||||
String get phoneConfigTitle => 'Contenu de l\'application mobile';
|
||||
|
||||
@override
|
||||
String get addConfig => 'Ajouter une configuration';
|
||||
|
||||
@ -127,6 +127,9 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
@override
|
||||
String get tooltipSwitchInstance => 'Instantie wisselen';
|
||||
|
||||
@override
|
||||
String get tooltipLogout => 'Uitloggen';
|
||||
|
||||
@override
|
||||
String get usersTitle => 'Gebruikers';
|
||||
|
||||
|
||||
@ -52,6 +52,7 @@
|
||||
"noInstanceFound": "Geen instantie gevonden",
|
||||
"configurePlan": "Plan configureren",
|
||||
"tooltipSwitchInstance": "Instantie wisselen",
|
||||
"tooltipLogout": "Uitloggen",
|
||||
|
||||
"usersTitle": "Gebruikers",
|
||||
"createUserBtn": "Gebruiker aanmaken",
|
||||
|
||||
@ -49,13 +49,14 @@ Future<void> main() async {
|
||||
|
||||
usePathUrlStrategy();
|
||||
|
||||
runApp(
|
||||
runApp(
|
||||
ChangeNotifierProvider<AppContext>(
|
||||
create: (_) => AppContext(managerAppContext),
|
||||
child: MaterialApp(
|
||||
locale: const Locale('fr'),
|
||||
supportedLocales: const [Locale('fr')],
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
FlutterQuillLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
|
||||
@ -34,6 +34,8 @@ class InstanceDTO {
|
||||
this.statsHistoryDays,
|
||||
this.hasAdvancedStats,
|
||||
this.applicationInstanceDTOs = const [],
|
||||
this.webSlug,
|
||||
this.publicApiKey,
|
||||
});
|
||||
|
||||
String? id;
|
||||
@ -114,6 +116,10 @@ class InstanceDTO {
|
||||
|
||||
List<ApplicationInstanceDTO>? applicationInstanceDTOs;
|
||||
|
||||
String? webSlug;
|
||||
|
||||
String? publicApiKey;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
@ -272,6 +278,16 @@ class InstanceDTO {
|
||||
} else {
|
||||
json[r'applicationInstanceDTOs'] = null;
|
||||
}
|
||||
if (this.webSlug != null) {
|
||||
json[r'webSlug'] = this.webSlug;
|
||||
} else {
|
||||
json[r'webSlug'] = null;
|
||||
}
|
||||
if (this.publicApiKey != null) {
|
||||
json[r'publicApiKey'] = this.publicApiKey;
|
||||
} else {
|
||||
json[r'publicApiKey'] = null;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@ -318,6 +334,8 @@ class InstanceDTO {
|
||||
hasAdvancedStats: mapValueOfType<bool>(json, r'hasAdvancedStats'),
|
||||
applicationInstanceDTOs: ApplicationInstanceDTO.listFromJson(
|
||||
json[r'applicationInstanceDTOs']),
|
||||
webSlug: mapValueOfType<String>(json, r'webSlug'),
|
||||
publicApiKey: mapValueOfType<String>(json, r'publicApiKey'),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
70
web/favicon.svg
Normal file
70
web/favicon.svg
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
width="439"
|
||||
height="419"
|
||||
id="svg137"
|
||||
sodipodi:docname="MyInfoMate_logo_only.svg"
|
||||
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs137" />
|
||||
<sodipodi:namedview
|
||||
id="namedview137"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.6568543"
|
||||
inkscape:cx="348.69203"
|
||||
inkscape:cy="38.448931"
|
||||
inkscape:window-width="5120"
|
||||
inkscape:window-height="1369"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="1072"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg137" />
|
||||
<path
|
||||
d="m 178.04447,135.21247 c 0.002,9.09742 0.17625,49.4843 0.17178,58.58172 -0.005,10.44131 -0.004,20.8826 0.002,31.32392 0.005,9.06176 0.005,18.12351 0.003,27.18527 -0.002,5.37036 -0.002,10.7407 0.002,16.11105 0.0204,38.14483 0.0204,38.14483 -0.54694,53.99548 l -0.10305,3.01772 c -0.80885,18.6575 -7.8096,35.94603 -20.4863,49.70518 l -2.15235,2.35938 c -12.39998,12.98838 -30.69723,23.86033 -49.02594,24.74586 -2.64076,0.0575 -5.28022,0.0839 -7.921566,0.10008 l -3.044189,0.03 c -3.328264,0.0316 -6.656542,0.0564 -9.984864,0.0811 -2.346596,0.0206 -4.693189,0.0416 -7.039779,0.063 -4.940416,0.044 -9.880843,0.0849 -14.821305,0.12331 -6.216775,0.0484 -12.433489,0.10212 -18.650202,0.158 -6.037887,0.054 -17.776846,0.19345 -40.2740759,0.28883 L 57.571753,137.10368 c 14.685204,-1.44088 35.90966,0.0974 45.537897,0.12284 41.79401,0.11064 74.93393,-6.04872 74.93482,-2.01405 z"
|
||||
fill="#d62f60"
|
||||
id="path1"
|
||||
transform="translate(249.91406,6.8671875)"
|
||||
sodipodi:nodetypes="cscsccccccccccscccsc" />
|
||||
<path
|
||||
d="m 64.688834,203.13197 c 0.0035,6.66536 0.0067,13.33073 0.0093,19.99609 l 9.86e-4,2.48865 c 0.005,13.72121 -0.0058,27.44236 -0.02756,41.16355 -0.01265,8.44313 -0.01133,16.88604 0.0085,25.32916 0.01266,5.78741 0.0111,11.57471 -0.0014,17.36211 -0.0067,3.33159 -0.0047,6.66256 0.01058,9.99416 0.111194,25.65838 0.111194,25.65838 -4.500365,37.04128 l -0.849251,2.18899 c -7.771476,18.55174 -21.788527,30.7335 -39.685905,38.97898 -3.37688,1.34444 -5.301227,2.48389 -8.978708,2.48389 l -3.2442484,1.47057 c -4.8987376,0.0599 -14.0045433,0.089 -15.4540455,0.10655 -25.7222011,0.30356 -49.7229121,-5.03616 -68.8916011,-23.19214 -3.286346,-3.24956 -6.197141,-6.66938 -8.810303,-10.47827 -1.170385,-1.6798 -3.844026,-5.57044 -5.590218,-8.45711 -0.851523,-1.40767 -3.595298,-4.4516 -7.983006,-16.21404 -0.853709,-1.50963 -2.403339,-12.94213 -2.403339,-12.94213 -0.0915,-1.48718 -0.23669,-2.92345 -0.23801,-4.41344 l -0.01,-2.78866 0.005,-3.06828 -0.007,-3.25582 c -0.006,-3.61823 -0.006,-7.23642 -0.005,-10.85466 -0.003,-2.58667 -0.006,-5.17335 -0.0102,-7.76002 -0.008,-6.30723 -0.0111,-12.61445 -0.0116,-18.92169 -4.7e-4,-5.12481 -0.003,-10.24962 -0.006,-15.37442 -0.009,-14.52085 -0.0134,-29.0417 -0.0127,-43.56255 l 1.3e-4,-2.37302 1.2e-4,-2.3759 c 4.1e-4,-12.71422 -0.009,-25.42841 -0.0233,-38.14262 -0.0143,-13.04611 -0.0213,-26.0922 -0.0204,-39.13831 3.3e-4,-7.32798 -0.002,-14.65593 -0.0132,-21.9839 -0.01,-6.88802 -0.01,-13.77597 -0.002,-20.663998 10e-4,-2.533683 1.124,-6.567371 1.118,-9.101047 -0.008,-3.44738 -1.128,-5.394528 82.246422,49.699935 83.374422,55.09446 83.377322,60.92629 83.380322,66.75811 z"
|
||||
fill="#51cdc8"
|
||||
id="path2"
|
||||
transform="translate(112.81113,8.4930303)"
|
||||
sodipodi:nodetypes="sscccccccccccccsccccccccscsccccccccs" />
|
||||
<path
|
||||
d="m 0,0 c 2.3047995,-6.7559e-4 4.6095989,-0.00164773 6.9143982,-0.00289917 4.8125578,-0.00146675 9.6250968,6.4331e-4 14.4376528,0.00534058 6.108101,0.00567724 12.216159,0.00242443 18.324259,-0.00357247 4.756666,-0.00364996 9.513323,-0.00244655 14.269991,1.2779e-4 2.249005,6.5808e-4 4.498012,-1.1905e-4 6.747016,-0.00247955 10.980782,-0.00899429 21.945816,0.06768592 32.917523,0.54693985 l 2.536386,0.10305596 C 119.97909,1.8334817 140.8053,14.193522 157.08594,31.132812 c 14.55199,16.47268 20.55085,36.163532 20.75,57.8125 0.0272,1.535344 0.0557,3.070663 0.0855,4.605958 0.0684,3.811023 0.11277,7.62181 0.14563,11.43329 0.018,2.0392 0.0412,21.15431 0.0616,30.38266 0.0376,3.46864 -119.042723,1.76559 -119.042723,1.76559 l -20.85965,1.44008 -111.140349,85.55992 c -0.161213,-39.22828 -0.161213,-39.22828 -0.195313,-55.73828 -0.02368,-11.37426 -0.05144,-22.7484 -0.106445,-34.12256 -0.04005,-8.28583 -0.06572,-16.57157 -0.0746,-24.8575 -0.0052,-4.3814 -0.01724,-8.76252 -0.04657,-13.143825 -0.02746,-4.136862 -0.03546,-8.273336 -0.02951,-12.41028 -0.0011,-1.50588 -0.0089,-3.011774 -0.02439,-4.517574 -0.131739,-13.445652 1.806738,-26.659985 8.289322,-38.647479 l 1.049072,-2.008056 c 2.851223,-5.317287 6.068313,-10.084275 10.138428,-14.554444 L -51.898437,21.875 C -43.655062,13.127533 -37.90534,5.8098811 -26.601562,1.8203125 l -12.3125,0.3125 v -1 C -25.942811,-0.00501656 -13.012554,-0.01357216 0,0 Z"
|
||||
fill="#fec728"
|
||||
id="path3"
|
||||
transform="translate(249.91406,6.8671875)"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
|
||||
<path
|
||||
d="M 122.4545,-1.5555303 C 104.75322,5.7344897 77.764999,26.892615 70.396697,44.304966 65.927561,56.152831 64.595666,67.366945 64.64297,79.919079 c -0.0088,1.568853 -0.01926,3.137697 -0.03133,4.706528 -0.02754,4.203537 -0.03127,8.406777 -0.03028,12.610391 -0.0032,4.413592 -0.02883,8.827052 -0.05198,13.240572 -0.04035,8.33285 -0.06085,16.66561 -0.07397,24.99854 -0.01594,9.49723 -0.05439,18.99434 -0.09459,28.4915 -0.08212,19.51341 -0.136384,39.02681 -0.171948,58.54036 -3.137967,0.048 -6.275837,0.0763 -9.414062,0.10156 l -2.652588,0.0413 C 23.81406,222.81977 1.5565346,207.45478 -18.375829,188.75648 l -2.718735,-2.53775 c -8.235245,-7.71396 -16.371582,-15.53064 -24.472001,-23.38588 -5.420898,-5.25288 -10.871421,-10.46504 -16.411803,-15.59199 -41.322082,-38.29606 -41.811362,-38.47284 -39.697042,-61.82222 2.114319,-23.349383 3.306846,-25.445419 3.989278,-27.72417 6.748595,-20.960043 21.800751,-37.772405 41,-48.4375003 18.641419,-9.40752742 36.480818,-9.88154862 87.01386,-9.85750697 50.533043,0.0240417 73.811792,-1.09807633 92.064262,-0.98624303"
|
||||
fill="#264863"
|
||||
id="path4"
|
||||
transform="translate(112.81113,8.4930303)"
|
||||
sodipodi:nodetypes="cccccccccccccccccccc" />
|
||||
<path
|
||||
d="m 0,0 131.25,-0.25 v 63.875 l 0.11035,19.705566 c 0.0181,7.998291 0.0181,7.998291 0.0214,11.753754 0.006,2.598872 0.0186,5.19694 0.0405,7.79565 0.033,3.95755 0.0333,7.91478 0.0318,11.87247 l 0.0436,3.45275 c -0.0875,17.24733 -6.73078,32.78677 -18.61099,45.21278 C 106.22208,169.37917 98.630621,174.4762 90,177 l -11.397775,1.80377 -1.45256,0.16395 c -7.104685,-0.0441 -3.43355,-0.0556 -10.538337,-0.0776 -2.653987,-0.0101 -5.307964,-0.0237 -7.961914,-0.041 -3.807645,-0.0242 -7.615144,-0.0356 -11.422852,-0.0444 l -3.614349,-0.0313 -3.336334,-4.6e-4 -2.947357,-0.0135 c -2.521553,0.0131 41.626196,-2.01422 39.819227,0.21323 L 33,179 H 30.1875 24 c -1.532555,0.0113 -3.065107,0.0231 -4.597656,0.0352 -1.821614,0.009 -3.643229,0.0184 -5.464844,0.0273 l -2.798828,0.0254 -2.6738282,0.01 -2.4494629,0.0159 C 4,179 5.0139855,178.84803 4.0508683,177.7768 l 1.9580347,1.35049 -19.547353,-0.15833 -0.795115,0.0476 L -16,179 l -3.272949,0.0317 c -3.999316,0.0361 -7.998616,0.0591 -11.998047,0.0781 -1.732447,0.0101 -3.464876,0.0237 -5.197266,0.041 -2.487184,0.0242 -4.974145,0.0356 -7.461425,0.0444 l -2.35495,0.0313 c -1.906618,4e-4 -13.996389,0.0497 -15.899078,-0.0727 l 18.898307,-4.96534 C -32.858078,170.63158 -17.423649,159.0936 -8,141 c 5.0244847,-11.01947 7.29498468,-20.88967 7.31884766,-32.92383 l 0.0307674,-3.60735 c 0.0305076,-3.83335 0.0477557,-7.666634 0.0644474,-11.50007 0.0169446,-2.374681 0.0347624,-4.749356 0.0534668,-7.124023 C -0.4694063,77.063221 -0.4232179,68.2816 -0.375,59.5 Z"
|
||||
fill="#773aaa"
|
||||
id="path5"
|
||||
transform="translate(177,231)"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccc" />
|
||||
<path
|
||||
d="m 130.75,72.125 c 0,0 -130.9459176,38.46063 -130.5354588,-0.05093 L 130.75,72.125 l 0.5,86.75 L 0,159 0.2145412,72.074065"
|
||||
fill="#ef7a34"
|
||||
id="path6"
|
||||
transform="translate(177,72)"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.3 KiB |
@ -31,6 +31,7 @@
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="icons/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="icons/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="icons/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="icons/android-icon-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user