From cad16a35d31cf2b521ebb2211ed95000e010eff9 Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Fri, 29 Dec 2023 15:06:09 +0100 Subject: [PATCH] Puzzle (handle cols rows + message) + show element for resource --- lib/Components/audio_player.dart | 245 +++++++++++++++++ lib/Components/loading_common.dart | 17 +- lib/Components/show_element_for_resource.dart | 100 +++++++ lib/Components/video_viewer_youtube.dart | 93 +++++++ lib/Models/ResponseSubDTO.dart | 12 +- lib/Models/map-marker.dart | 8 +- lib/Models/tabletContext.dart | 1 + lib/Screens/Agenda/agenda_view.dart | 45 ++++ lib/Screens/Article/article_view.dart | 46 ++++ lib/Screens/MainView/language_selection.dart | 49 ++-- lib/Screens/MainView/main_view.dart | 248 +++++++++++++----- lib/Screens/Map/google_map_view.dart | 6 +- lib/Screens/Map/marker_view.dart | 16 +- lib/Screens/Menu/menu_view.dart | 33 ++- lib/Screens/PDF/pdf_view.dart | 80 ++++-- lib/Screens/Puzzle/correct_overlay.dart | 4 +- lib/Screens/Puzzle/message_dialog.dart | 89 +++++++ lib/Screens/Puzzle/puzzle_piece.dart | 142 ++++++---- lib/Screens/Puzzle/puzzle_view.dart | 160 +++++++---- lib/Screens/Quizz/quizz_view.dart | 30 +-- lib/Screens/Quizz/showResponses.dart | 4 +- lib/Screens/Slider/slider_view.dart | 47 ++-- lib/Screens/Video/video_view.dart | 8 +- lib/Screens/Web/web_view.dart | 4 +- lib/api/swagger.yaml | 8 +- lib/constants.dart | 16 +- lib/main.dart | 2 +- manager_api/doc/AuthenticationApi.md | 2 +- manager_api/doc/ConfigurationApi.md | 2 +- manager_api/doc/DeviceApi.md | 2 +- manager_api/doc/InstanceApi.md | 2 +- manager_api/doc/PuzzleDTO.md | 2 + manager_api/doc/ResourceApi.md | 2 +- manager_api/doc/SectionApi.md | 2 +- manager_api/doc/UserApi.md | 2 +- manager_api/lib/api_client.dart | 2 +- manager_api/lib/model/puzzle_dto.dart | 40 ++- manager_api/lib/model/resource_type.dart | 70 +++-- 38 files changed, 1284 insertions(+), 357 deletions(-) create mode 100644 lib/Components/audio_player.dart create mode 100644 lib/Components/show_element_for_resource.dart create mode 100644 lib/Components/video_viewer_youtube.dart create mode 100644 lib/Screens/Agenda/agenda_view.dart create mode 100644 lib/Screens/Article/article_view.dart create mode 100644 lib/Screens/Puzzle/message_dialog.dart diff --git a/lib/Components/audio_player.dart b/lib/Components/audio_player.dart new file mode 100644 index 0000000..1dcb434 --- /dev/null +++ b/lib/Components/audio_player.dart @@ -0,0 +1,245 @@ +import 'dart:typed_data'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import 'package:just_audio/just_audio.dart'; +import 'package:tablet_app/Models/tabletContext.dart'; +import 'package:tablet_app/app_context.dart'; + + +class AudioPlayerFloatingContainer extends StatefulWidget { + const AudioPlayerFloatingContainer({Key? key, required this.audioBytes, required this.resourceURl, required this.isAuto}) : super(key: key); + + final Uint8List? audioBytes; + final String resourceURl; + final bool isAuto; + + @override + State createState() => _AudioPlayerFloatingContainerState(); +} + +class _AudioPlayerFloatingContainerState extends State { + AudioPlayer player = AudioPlayer(); + late Uint8List audiobytes; + bool isplaying = false; + bool audioplayed = false; + int currentpos = 0; + int maxduration = 100; + Duration? durationAudio; + String currentpostlabel = "00:00"; + + @override + void initState() { + Future.delayed(Duration.zero, () async { + if(widget.audioBytes != null) { + audiobytes = widget.audioBytes!; + } + + player.durationStream.listen((Duration? d) { //get the duration of audio + if(d != null) { + maxduration = d.inSeconds; + durationAudio = d; + } + }); + + //player.bufferedPositionStream + + player.positionStream.listen((event) { + if(durationAudio != null) { + + currentpos = event.inMilliseconds; //get the current position of playing audio + + //generating the duration label + int shours = Duration(milliseconds:durationAudio!.inMilliseconds - currentpos).inHours; + int sminutes = Duration(milliseconds:durationAudio!.inMilliseconds - currentpos).inMinutes; + int sseconds = Duration(milliseconds:durationAudio!.inMilliseconds - currentpos).inSeconds; + + int rminutes = sminutes - (shours * 60); + int rseconds = sseconds - (sminutes * 60 + shours * 60 * 60); + + String minutesToShow = rminutes < 10 ? '0$rminutes': rminutes.toString(); + String secondsToShow = rseconds < 10 ? '0$rseconds': rseconds.toString(); + + currentpostlabel = "$minutesToShow:$secondsToShow"; + + setState(() { + //refresh the UI + if(currentpos > player.duration!.inMilliseconds) { + print("RESET ALL"); + player.stop(); + player.seek(const Duration(seconds: 0)); + isplaying = false; + audioplayed = false; + currentpostlabel = "00:00"; + } + }); + } + }); + + + + /*player.onPositionChanged.listen((Duration p){ + currentpos = p.inMilliseconds; //get the current position of playing audio + + //generating the duration label + int shours = Duration(milliseconds:currentpos).inHours; + int sminutes = Duration(milliseconds:currentpos).inMinutes; + int sseconds = Duration(milliseconds:currentpos).inSeconds; + + int rminutes = sminutes - (shours * 60); + int rseconds = sseconds - (sminutes * 60 + shours * 60 * 60); + + String minutesToShow = rminutes < 10 ? '0$rminutes': rminutes.toString(); + String secondsToShow = rseconds < 10 ? '0$rseconds': rseconds.toString(); + + currentpostlabel = "$minutesToShow:$secondsToShow"; + + setState(() { + //refresh the UI + }); + });*/ + + if(widget.isAuto) { + //player.play(BytesSource(audiobytes)); + //await player.setAudioSource(LoadedSource(audiobytes)); + await player.setUrl(widget.resourceURl); + player.play(); + setState(() { + isplaying = true; + audioplayed = true; + }); + } + }); + super.initState(); + } + + @override + void dispose() { + player.stop(); + player.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final appContext = Provider.of(context); + TabletAppContext tabletAppContext = appContext.getContext(); + + return FloatingActionButton( + backgroundColor: new Color(int.parse(tabletAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)).withOpacity(0.7), + onPressed: () async { + if(!isplaying && !audioplayed){ + //player.play(BytesSource(audiobytes)); + await player.setAudioSource(LoadedSource(audiobytes)); + player.play(); + setState(() { + isplaying = true; + audioplayed = true; + }); + }else if(audioplayed && !isplaying){ + //player.resume(); + player.play(); + setState(() { + isplaying = true; + audioplayed = true; + }); + }else{ + player.pause(); + setState(() { + isplaying = false; + }); + } + }, + child: isplaying ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.pause), + Text(currentpostlabel), + ], + ) : audioplayed ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.play_arrow), + Text(currentpostlabel), + ], + ): const Icon(Icons.play_arrow), + + /*Column( + children: [ + //Text(currentpostlabel, style: const TextStyle(fontSize: 25)), + Wrap( + spacing: 10, + children: [ + ElevatedButton.icon( + style: ElevatedButton.styleFrom( + backgroundColor: kSecondColor, // Background color + ), + onPressed: () async { + if(!isplaying && !audioplayed){ + //player.play(BytesSource(audiobytes)); + await player.setAudioSource(LoadedSource(audiobytes)); + player.play(); + setState(() { + isplaying = true; + audioplayed = true; + }); + }else if(audioplayed && !isplaying){ + //player.resume(); + player.play(); + setState(() { + isplaying = true; + audioplayed = true; + }); + }else{ + player.pause(); + setState(() { + isplaying = false; + }); + } + }, + icon: Icon(isplaying?Icons.pause:Icons.play_arrow), + //label:Text(isplaying?TranslationHelper.getFromLocale("pause", appContext.getContext()):TranslationHelper.getFromLocale("play", appContext.getContext())) + ), + + /*ElevatedButton.icon( + style: ElevatedButton.styleFrom( + backgroundColor: kSecondColor, // Background color + ), + onPressed: () async { + player.stop(); + player.seek(const Duration(seconds: 0)); + setState(() { + isplaying = false; + audioplayed = false; + currentpostlabel = "00:00"; + }); + }, + icon: const Icon(Icons.stop), + //label: Text(TranslationHelper.getFromLocale("stop", appContext.getContext())) + ),*/ + ], + ) + ], + ),*/ + ); + } +} + +// Feed your own stream of bytes into the player +class LoadedSource extends StreamAudioSource { + final List bytes; + LoadedSource(this.bytes); + + @override + Future request([int? start, int? end]) async { + start ??= 0; + end ??= bytes.length; + return StreamAudioResponse( + sourceLength: bytes.length, + contentLength: end - start, + offset: start, + stream: Stream.value(bytes.sublist(start, end)), + contentType: 'audio/mpeg', + ); + } +} diff --git a/lib/Components/loading_common.dart b/lib/Components/loading_common.dart index 61b3b12..75f1778 100644 --- a/lib/Components/loading_common.dart +++ b/lib/Components/loading_common.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:tablet_app/Models/tabletContext.dart'; +import 'package:tablet_app/app_context.dart'; import 'package:tablet_app/constants.dart'; class LoadingCommon extends StatefulWidget { @@ -28,6 +31,9 @@ class _LoadingCommonState extends State with TickerProviderStateM @override Widget build(BuildContext context) { + final appContext = Provider.of(context); + TabletAppContext tabletAppContext = appContext.getContext(); + Size size = MediaQuery.of(context).size; _controller!.forward(from: 0.0); _controller!.addListener(() { @@ -39,9 +45,14 @@ class _LoadingCommonState extends State with TickerProviderStateM } }); return Center( - child: RotationTransition( - turns: Tween(begin: 0.0, end: 3.0).animate(_controller!), - child: Icon(Icons.museum_outlined, color: kTestSecondColor, size: size.height*0.1), + child: SizedBox( + height: size.height * 0.1, + child: RotationTransition( + turns: Tween(begin: 0.0, end: 3.0).animate(_controller!), + child: tabletAppContext.configuration != null && tabletAppContext.configuration!.loaderImageUrl != null ? + Image.network(tabletAppContext.configuration!.loaderImageUrl!) + : Icon(Icons.museum_outlined, color: kTestSecondColor, size: size.height*0.1), + ), ), ); } diff --git a/lib/Components/show_element_for_resource.dart b/lib/Components/show_element_for_resource.dart new file mode 100644 index 0000000..0d9560b --- /dev/null +++ b/lib/Components/show_element_for_resource.dart @@ -0,0 +1,100 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:manager_api/api.dart'; +import 'package:tablet_app/Components/audio_player.dart'; +import 'package:tablet_app/Components/video_viewer.dart'; +import 'package:tablet_app/Components/video_viewer_youtube.dart'; +import 'package:tablet_app/Models/tabletContext.dart'; +import 'package:tablet_app/app_context.dart'; + +showElementForResource(ResourceDTO resourceDTO, AppContext appContext) { + TabletAppContext tabletAppContext = appContext.getContext(); + Color primaryColor = new Color(int.parse(tabletAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)); + + switch(resourceDTO.type) { + case ResourceType.Image: + return Image.network( + resourceDTO.url!, + fit:BoxFit.fill, + loadingBuilder: (BuildContext context, Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) { + return child; + } + return Center( + child: CircularProgressIndicator( + color: primaryColor, + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + ); + break; + case ResourceType.ImageUrl: + return Image.network( + resourceDTO.url!, + fit:BoxFit.fill, + loadingBuilder: (BuildContext context, Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) { + return child; + } + return Center( + child: CircularProgressIndicator( + color: primaryColor, + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + ); + case ResourceType.Audio: + return AudioPlayerFloatingContainer(audioBytes: null, resourceURl: resourceDTO.url!, isAuto: true); + /*return FutureBuilder( + future: getAudio(resourceDTO.url, appContext), + builder: (context, AsyncSnapshot snapshot) { + Size size = MediaQuery.of(context).size; + if (snapshot.connectionState == ConnectionState.done) { + var audioBytes; + if(snapshot.data != null) { + print("snapshot.data"); + print(snapshot.data); + audioBytes = snapshot.data; + //this.player.playBytes(audiobytes); + } + return AudioPlayerFloatingContainer(audioBytes: audioBytes, resourceURl: resourceDTO.url, isAuto: true); + } else if (snapshot.connectionState == ConnectionState.none) { + return Text("No data"); + } else { + return Center( + child: Container( + //height: size.height * 0.2, + width: size.width * 0.2, + child: LoadingCommon() + ) + ); + } + } + );*/ + case ResourceType.Video: + if(resourceDTO.url == null) { + return Center(child: Text("Error loading video")); + } else { + return VideoViewer(videoUrl: resourceDTO.url!); + } + case ResourceType.VideoUrl: + if(resourceDTO.url == null) { + return Center(child: Text("Error loading video")); + } else { + return VideoViewerYoutube(videoUrl: resourceDTO.url!); + } + } +} diff --git a/lib/Components/video_viewer_youtube.dart b/lib/Components/video_viewer_youtube.dart new file mode 100644 index 0000000..a4a1805 --- /dev/null +++ b/lib/Components/video_viewer_youtube.dart @@ -0,0 +1,93 @@ +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:manager_api/api.dart'; +import 'package:tablet_app/constants.dart'; +import 'package:youtube_player_iframe/youtube_player_iframe.dart' as iframe; +import 'package:youtube_player_flutter/youtube_player_flutter.dart'; + +class VideoViewerYoutube extends StatefulWidget { + final String videoUrl; + VideoViewerYoutube({required this.videoUrl}); + + @override + _VideoViewerYoutube createState() => _VideoViewerYoutube(); +} + +class _VideoViewerYoutube extends State { + iframe.YoutubePlayer? _videoViewWeb; + YoutubePlayer? _videoView; + + @override + void initState() { + String? videoId; + if (widget.videoUrl.length > 0 ) { + videoId = YoutubePlayer.convertUrlToId(widget.videoUrl); + + if (kIsWeb) { + final _controllerWeb = iframe.YoutubePlayerController( + params: iframe.YoutubePlayerParams( + mute: false, + showControls: true, + showFullscreenButton: false, + loop: true, + showVideoAnnotations: false, + strictRelatedVideos: false, + enableKeyboard: false, + enableCaption: false, + pointerEvents: iframe.PointerEvents.auto + ), + ); + + _controllerWeb.loadVideo(widget.videoUrl); + + _videoViewWeb = iframe.YoutubePlayer( + controller: _controllerWeb, + //showVideoProgressIndicator: false, + /*progressIndicatorColor: Colors.amber, + progressColors: ProgressBarColors( + playedColor: Colors.amber, + handleColor: Colors.amberAccent, + ),*/ + ); + } else { + videoId = YoutubePlayer.convertUrlToId(widget.videoUrl); + YoutubePlayerController _controller = YoutubePlayerController( + initialVideoId: videoId!, + flags: YoutubePlayerFlags( + autoPlay: true, + controlsVisibleAtStart: false, + loop: true, + hideControls: false, + hideThumbnail: false, + ), + ); + + + _videoView = YoutubePlayer( + controller: _controller, + //showVideoProgressIndicator: false, + progressIndicatorColor: Colors.amber, + progressColors: ProgressBarColors( + playedColor: Colors.amber, + handleColor: Colors.amberAccent, + ), + ); + } + super.initState(); + } + } + + @override + void dispose() { + _videoView = null; + _videoViewWeb = null; + super.dispose(); + } + + @override + Widget build(BuildContext context) => widget.videoUrl.length > 0 ? + (kIsWeb ? _videoViewWeb! : _videoView!): + Center(child: Text("La vidéo ne peut pas être affichée, l'url est incorrecte", style: new TextStyle(fontSize: kNoneInfoOrIncorrect))); +} \ No newline at end of file diff --git a/lib/Models/ResponseSubDTO.dart b/lib/Models/ResponseSubDTO.dart index 2728793..130523a 100644 --- a/lib/Models/ResponseSubDTO.dart +++ b/lib/Models/ResponseSubDTO.dart @@ -1,7 +1,7 @@ import 'package:manager_api/api.dart'; class ResponseSubDTO { - List? label; + List? label; bool? isGood; int? order; @@ -25,14 +25,14 @@ class ResponseSubDTO { } class QuestionSubDTO { - List? label; + List? label; List? responsesSubDTO; int? chosen; String? resourceId; - String? source_; + String? resourceUrl; int? order; - QuestionSubDTO({this.label, this.responsesSubDTO, this.chosen, this.resourceId, this.source_, this.order}); + QuestionSubDTO({this.label, this.responsesSubDTO, this.chosen, this.resourceId, this.resourceUrl, this.order}); List fromJSON(List questionsDTO) { List questionSubDTO = []; @@ -42,8 +42,8 @@ class QuestionSubDTO { chosen: null, label: questionDTO.label, responsesSubDTO: ResponseSubDTO().fromJSON(questionDTO.responses!), - resourceId: questionDTO.resourceId, - source_: questionDTO.source_, + resourceId: questionDTO.imageBackgroundResourceId, + resourceUrl: questionDTO.imageBackgroundResourceUrl, order: questionDTO.order, )); } diff --git a/lib/Models/map-marker.dart b/lib/Models/map-marker.dart index 8a3115c..fb067a0 100644 --- a/lib/Models/map-marker.dart +++ b/lib/Models/map-marker.dart @@ -4,18 +4,18 @@ class MapMarker { int? id; String? title; String? description; - List? images; + List? contents; String? latitude; String? longitude; - MapMarker({this.id, this.title, this.description, this.images, this.latitude, this.longitude}); + MapMarker({this.id, this.title, this.description, this.contents, this.latitude, this.longitude}); factory MapMarker.fromJson(Map json) { return new MapMarker( id: json['id'] as int, title: json['title'] as String, description: json['description'] as String, - images: json['image'] as List, + contents: json['contents'] as List, latitude: json['latitude'] as String, longitude: json['longitude'] as String, ); @@ -23,6 +23,6 @@ class MapMarker { @override String toString() { - return 'MapMarker{id: $id, title: $title, description: $description, images: $images, latitude: $latitude, longitude: $longitude}'; + return 'MapMarker{id: $id, title: $title, description: $description, contents: $contents, latitude: $latitude, longitude: $longitude}'; } } \ No newline at end of file diff --git a/lib/Models/tabletContext.dart b/lib/Models/tabletContext.dart index 2a066f1..a739c5b 100644 --- a/lib/Models/tabletContext.dart +++ b/lib/Models/tabletContext.dart @@ -16,6 +16,7 @@ class TabletAppContext with ChangeNotifier{ String? language; String? deviceId; String? instanceId; + Size? puzzleSize; TabletAppContext({this.id, this.deviceId, this.host, this.configuration, this.language, this.instanceId, this.clientAPI}); diff --git a/lib/Screens/Agenda/agenda_view.dart b/lib/Screens/Agenda/agenda_view.dart new file mode 100644 index 0000000..5b4cfe0 --- /dev/null +++ b/lib/Screens/Agenda/agenda_view.dart @@ -0,0 +1,45 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +//import 'dart:html'; +import 'dart:ui' as ui; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:manager_api/api.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:tablet_app/Components/loading_common.dart'; + + +class AgendaView extends StatefulWidget { + final SectionDTO? section; + AgendaView({this.section}); + + @override + _AgendaView createState() => _AgendaView(); +} + +class _AgendaView extends State { + AgendaDTO agendaDTO = AgendaDTO(); + + @override + void initState() { + print(widget.section!.data); + agendaDTO = AgendaDTO.fromJson(jsonDecode(widget.section!.data!))!; + print(agendaDTO); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + + @override + Widget build(BuildContext context) { + return new Center( + child: Text("TODO Agenda"), + ); + } +} //_webView \ No newline at end of file diff --git a/lib/Screens/Article/article_view.dart b/lib/Screens/Article/article_view.dart new file mode 100644 index 0000000..420a396 --- /dev/null +++ b/lib/Screens/Article/article_view.dart @@ -0,0 +1,46 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +//import 'dart:html'; +import 'dart:ui' as ui; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:manager_api/api.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:tablet_app/Components/loading_common.dart'; + + +class ArticleView extends StatefulWidget { + final SectionDTO? section; + ArticleView({this.section}); + + @override + _ArticleView createState() => _ArticleView(); +} + +class _ArticleView extends State { + AgendaDTO agendaDTO = AgendaDTO(); + + @override + void initState() { + print(widget.section!.data); + agendaDTO = AgendaDTO.fromJson(jsonDecode(widget.section!.data!))!; + print(agendaDTO); + super.initState(); + } + + @override + void dispose() { + //_webView = null; + super.dispose(); + } + + + @override + Widget build(BuildContext context) { + return new Center( + child: Text("TODO Agenda"), + ); + } +} //_webView \ No newline at end of file diff --git a/lib/Screens/MainView/language_selection.dart b/lib/Screens/MainView/language_selection.dart index 460bdd5..7751614 100644 --- a/lib/Screens/MainView/language_selection.dart +++ b/lib/Screens/MainView/language_selection.dart @@ -84,30 +84,33 @@ class _LanguageSelection extends State with TickerProviderSta left: _leftLanguage, right: _rightLanguage, bottom: _bottomLanguage, - child: ListView( - children: [ - if(minimized) ... [ - for(var language in languagesEnable!.where((element) => element.toUpperCase() != selectedLanguage )) - InkWell( - onTap: () { - setState(() { - TabletAppContext tabletAppContext = appContext.getContext(); - tabletAppContext.language = language; - appContext.setContext(tabletAppContext); - minimizedAnimation(size); - }); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - width: 75, - height: 75, - decoration: flagDecoration(language), + child: Padding( + padding: const EdgeInsets.only(top: 25.0), + child: ListView( + children: [ + if(minimized) ... [ + for(var language in languagesEnable!.where((element) => element.toUpperCase() != selectedLanguage )) + InkWell( + onTap: () { + setState(() { + TabletAppContext tabletAppContext = appContext.getContext(); + tabletAppContext.language = language; + appContext.setContext(tabletAppContext); + minimizedAnimation(size); + }); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: 35, + height: 35, + decoration: flagDecoration(language), + ), ), - ), - ) - ] - ], + ) + ] + ], + ), ), ), ], diff --git a/lib/Screens/MainView/main_view.dart b/lib/Screens/MainView/main_view.dart index 9e576f8..af5f345 100644 --- a/lib/Screens/MainView/main_view.dart +++ b/lib/Screens/MainView/main_view.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -7,13 +9,18 @@ import 'package:manager_api/api.dart'; import 'package:provider/provider.dart'; import 'package:tablet_app/Components/loading.dart'; import 'package:tablet_app/Components/loading_common.dart'; +import 'package:tablet_app/Helpers/DatabaseHelper.dart'; import 'package:tablet_app/Helpers/MQTTHelper.dart'; +import 'package:tablet_app/Screens/Agenda/agenda_view.dart'; +import 'package:tablet_app/Screens/Article/article_view.dart'; import 'package:tablet_app/Screens/Configuration/config_view.dart'; import 'package:tablet_app/Screens/Map/map_context.dart'; import 'package:tablet_app/Screens/Map/map_view.dart'; import 'package:tablet_app/Models/map-marker.dart'; import 'package:tablet_app/Models/tabletContext.dart'; import 'package:tablet_app/Screens/Menu/menu_view.dart'; +import 'package:tablet_app/Screens/PDF/pdf_view.dart'; +import 'package:tablet_app/Screens/Puzzle/puzzle_view.dart'; import 'package:tablet_app/Screens/Slider/slider_view.dart'; import 'package:tablet_app/Screens/Video/video_view.dart'; import 'package:tablet_app/Screens/Web/web_view.dart'; @@ -42,11 +49,11 @@ class _MainViewWidget extends State { final appContext = Provider.of(context); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); Size size = MediaQuery.of(context).size; - configurationDTO = appContext.getContext().configuration; - if (!MQTTHelper.instance.isInstantiated) - MQTTHelper.instance.connect(appContext); + // TODO REMOVE + /*if (!MQTTHelper.instance.isInstantiated) + MQTTHelper.instance.connect(appContext);*/ if(sectionSelected != null) { var elementToShow; @@ -70,17 +77,29 @@ class _MainViewWidget extends State { elementToShow = WebView(section: sectionSelected); break; case SectionType.video : // Video - elementToShow = VideoViewWidget(section: sectionSelected); + elementToShow = VideoView(section: sectionSelected); break; case SectionType.slider : - elementToShow = SliderViewWidget(section: sectionSelected); + elementToShow = SliderView(section: sectionSelected); break; case SectionType.menu : - elementToShow = MenuViewWidget(section: sectionSelected!); + elementToShow = MenuView(section: sectionSelected!); break; case SectionType.quizz : - elementToShow = QuizzViewWidget(section: sectionSelected); + elementToShow = QuizzView(section: sectionSelected); break; + case SectionType.pdf : + elementToShow = PDFViewWidget(section: sectionSelected); + break; + case SectionType.puzzle : + elementToShow = PuzzleView(section: sectionSelected); + break; + case SectionType.agenda : + elementToShow = AgendaView(section: sectionSelected); + break; + /*case SectionType.article : // TODO + elementToShow = ArticleView(section: sectionSelected); + break;*/ default: elementToShow = Text("Ce type n'est pas supporté"); break; @@ -132,7 +151,7 @@ class _MainViewWidget extends State { alignment: Alignment.centerLeft, child: HtmlWidget( sectionSelected!.title!.firstWhere((translation) => translation.language == appContext.getContext().language).value!, - textStyle: new TextStyle(fontSize: kIsWeb ? kWebSectionTitleDetailSize : kSectionTitleDetailSize), + textStyle: new TextStyle(fontSize: kIsWeb ? kWebSectionTitleDetailSize : kSectionTitleDetailSize, color: Colors.white), ) ) ), @@ -181,10 +200,10 @@ class _MainViewWidget extends State { ), floatingActionButtonLocation: FloatingActionButtonLocation.endTop, floatingActionButton: Padding( - padding: const EdgeInsets.only(top: kIsWeb ? 16.0 : 0.0), + padding: const EdgeInsets.only(top: kIsWeb ? 16.0 : 16.0), child: Container( - height: kIsWeb ? size.height *0.08 : 185.0, - width: kIsWeb ? size.width *0.08: 185.0, + height: kIsWeb ? size.height *0.08 : size.height *0.08, + width: kIsWeb ? size.width *0.08: size.width *0.08, child: FittedBox( child: FloatingActionButton.extended( backgroundColor: kBackgroundColor, @@ -196,7 +215,7 @@ class _MainViewWidget extends State { }); }, icon: Icon(Icons.arrow_back, color: Colors.grey), - label: Text("Menu") + label: Text("Menu", style: TextStyle(color: Colors.black)) ), ), ), @@ -218,28 +237,28 @@ class _MainViewWidget extends State { ), ) : null, child: Stack( - children: [ - LanguageSelection(size: size), - Center( - child: Container( - height: kIsWeb ? size.height : size.height * 0.85, - width: size.width * 0.9, - child: FutureBuilder( - future: getSections(appContext), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.data == null) { - // Show select config - return Text(""); - } - else { - return Center( - child: GridView.builder( - shrinkWrap: true, - gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: rowCount), - itemCount: snapshot.data?.length, - itemBuilder: (BuildContext context, int index) { - return InkWell( + children: [ + LanguageSelection(size: size), + Center( + child: Container( + height: kIsWeb ? size.height : size.height * 0.85, + width: size.width * 0.9, + child: FutureBuilder( + future: getSections(appContext), + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.data == null) { + // Show select config + return Text(""); + } + else { + return Center( + child: GridView.builder( + shrinkWrap: true, + gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: rowCount), + itemCount: snapshot.data?.length, + itemBuilder: (BuildContext context, int index) { + return InkWell( onTap: () { setState(() { sectionSelected = snapshot.data[index]; @@ -252,60 +271,134 @@ class _MainViewWidget extends State { child: Align( alignment: Alignment.bottomRight, child: FractionallySizedBox( - heightFactor: 0.25, - child: Column( - children: [ - Align( - alignment: Alignment.centerRight, - child: HtmlWidget( - snapshot.data[index].title.firstWhere((translation) => translation.language == appContext.getContext().language).value, - customStylesBuilder: (element) { - return {'text-align': 'right'}; - }, - textStyle: new TextStyle(fontSize: kIsWeb ? kWebMenuTitleDetailSize: kMenuTitleDetailSize), + heightFactor: 0.35, + child: Container( + color: Colors.green, + child: Column( + children: [ + Container( + color: Colors.blue, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return SizedBox( + width: double.infinity, + child: FittedBox( + fit: BoxFit.fitWidth, + child: Align( + alignment: Alignment.centerRight, + child: HtmlWidget( + snapshot.data[index].title.firstWhere((translation) => translation.language == appContext.getContext().language).value, + customStylesBuilder: (element) { + return {'text-align': 'right'}; + }, + textStyle: TextStyle(fontSize: calculateFontSize(constraints.maxWidth, constraints.maxHeight, kIsWeb ? kWebMenuTitleDetailSize : kMenuTitleDetailSize)), + ), + ), + ), + ); + }, + ), ), - ), - Align( - alignment: Alignment.centerRight, - child: HtmlWidget( - snapshot.data[index].description.firstWhere((translation) => translation.language == appContext.getContext().language).value, - customStylesBuilder: (element) { - return {'text-align': 'right'}; - }, - textStyle: new TextStyle(fontSize: kIsWeb ? kWebMenuDescriptionDetailSize: kMenuDescriptionDetailSize, fontFamily: ""), - ), - ), - ], + Container(color: Colors.orange, child: Text("ds")), + + /*Container( + color: Colors.orange, + child: FittedBox( + fit: BoxFit.fitWidth, + child: Align( + alignment: Alignment.centerRight, + child: HtmlWidget( + snapshot.data[index].title.firstWhere((translation) => translation.language == appContext.getContext().language).value, + customStylesBuilder: (element) { + return {'text-align': 'right'}; + }, + textStyle: new TextStyle(fontSize: calculateFontSize(context, kIsWeb ? kWebMenuTitleDetailSize: kMenuTitleDetailSize)), + ), + ), + ), + ), + FittedBox( + fit: BoxFit.fill, + child: Align( + alignment: Alignment.centerRight, + child: HtmlWidget( + snapshot.data[index].description.firstWhere((translation) => translation.language == appContext.getContext().language).value, + customStylesBuilder: (element) { + return {'text-align': 'right'}; + }, + textStyle: new TextStyle(fontSize: calculateFontSize(context, kIsWeb ? kWebMenuDescriptionDetailSize: kMenuDescriptionDetailSize), fontFamily: ""), + ), + ), + ),*/ + ], + ), ) ), ), ), ); - } - ), + } + ), + ); + } + } else if (snapshot.connectionState == ConnectionState.none) { + return Text("No data"); + } else { + return Center( + child: Container( + child: LoadingCommon() + ) ); } - } else if (snapshot.connectionState == ConnectionState.none) { - return Text("No data"); - } else { - return Center( - child: Container( - child: LoadingCommon() - ) - ); } - } + ), ), ), - ), - ]), + ]), ) ); } } + Future getCurrentConfiguration(dynamic appContext) async { + TabletAppContext tabletAppContext = await appContext.getContext(); + try { + ConfigurationDTO? configurationDTO = await tabletAppContext.clientAPI!.configurationApi!.configurationGetDetail(tabletAppContext.configuration!.id!); + + tabletAppContext.configuration = configurationDTO; + + TabletAppContext? localContext = await DatabaseHelper.instance.getData(); + if (localContext != null) { // Check if sql DB exist + await DatabaseHelper.instance.update(tabletAppContext); + } else { + await DatabaseHelper.instance.insert(tabletAppContext); + } + + /* + appContext.setContext(tabletAppContext); + // STORE IT LOCALLY (SQLite) + TabletAppContext? localContext = await DatabaseHelper.instance.getData(); + if (localContext != null) { // Check if sql DB exist + await DatabaseHelper.instance.update(tabletAppContext); + } else { + await DatabaseHelper.instance.insert(tabletAppContext); + }*/ + + return configurationDTO; + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Une erreur est survenue lors de la récupération de la configuration'), + ), + ); + } + } + Future?> getSections(dynamic appContext) async { TabletAppContext tabletAppContext = await appContext.getContext(); + + await getCurrentConfiguration(appContext); + try { List? sections = await tabletAppContext.clientAPI!.sectionApi!.sectionGetFromConfiguration(tabletAppContext.configuration!.id!); sections!.sort((a, b) => a.order!.compareTo(b.order!)); @@ -326,6 +419,21 @@ class _MainViewWidget extends State { } } +double calculateFontSize(double parentWidth, double parentHeight, double baseSize) { + // La taille de base est basée sur la taille définie dans vos constantes (kWebMenuTitleDetailSize ou kMenuTitleDetailSize). + // Vous pouvez ajuster ce facteur en fonction de vos besoins. + double scaleFactor = 0.8; + + // Calculez la taille de la police en fonction de la largeur et de la hauteur maximales disponibles + //double calculatedFontSize = parentWidth * scaleFactor; + + // Vous pouvez également prendre en compte la hauteur ici si nécessaire + double calculatedFontSize = min(parentWidth, parentHeight) * scaleFactor; + + // Utilisez la plus petite valeur entre la taille de base et la taille calculée + return calculatedFontSize < baseSize ? calculatedFontSize : baseSize; +} + boxDecoration(SectionDTO section, bool isSelected) { return BoxDecoration( color: kBackgroundLight, diff --git a/lib/Screens/Map/google_map_view.dart b/lib/Screens/Map/google_map_view.dart index a97d4e2..5741e04 100644 --- a/lib/Screens/Map/google_map_view.dart +++ b/lib/Screens/Map/google_map_view.dart @@ -42,7 +42,7 @@ class _GoogleMapViewState extends State { description: point.description!.firstWhere((translation) => translation.language == language).value, longitude: point.longitude, latitude: point.latitude, - images: point.images + contents: point.contents ); markersList.add(mapMarker); }); @@ -65,7 +65,7 @@ class _GoogleMapViewState extends State { mapContext.setSelectedMarker( new MapMarker( title: element.title, - images: element.images, + contents: element.contents, description: element.description, longitude: element.longitude, latitude: element.latitude, @@ -145,7 +145,7 @@ class _GoogleMapViewState extends State { new MapMarker( title: '', description: '', - images: null, + contents: null, longitude: null, latitude: null )); diff --git a/lib/Screens/Map/marker_view.dart b/lib/Screens/Map/marker_view.dart index 517ce6c..635375a 100644 --- a/lib/Screens/Map/marker_view.dart +++ b/lib/Screens/Map/marker_view.dart @@ -65,12 +65,12 @@ class _MarkerInfoWidget extends State { child: Stack( children: [ Positioned( - right: 15, - top: 15, + right: 5, + top: 5, child: InkWell( onTap: () { setState(() { - mapContext.setSelectedMarker(new MapMarker(longitude: null, latitude: null, title: '', images: null, description: '')); + mapContext.setSelectedMarker(new MapMarker(longitude: null, latitude: null, title: '', contents: null, description: '')); }); }, child: Container( @@ -90,7 +90,7 @@ class _MarkerInfoWidget extends State { ), child: Icon( Icons.close, - size: 35, + size: 25, color: Colors.white, ), ), @@ -223,8 +223,8 @@ class _MarkerInfoWidget extends State { }, child: Icon( Icons.chevron_right, - size: kIsWeb ? 100 : 150, - color: kMainRed, + size: kIsWeb ? 100 : 85, + color: kTestSecondColor, ), ) ), @@ -239,8 +239,8 @@ class _MarkerInfoWidget extends State { }, child: Icon( Icons.chevron_left, - size: kIsWeb ? 100 : 150, - color: kMainRed, + size: kIsWeb ? 100 : 85, + color: kTestSecondColor, ), ) ), diff --git a/lib/Screens/Menu/menu_view.dart b/lib/Screens/Menu/menu_view.dart index b0fba58..8e52387 100644 --- a/lib/Screens/Menu/menu_view.dart +++ b/lib/Screens/Menu/menu_view.dart @@ -7,8 +7,11 @@ import 'package:manager_api/api.dart'; import 'package:provider/provider.dart'; import 'package:tablet_app/Models/map-marker.dart'; import 'package:tablet_app/Models/tabletContext.dart'; +import 'package:tablet_app/Screens/Agenda/agenda_view.dart'; import 'package:tablet_app/Screens/Map/map_context.dart'; import 'package:tablet_app/Screens/Map/map_view.dart'; +import 'package:tablet_app/Screens/PDF/pdf_view.dart'; +import 'package:tablet_app/Screens/Puzzle/puzzle_view.dart'; import 'package:tablet_app/Screens/Quizz/quizz_view.dart'; import 'package:tablet_app/Screens/Slider/slider_view.dart'; import 'package:tablet_app/Screens/Video/video_view.dart'; @@ -16,15 +19,15 @@ import 'package:tablet_app/Screens/Web/web_view.dart'; import 'package:tablet_app/app_context.dart'; import 'package:tablet_app/constants.dart'; -class MenuViewWidget extends StatefulWidget { +class MenuView extends StatefulWidget { final SectionDTO? section; - MenuViewWidget({this.section}); + MenuView({this.section}); @override - _MenuViewWidget createState() => _MenuViewWidget(); + _MenuView createState() => _MenuView(); } -class _MenuViewWidget extends State { +class _MenuView extends State { MenuDTO menuDTO = MenuDTO(); SectionDTO? selectedSection; @override @@ -68,14 +71,26 @@ class _MenuViewWidget extends State { elementToShow = WebView(section: selectedSection); break; case SectionType.video : // Video - elementToShow = VideoViewWidget(section: selectedSection); + elementToShow = VideoView(section: selectedSection); break; - case SectionType.slider : // Slider: - elementToShow = SliderViewWidget(section: selectedSection); + case SectionType.slider : // Slider + elementToShow = SliderView(section: selectedSection); break; - case SectionType.quizz : // Slider: - elementToShow = QuizzViewWidget(section: selectedSection); + case SectionType.quizz : // Quizz + elementToShow = QuizzView(section: selectedSection); break; + case SectionType.pdf : // Pdf + elementToShow = PDFViewWidget(section: selectedSection); + break; + case SectionType.puzzle : // Puzzle + elementToShow = PuzzleView(section: selectedSection); + break; + case SectionType.agenda : // Agenda + elementToShow = AgendaView(section: selectedSection); + break; + /*case SectionType.article : // Article + elementToShow = ArticleView(section: selectedSection); + break;*/ default: elementToShow = Text('Section type not supported'); break; diff --git a/lib/Screens/PDF/pdf_view.dart b/lib/Screens/PDF/pdf_view.dart index e97b2fb..531210c 100644 --- a/lib/Screens/PDF/pdf_view.dart +++ b/lib/Screens/PDF/pdf_view.dart @@ -28,12 +28,12 @@ class _PDFViewWidget extends State { int? currentPage = 0; bool isReady = false; String errorMessage = ''; + ValueNotifier> currentState = ValueNotifier>({'page': 0, 'total': 0}); @override void initState() { print(widget.section!.data); pdfDTO = PdfDTO.fromJson(jsonDecode(widget.section!.data!))!; - pdfDTO.source_ = "todo"; print(pdfDTO); super.initState(); @@ -52,8 +52,7 @@ class _PDFViewWidget extends State { try { // "https://berlin2017.droidcon.cod.newthinking.net/sites/global.droidcon.cod.newthinking.net/files/media/documents/Flutter%20-%2060FPS%20UI%20of%20the%20future%20%20-%20DroidconDE%2017.pdf"; // final url = "https://pdfkit.org/docs/guide.pdf"; - final url = "http://www.pdf995.com/samples/pdf.pdf"; - // TODO replace by source_ + final url = source_; final filename = url.substring(url.lastIndexOf("/") + 1); var request = await HttpClient().getUrl(Uri.parse(url)); var response = await request.close(); @@ -80,37 +79,60 @@ class _PDFViewWidget extends State { @override - Widget build(BuildContext context) => pdfDTO.source_ != null && pdfDTO.source_!.length > 0 ? + Widget build(BuildContext context) => pdfDTO.resourceUrl != null && pdfDTO.resourceUrl!.length > 0 ? FutureBuilder( - future: createFileOfPdfUrl(""), + future: createFileOfPdfUrl(pdfDTO.resourceUrl!), builder: (context, AsyncSnapshot snapshot) { print("snapshot.data"); print(snapshot.data); if (snapshot.connectionState == ConnectionState.done) { - return PDFView( - filePath: snapshot.data.path, - enableSwipe: true, - swipeHorizontal: true, - autoSpacing: true, - pageFling: true, - onRender: (_pages) { - //setState(() { - pages = _pages; - isReady = true; - //}); - }, - onError: (error) { - print(error.toString()); - }, - onPageError: (page, error) { - print('$page: ${error.toString()}'); - }, - onViewCreated: (PDFViewController pdfViewController) { - //_controller.complete(pdfViewController); - }, - onPageChanged: (int? page, int? total) { - print('page change: $page/$total'); - }, + return Stack( + children: [ + PDFView( + filePath: snapshot.data.path, + enableSwipe: true, + swipeHorizontal: true, + autoSpacing: true, + pageFling: true, + fitPolicy: FitPolicy.HEIGHT, + onRender: (_pages) { + //setState(() { + pages = _pages; + isReady = true; + //}); + }, + onError: (error) { + print(error.toString()); + }, + onPageError: (page, error) { + print('$page: ${error.toString()}'); + }, + onViewCreated: (PDFViewController pdfViewController) { + //_controller.complete(pdfViewController); + }, + onPageChanged: (int? page, int? total) { + currentPage = page; + pages = total; + currentState.value = {'page': page!, 'total': total!}; + + print('page change: $page/$total'); + }, + ), + Positioned( + bottom: 20, + right: 20, + child: ValueListenableBuilder>( + valueListenable: currentState, + builder: (context, value, _) { + return Container( + //color: Colors.blueAccent, + child: Text("${value["page"]!+1}/${value["total"]!}", + style: TextStyle(color: Colors.black, fontSize: 30)) + ); + }, + ), + ), + ], ); } else { return Center( diff --git a/lib/Screens/Puzzle/correct_overlay.dart b/lib/Screens/Puzzle/correct_overlay.dart index be33c18..712e7a8 100644 --- a/lib/Screens/Puzzle/correct_overlay.dart +++ b/lib/Screens/Puzzle/correct_overlay.dart @@ -35,7 +35,7 @@ class CorrectOverlayState extends State @override Widget build(BuildContext context) { - return new Material( + return new Container( color: Colors.black54, child: new InkWell( onTap: () => widget._onTap(), @@ -44,7 +44,7 @@ class CorrectOverlayState extends State children: [ new Container( decoration: new BoxDecoration( - color: Colors.white, shape: BoxShape.circle), + color: Colors.blueAccent, shape: BoxShape.circle), child: new Transform.rotate( angle: _iconAnimation.value * 2 * math.pi, child: new Icon( diff --git a/lib/Screens/Puzzle/message_dialog.dart b/lib/Screens/Puzzle/message_dialog.dart new file mode 100644 index 0000000..f60d0fa --- /dev/null +++ b/lib/Screens/Puzzle/message_dialog.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; +import 'package:manager_api/api.dart'; +import 'package:tablet_app/Components/show_element_for_resource.dart'; +import 'package:tablet_app/app_context.dart'; +import 'package:tablet_app/constants.dart'; + +void showMessage(TranslationAndResourceDTO translationAndResourceDTO, AppContext appContext, BuildContext context, Size size) { + print("translationAndResourceDTO"); + print(translationAndResourceDTO); + showDialog( + builder: (BuildContext context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20.0)) + ), + content: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if(translationAndResourceDTO.resourceId != null) + Container( + //color: Colors.cyan, + height: size.height *0.45, + width: size.width *0.5, + child: Center( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + //border: Border.all(width: 3, color: Colors.black) + ), + child: showElementForResource(ResourceDTO(id: translationAndResourceDTO.resourceId, type: translationAndResourceDTO.resourceType, url: translationAndResourceDTO.resourceUrl), appContext), + ), + ), + ), + Container( + //color: Colors.green, + height: size.height *0.3, + width: size.width *0.5, + child: Center( + child: Align( + alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: HtmlWidget( + translationAndResourceDTO.value!, + customStylesBuilder: (element) { + return {'text-align': 'center'}; + }, + textStyle: TextStyle(fontSize: kDescriptionSize), + ),/*Text( + resourceDTO.label == null ? "" : resourceDTO.label, + style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),*/ + ), + ), + ), + ), + ], + ), + ), + /*actions: [ + 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( + text: "Merci", + icon: Icons.undo, + color: kSecondGrey, + press: () { + Navigator.of(context).pop(); + }, + fontSize: 20, + ), + ), + ), + ), + ], + ), + ],*/ + ), context: context + ); +} diff --git a/lib/Screens/Puzzle/puzzle_piece.dart b/lib/Screens/Puzzle/puzzle_piece.dart index 9ee7ea1..601a5a1 100644 --- a/lib/Screens/Puzzle/puzzle_piece.dart +++ b/lib/Screens/Puzzle/puzzle_piece.dart @@ -1,6 +1,10 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:tablet_app/Models/tabletContext.dart'; +import 'package:tablet_app/app_context.dart'; +import 'package:tablet_app/constants.dart'; class PuzzlePiece extends StatefulWidget { final Image image; @@ -49,14 +53,38 @@ class _PuzzlePieceState extends State { // can we move the piece ? bool isMovable = true; + GlobalKey _widgetPieceKey = GlobalKey(); + + @override + void initState() { + super.initState(); + + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + + RenderBox renderBox = _widgetPieceKey.currentContext?.findRenderObject() as RenderBox; + Size size = renderBox.size; + + final appContext = Provider.of(context, listen: false); + TabletAppContext tabletAppContext = appContext.getContext(); + tabletAppContext.puzzleSize = size; + appContext.setContext(tabletAppContext); + + if(widget.row == 0 && widget.col == 0) { + widget.sendToBack(widget); + } + }); + }); + } + @override Widget build(BuildContext context) { - // the image width - final imageWidth = MediaQuery.of(context).size.width; - // the image height - final imageHeight = MediaQuery.of(context).size.height * - MediaQuery.of(context).size.width / - widget.imageSize.width; + + var isPortrait = MediaQuery.of(context).orientation == Orientation.portrait; + + var imageHeight = isPortrait ? widget.imageSize.width/1.5 : widget.imageSize.width; + var imageWidth = isPortrait ? widget.imageSize.width/1.5: widget.imageSize.height; + final pieceWidth = imageWidth / widget.maxCol; final pieceHeight = imageHeight / widget.maxRow; @@ -64,60 +92,74 @@ class _PuzzlePieceState extends State { top = Random().nextInt((imageHeight - pieceHeight).ceil()).toDouble(); var test = top!; test -= widget.row * pieceHeight; - top = test; + top = test /2.2; // TODO change ? } + if (left == null) { left = Random().nextInt((imageWidth - pieceWidth).ceil()).toDouble(); var test = left!; test -= widget.col * pieceWidth; - left = test; + left = test /2.2; // TODO change ? + } + + if(widget.row == 0 && widget.col == 0) { + top = 0; + left = 0; + isMovable = false; } return Positioned( top: top, left: left, width: imageWidth, - child: GestureDetector( - onTap: () { - if (isMovable) { - widget.bringToTop(widget); - } - }, - onPanStart: (_) { - if (isMovable) { - widget.bringToTop(widget); - } - }, - onPanUpdate: (dragUpdateDetails) { - if (isMovable) { - setState(() { - var testTop = top!; - var testLeft = left!; - testTop = top!; - testLeft = left!; - testTop += dragUpdateDetails.delta.dy; - testLeft += dragUpdateDetails.delta.dx; - top = testTop!; - left = testLeft!; + child: Container( + key: _widgetPieceKey, + decoration: widget.col == 0 && widget.row == 0 ? BoxDecoration( + border: Border.all( + color: Colors.black, + width: 0.5, + ), + ) : null, + child: GestureDetector( + onTap: () { + if (isMovable) { + widget.bringToTop(widget); + } + }, + onPanStart: (_) { + if (isMovable) { + widget.bringToTop(widget); + } + }, + onPanUpdate: (dragUpdateDetails) { + if (isMovable) { + setState(() { + var testTop = top!; + var testLeft = left!; + testTop = top!; + testLeft = left!; + testTop += dragUpdateDetails.delta.dy; + testLeft += dragUpdateDetails.delta.dx; + top = testTop; + left = testLeft; - if (-10 < top! && top! < 10 && -10 < left! && left! < 10) { - top = 0; - left = 0; - isMovable = false; - widget.sendToBack(widget); - - //ScoreWidget.of(context).allInPlaceCount++; - } - }); - } - }, - child: ClipPath( - child: CustomPaint( - foregroundPainter: PuzzlePiecePainter( - widget.row, widget.col, widget.maxRow, widget.maxCol), - child: widget.image), - clipper: PuzzlePieceClipper( - widget.row, widget.col, widget.maxRow, widget.maxCol), + if (-10 < top! && top! < 10 && -10 < left! && left! < 10) { + top = 0; + left = 0; + isMovable = false; + widget.sendToBack(widget); + } + }); + } + }, + child: ClipPath( + child: CustomPaint( + foregroundPainter: PuzzlePiecePainter( + widget.row, widget.col, widget.maxRow, widget.maxCol), + child: widget.image), + clipper: PuzzlePieceClipper( + widget.row, widget.col, widget.maxRow, widget.maxCol), + ), ), )); } @@ -153,9 +195,9 @@ class PuzzlePiecePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final Paint paint = Paint() - ..color = Color(0x80FFFFFF) + ..color = Colors.black//Color(0x80FFFFFF) ..style = PaintingStyle.stroke - ..strokeWidth = 1.0; + ..strokeWidth = 2.5; canvas.drawPath(getPiecePath(size, row, col, maxRow, maxCol), paint); } diff --git a/lib/Screens/Puzzle/puzzle_view.dart b/lib/Screens/Puzzle/puzzle_view.dart index c638b00..bdb1cac 100644 --- a/lib/Screens/Puzzle/puzzle_view.dart +++ b/lib/Screens/Puzzle/puzzle_view.dart @@ -4,6 +4,11 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:manager_api/api.dart'; +import 'package:provider/provider.dart'; +import 'package:tablet_app/Components/loading_common.dart'; +import 'package:tablet_app/Models/tabletContext.dart'; +import 'package:tablet_app/Screens/Puzzle/message_dialog.dart'; +import 'package:tablet_app/app_context.dart'; import 'puzzle_piece.dart'; import 'score_widget.dart'; @@ -14,49 +19,61 @@ class PuzzleView extends StatefulWidget { PuzzleView({this.section}); @override - _PuzzleViewWidget createState() => _PuzzleViewWidget(); + _PuzzleView createState() => _PuzzleView(); } -class _PuzzleViewWidget extends State { - SliderDTO sliderDTO = SliderDTO(); - final int rows = 3; - final int cols = 3; +class _PuzzleView extends State { + PuzzleDTO puzzleDTO = PuzzleDTO(); + + int allInPlaceCount = 0; + bool isFinished = false; + + GlobalKey _widgetKey = GlobalKey(); + Size? realWidgetSize; //File? _image; String? _imagePath; List pieces = []; - bool _overlayVisible = true; + bool isSplittingImage = true; + @override void initState() { - sliderDTO = SliderDTO.fromJson(jsonDecode(widget.section!.data!))!; + puzzleDTO = PuzzleDTO.fromJson(jsonDecode(widget.section!.data!))!; + + puzzleDTO.rows = puzzleDTO.rows != null ? puzzleDTO.rows : 3; + puzzleDTO.cols = puzzleDTO.cols != null ? puzzleDTO.cols : 3; + + WidgetsBinding.instance.addPostFrameCallback((_) { + Size size = MediaQuery.of(context).size; + final appContext = Provider.of(context, listen: false); + TabletAppContext tabletAppContext = appContext.getContext(); + TranslationAndResourceDTO? messageDebut = puzzleDTO.messageDebut != null ? puzzleDTO.messageDebut!.firstWhere((message) => message.language!.toUpperCase() == tabletAppContext.language!.toUpperCase()) : null; + + if(messageDebut != null) { + showMessage(messageDebut, appContext, context, size); + } + + getRealWidgetSize(); + }); - sliderDTO.images!.sort((a, b) => a.order!.compareTo(b.order!)); super.initState(); - splitImage(Image.network(sliderDTO.images![1].source_!)); + + if(puzzleDTO.image != null && puzzleDTO.image!.resourceUrl != null) { + splitImage(Image.network(puzzleDTO.image!.resourceUrl!)); + } } - /*void savePrefs() async { - await prefs!.setString(IMAGE_PATH, _imagePath!); - }*/ + Future getRealWidgetSize() async { + RenderBox renderBox = _widgetKey.currentContext?.findRenderObject() as RenderBox; + Size size = renderBox.size; - /*Future getImage(ImageSource source) async { - var image = await ImagePicker.platform.(source: source); - - if (image != null) { - setState(() { - _image = image; - _imagePath = _image!.path; - pieces.clear(); - ScoreWidget - .of(context) - .allInPlaceCount = 0; - }); - } - splitImage(Image.file(image)); - savePrefs(); - }*/ + setState(() { + realWidgetSize = size; + }); + print("Taille réelle du widget : $size"); + } // we need to find out the image size, to be used in the PuzzlePiece widget Future getImageSize(Image image) async { @@ -78,9 +95,11 @@ class _PuzzleViewWidget extends State { // using the rows and columns defined above; each piece will be added to a stack void splitImage(Image image) async { Size imageSize = await getImageSize(image); + //imageSize = realWidgetSize!; + imageSize = Size(realWidgetSize!.width * 1.25, realWidgetSize!.height * 1.25); - for (int x = 0; x < rows; x++) { - for (int y = 0; y < cols; y++) { + for (int x = 0; x < puzzleDTO.rows!; x++) { + for (int y = 0; y < puzzleDTO.cols!; y++) { setState(() { pieces.add( PuzzlePiece( @@ -89,8 +108,8 @@ class _PuzzleViewWidget extends State { imageSize: imageSize, row: x, col: y, - maxRow: rows, - maxCol: cols, + maxRow: puzzleDTO.rows!, + maxCol: puzzleDTO.cols!, bringToTop: this.bringToTop, sendToBack: this.sendToBack, ), @@ -98,6 +117,10 @@ class _PuzzleViewWidget extends State { }); } } + + setState(() { + isSplittingImage = false; + }); } // when the pan of a piece starts, we need to bring it to the front of the stack @@ -112,38 +135,61 @@ class _PuzzleViewWidget extends State { // it will be sent to the back of the stack to not get in the way of other, still movable, pieces void sendToBack(Widget widget) { setState(() { + allInPlaceCount++; + isFinished = allInPlaceCount == puzzleDTO.rows! * puzzleDTO.cols!; pieces.remove(widget); pieces.insert(0, widget); + + if(isFinished) { + Size size = MediaQuery.of(context).size; + final appContext = Provider.of(context, listen: false); + TabletAppContext tabletAppContext = appContext.getContext(); + TranslationAndResourceDTO? messageFin = puzzleDTO.messageFin != null ? puzzleDTO.messageFin!.firstWhere((message) => message.language!.toUpperCase() == tabletAppContext.language!.toUpperCase()) : null; + + if(messageFin != null) { + showMessage(messageFin, appContext, context, size); + } + } }); } @override Widget build(BuildContext context) { - //savePrefs(); + final appContext = Provider.of(context); + TabletAppContext tabletAppContext = appContext.getContext(); - return SafeArea( - child: sliderDTO.images![0].source_! == null - ? Center(child: Text('No image selected.')) - : Stack( - children: pieces, - ), - ); /*ScoreWidget - .of(context) - .allInPlaceCount == - rows * cols - ? Overlay( - initialEntries: [ - OverlayEntry(builder: (context) { - return CorrectOverlay(true, () { - setState(() { - ScoreWidget - .of(context) - .allInPlaceCount = 0; - }); - }); - }) - ], - ) - :*/ + return Padding( + key: _widgetKey, + padding: const EdgeInsets.all(10.0), + child: isSplittingImage ? Center(child: LoadingCommon()) : + puzzleDTO.image!.resourceUrl == null || realWidgetSize == null + ? Container( + width: 50, + height: 50, + color: Colors.cyan, + child: InkWell(onTap: () { + Size size = MediaQuery.of(context).size; + final appContext = Provider.of(context, listen: false); + TabletAppContext tabletAppContext = appContext.getContext(); + TranslationAndResourceDTO? messageFin = puzzleDTO.messageFin != null ? puzzleDTO.messageFin!.firstWhere((message) => message.language!.toUpperCase() == tabletAppContext.language!.toUpperCase()) : null; + + if(messageFin != null) { + // Alert dialog + showMessage(messageFin, appContext, context, size); + } + },),)//Center(child: Text("Invalid image")) + : Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: tabletAppContext.puzzleSize != null ? tabletAppContext.puzzleSize!.width : realWidgetSize!.width * 0.8, + height: tabletAppContext.puzzleSize != null ? tabletAppContext.puzzleSize!.height +1.5 : realWidgetSize!.height * 0.8, + child: Stack( + children: pieces, + ), + ), + ), + ), + ); } } \ No newline at end of file diff --git a/lib/Screens/Quizz/quizz_view.dart b/lib/Screens/Quizz/quizz_view.dart index bd9ea33..924a54a 100644 --- a/lib/Screens/Quizz/quizz_view.dart +++ b/lib/Screens/Quizz/quizz_view.dart @@ -17,16 +17,16 @@ import 'package:tablet_app/constants.dart'; import 'drawStrawberry.dart'; -class QuizzViewWidget extends StatefulWidget { +class QuizzView extends StatefulWidget { final SectionDTO? section; GlobalKey? key; - QuizzViewWidget({this.section, this.key}); + QuizzView({this.section, this.key}); @override - _QuizzViewWidget createState() => _QuizzViewWidget(); + _QuizzView createState() => _QuizzView(); } -class _QuizzViewWidget extends State { +class _QuizzView extends State { ConfettiController? _controllerCenter; QuizzDTO quizzDTO = QuizzDTO(); List _questionsSubDTO = []; @@ -303,11 +303,11 @@ class _QuizzViewWidget extends State { color: kBackgroundLight, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(20.0), - image: i.source_ != null ? new DecorationImage( - fit: BoxFit.contain, + image: i.resourceUrl != null ? new DecorationImage( + fit: BoxFit.cover, opacity: 0.35, image: new NetworkImage( - i.source_!, + i.resourceUrl!, ), ): null, boxShadow: [ @@ -382,9 +382,9 @@ class _QuizzViewWidget extends State { child: GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, - mainAxisExtent: kIsWeb ? 75 : 150, // TODO depends on percentage - mainAxisSpacing: kIsWeb ? 75 : 150, // TODO depends on percentage - crossAxisSpacing: kIsWeb ? 75 : 150, // TODO depends on percentage + mainAxisExtent: kIsWeb ? 75 : 100, // TODO depends on percentage 150 + mainAxisSpacing: kIsWeb ? 75 : 45, // TODO depends on percentage + crossAxisSpacing: kIsWeb ? 75 : 20, // TODO depends on percentage ), itemCount: i.responsesSubDTO!.length, itemBuilder: (BuildContext ctx, index) { @@ -464,8 +464,8 @@ class _QuizzViewWidget extends State { }, child: Icon( Icons.chevron_right, - size: kIsWeb ? 100 : 150, - color: kMainRed, + size: kIsWeb ? 100 : 95, + color: kTestSecondColor, ), ) ), @@ -480,8 +480,8 @@ class _QuizzViewWidget extends State { }, child: Icon( Icons.chevron_left, - size: kIsWeb ? 100 : 150, - color: kMainRed, + size: kIsWeb ? 100 : 95, + color: kTestSecondColor, ), ) ), @@ -493,7 +493,7 @@ class _QuizzViewWidget extends State { child: InkWell( child: Text( currentIndex.toString()+'/'+quizzDTO.questions!.length.toString(), - style: TextStyle(fontSize: 30, fontWeight: FontWeight.w500), + style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500), ), ) ), diff --git a/lib/Screens/Quizz/showResponses.dart b/lib/Screens/Quizz/showResponses.dart index 3f75f80..729eb01 100644 --- a/lib/Screens/Quizz/showResponses.dart +++ b/lib/Screens/Quizz/showResponses.dart @@ -76,11 +76,11 @@ class _ShowReponsesWidget extends State { color: kBackgroundLight, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(20.0), - image: i.source_ != null ? new DecorationImage( + image: i.resourceUrl != null ? new DecorationImage( fit: BoxFit.contain, opacity: 0.35, image: new NetworkImage( - i.source_!, + i.resourceUrl!, ), ): null, boxShadow: [ diff --git a/lib/Screens/Slider/slider_view.dart b/lib/Screens/Slider/slider_view.dart index 16ce3c1..4dd3fc3 100644 --- a/lib/Screens/Slider/slider_view.dart +++ b/lib/Screens/Slider/slider_view.dart @@ -6,19 +6,20 @@ import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:manager_api/api.dart'; import 'package:provider/provider.dart'; +import 'package:tablet_app/Components/video_viewer.dart'; import 'package:tablet_app/app_context.dart'; import 'package:tablet_app/constants.dart'; import 'package:photo_view/photo_view.dart'; -class SliderViewWidget extends StatefulWidget { +class SliderView extends StatefulWidget { final SectionDTO? section; - SliderViewWidget({this.section}); + SliderView({this.section}); @override - _SliderViewWidget createState() => _SliderViewWidget(); + _SliderView createState() => _SliderView(); } -class _SliderViewWidget extends State { +class _SliderView extends State { SliderDTO sliderDTO = SliderDTO(); CarouselController? sliderController; int currentIndex = 1; @@ -30,7 +31,7 @@ class _SliderViewWidget extends State { sliderController = CarouselController(); sliderDTO = SliderDTO.fromJson(jsonDecode(widget.section!.data!))!; - sliderDTO.images!.sort((a, b) => a.order!.compareTo(b.order!)); + sliderDTO.contents!.sort((a, b) => a.order!.compareTo(b.order!)); super.initState(); } @@ -54,7 +55,7 @@ class _SliderViewWidget extends State { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - if(sliderDTO.images != null && sliderDTO.images!.length > 0) + if(sliderDTO.contents != null && sliderDTO.contents!.length > 0) CarouselSlider( carouselController: sliderController, options: CarouselOptions( @@ -67,7 +68,7 @@ class _SliderViewWidget extends State { enlargeCenterPage: true, reverse: false, ), - items: sliderDTO.images!.map((i) { + items: sliderDTO.contents!.map((i) { return Builder( builder: (BuildContext context) { return Container( @@ -116,18 +117,18 @@ class _SliderViewWidget extends State { child: AspectRatio( aspectRatio: 16 / 9, child: ClipRect( - child: PhotoView( + child: VideoViewer(videoUrl: "https://firebasestorage.googleapis.com/v0/b/mymuseum-3b97f.appspot.com/o/All%2024%20Cybertruck%20Accessories%20Revealed!.mp4?alt=media&token=fc178259-10fc-4167-b496-cf7d04aaae5e")/*PhotoView( imageProvider: new NetworkImage( i.source_!, ), minScale: PhotoViewComputedScale.contained * 0.8, maxScale: PhotoViewComputedScale.contained * 3.0, - backgroundDecoration: BoxDecoration( + backgroundDecoration: BoxDecoration( color: kBackgroundSecondGrey, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(15.0), ), - ), + ),*/ ), ), ), @@ -190,39 +191,39 @@ class _SliderViewWidget extends State { ), ], ), - if(sliderDTO.images != null && sliderDTO.images!.length > 1) + if(sliderDTO.contents != null && sliderDTO.contents!.length > 1) Positioned( top: MediaQuery.of(context).size.height * 0.35, right: 60, child: InkWell( onTap: () { - if (sliderDTO.images!.length > 0) + if (sliderDTO.contents!.length > 0) sliderController!.nextPage(duration: new Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); }, child: Icon( Icons.chevron_right, - size: 150, - color: kMainRed, + size: 90, + color: Colors.white, ), ) ), - if(sliderDTO.images != null && sliderDTO.images!.length > 1) + if(sliderDTO.contents != null && sliderDTO.contents!.length > 1) Positioned( top: MediaQuery.of(context).size.height * 0.35, left: 60, child: InkWell( onTap: () { - if (sliderDTO.images!.length > 0) + if (sliderDTO.contents!.length > 0) sliderController!.previousPage(duration: new Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); }, child: Icon( Icons.chevron_left, - size: 150, - color: kMainRed, + size: 90, + color: Colors.white, ), ) ), - if(sliderDTO.images != null && sliderDTO.images!.length > 0) + if(sliderDTO.contents != null && sliderDTO.contents!.length > 0) Padding( padding: widget.section!.parentId == null ? EdgeInsets.only() : const EdgeInsets.only(left: 15, bottom: 10), child: Align( @@ -232,14 +233,14 @@ class _SliderViewWidget extends State { sliderController!.previousPage(duration: new Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); }, child: Text( - currentIndex.toString()+'/'+sliderDTO.images!.length.toString(), - style: TextStyle(fontSize: 30, fontWeight: FontWeight.w500), + currentIndex.toString()+'/'+sliderDTO.contents!.length.toString(), + style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500), ), ) ), ), - if(sliderDTO.images == null || sliderDTO.images!.length == 0) - Center(child: Text("Aucune image à afficher", style: TextStyle(fontSize: kNoneInfoOrIncorrect),)) + if(sliderDTO.contents == null || sliderDTO.contents!.length == 0) + Center(child: Text("Aucun contenu à afficher", style: TextStyle(fontSize: kNoneInfoOrIncorrect),)) // Description /*Container( height: sliderDTO.images != null && sliderDTO.images.length > 0 ? size.height *0.3 : size.height *0.6, diff --git a/lib/Screens/Video/video_view.dart b/lib/Screens/Video/video_view.dart index a8d2763..313d5c2 100644 --- a/lib/Screens/Video/video_view.dart +++ b/lib/Screens/Video/video_view.dart @@ -7,15 +7,15 @@ import 'package:tablet_app/constants.dart'; import 'package:youtube_player_iframe/youtube_player_iframe.dart' as iframe; import 'package:youtube_player_flutter/youtube_player_flutter.dart'; -class VideoViewWidget extends StatefulWidget { +class VideoView extends StatefulWidget { final SectionDTO? section; - VideoViewWidget({this.section}); + VideoView({this.section}); @override - _VideoViewWidget createState() => _VideoViewWidget(); + _VideoView createState() => _VideoView(); } -class _VideoViewWidget extends State { +class _VideoView extends State { iframe.YoutubePlayer? _videoViewWeb; YoutubePlayer? _videoView; VideoDTO? videoDTO; diff --git a/lib/Screens/Web/web_view.dart b/lib/Screens/Web/web_view.dart index 18eae19..653387e 100644 --- a/lib/Screens/Web/web_view.dart +++ b/lib/Screens/Web/web_view.dart @@ -14,10 +14,10 @@ class WebView extends StatefulWidget { WebView({this.section}); @override - _WebViewWidget createState() => _WebViewWidget(); + _WebView createState() => _WebView(); } -class _WebViewWidget extends State { +class _WebView extends State { //final IFrameElement _iframeElement = IFrameElement(); //WebView _webView; WebDTO webDTO = WebDTO(); diff --git a/lib/api/swagger.yaml b/lib/api/swagger.yaml index e6997e0..f8d3bde 100644 --- a/lib/api/swagger.yaml +++ b/lib/api/swagger.yaml @@ -5,7 +5,7 @@ info: description: API Manager Service version: Version Alpha servers: - - url: http://localhost:5000 + - url: https://api.myinfomate.be paths: /api/Configuration: get: @@ -2400,6 +2400,12 @@ components: nullable: true oneOf: - $ref: '#/components/schemas/ContentDTO' + rows: + type: integer + format: int32 + cols: + type: integer + format: int32 AgendaDTO: type: object additionalProperties: false diff --git a/lib/constants.dart b/lib/constants.dart index 6e3a7af..1be3e8c 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -17,20 +17,20 @@ const kBackgroundLight = Color(0xfff3f3f3); const List languages = ["FR", "NL", "EN", "DE", "IT", "ES", "PL", "CN", "AR", "UK"]; // hmmmm depends on config.. -const kTitleSize = 40.0; -const kDescriptionSize = 25.0; +const kTitleSize = 32.0; +const kDescriptionSize = 15.0; -const kSectionTitleDetailSize = 50.0; -const kSectionDescriptionDetailSize = 35.0; +const kSectionTitleDetailSize = 30.0; +const kSectionDescriptionDetailSize = 18.0; -const kMenuTitleDetailSize = 45.0; -const kMenuDescriptionDetailSize = 28.0; +const kMenuTitleDetailSize = 30.0; +const kMenuDescriptionDetailSize = 15.0; // WEB const kWebMenuTitleDetailSize = 30.0; const kWebMenuDescriptionDetailSize = 14.0; -const kWebSectionTitleDetailSize = 35.0; -const kWebSectionDescriptionDetailSize = 20.0; +const kWebSectionTitleDetailSize = 30.0; +const kWebSectionDescriptionDetailSize = 15.0; const kWebTitleSize = 30.0; const kWebDescriptionSize = 14.0; diff --git a/lib/main.dart b/lib/main.dart index cc70db4..e9a6061 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -45,7 +45,7 @@ void main() async { } } else { print("NO LOCAL DB !"); - localContext = TabletAppContext(host: "https://api.mymuseum.be"); + localContext = TabletAppContext(host: "https://api.myinfomate.be"); } if(kIsWeb) { diff --git a/manager_api/doc/AuthenticationApi.md b/manager_api/doc/AuthenticationApi.md index 8fdf05d..71112c8 100644 --- a/manager_api/doc/AuthenticationApi.md +++ b/manager_api/doc/AuthenticationApi.md @@ -5,7 +5,7 @@ import 'package:manager_api/api.dart'; ``` -All URIs are relative to *http://localhost:5000* +All URIs are relative to *https://api.myinfomate.be* Method | HTTP request | Description ------------- | ------------- | ------------- diff --git a/manager_api/doc/ConfigurationApi.md b/manager_api/doc/ConfigurationApi.md index 99d625e..7ef7c1c 100644 --- a/manager_api/doc/ConfigurationApi.md +++ b/manager_api/doc/ConfigurationApi.md @@ -5,7 +5,7 @@ import 'package:manager_api/api.dart'; ``` -All URIs are relative to *http://localhost:5000* +All URIs are relative to *https://api.myinfomate.be* Method | HTTP request | Description ------------- | ------------- | ------------- diff --git a/manager_api/doc/DeviceApi.md b/manager_api/doc/DeviceApi.md index 020ce00..aef8698 100644 --- a/manager_api/doc/DeviceApi.md +++ b/manager_api/doc/DeviceApi.md @@ -5,7 +5,7 @@ import 'package:manager_api/api.dart'; ``` -All URIs are relative to *http://localhost:5000* +All URIs are relative to *https://api.myinfomate.be* Method | HTTP request | Description ------------- | ------------- | ------------- diff --git a/manager_api/doc/InstanceApi.md b/manager_api/doc/InstanceApi.md index 4176d2e..a0aaa08 100644 --- a/manager_api/doc/InstanceApi.md +++ b/manager_api/doc/InstanceApi.md @@ -5,7 +5,7 @@ import 'package:manager_api/api.dart'; ``` -All URIs are relative to *http://localhost:5000* +All URIs are relative to *https://api.myinfomate.be* Method | HTTP request | Description ------------- | ------------- | ------------- diff --git a/manager_api/doc/PuzzleDTO.md b/manager_api/doc/PuzzleDTO.md index 55c1750..a6655c1 100644 --- a/manager_api/doc/PuzzleDTO.md +++ b/manager_api/doc/PuzzleDTO.md @@ -11,6 +11,8 @@ Name | Type | Description | Notes **messageDebut** | [**List**](TranslationAndResourceDTO.md) | | [optional] [default to const []] **messageFin** | [**List**](TranslationAndResourceDTO.md) | | [optional] [default to const []] **image** | [**PuzzleDTOImage**](PuzzleDTOImage.md) | | [optional] +**rows** | **int** | | [optional] +**cols** | **int** | | [optional] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/manager_api/doc/ResourceApi.md b/manager_api/doc/ResourceApi.md index fb6bad9..22722f9 100644 --- a/manager_api/doc/ResourceApi.md +++ b/manager_api/doc/ResourceApi.md @@ -5,7 +5,7 @@ import 'package:manager_api/api.dart'; ``` -All URIs are relative to *http://localhost:5000* +All URIs are relative to *https://api.myinfomate.be* Method | HTTP request | Description ------------- | ------------- | ------------- diff --git a/manager_api/doc/SectionApi.md b/manager_api/doc/SectionApi.md index 6afa0b2..039f7f4 100644 --- a/manager_api/doc/SectionApi.md +++ b/manager_api/doc/SectionApi.md @@ -5,7 +5,7 @@ import 'package:manager_api/api.dart'; ``` -All URIs are relative to *http://localhost:5000* +All URIs are relative to *https://api.myinfomate.be* Method | HTTP request | Description ------------- | ------------- | ------------- diff --git a/manager_api/doc/UserApi.md b/manager_api/doc/UserApi.md index 6a55295..644770e 100644 --- a/manager_api/doc/UserApi.md +++ b/manager_api/doc/UserApi.md @@ -5,7 +5,7 @@ import 'package:manager_api/api.dart'; ``` -All URIs are relative to *http://localhost:5000* +All URIs are relative to *https://api.myinfomate.be* Method | HTTP request | Description ------------- | ------------- | ------------- diff --git a/manager_api/lib/api_client.dart b/manager_api/lib/api_client.dart index 0193f94..fa3fc94 100644 --- a/manager_api/lib/api_client.dart +++ b/manager_api/lib/api_client.dart @@ -11,7 +11,7 @@ part of openapi.api; class ApiClient { - ApiClient({this.basePath = 'http://localhost:5000', this.authentication,}); + ApiClient({this.basePath = 'https://api.myinfomate.be', this.authentication,}); final String basePath; final Authentication? authentication; diff --git a/manager_api/lib/model/puzzle_dto.dart b/manager_api/lib/model/puzzle_dto.dart index 2955a13..14654e5 100644 --- a/manager_api/lib/model/puzzle_dto.dart +++ b/manager_api/lib/model/puzzle_dto.dart @@ -16,6 +16,8 @@ class PuzzleDTO { this.messageDebut = const [], this.messageFin = const [], this.image, + this.rows, + this.cols, }); List? messageDebut; @@ -24,21 +26,41 @@ class PuzzleDTO { PuzzleDTOImage? image; + /// + /// Please note: This property should have been non-nullable! Since the specification file + /// does not include a default value (using the "default:" property), however, the generated + /// source code must fall back to having a nullable type. + /// Consider adding a "default:" property in the specification file to hide this note. + /// + int? rows; + + /// + /// Please note: This property should have been non-nullable! Since the specification file + /// does not include a default value (using the "default:" property), however, the generated + /// source code must fall back to having a nullable type. + /// Consider adding a "default:" property in the specification file to hide this note. + /// + int? cols; + @override bool operator ==(Object other) => identical(this, other) || other is PuzzleDTO && other.messageDebut == messageDebut && other.messageFin == messageFin && - other.image == image; + other.image == image && + other.rows == rows && + other.cols == cols; @override int get hashCode => // ignore: unnecessary_parenthesis (messageDebut == null ? 0 : messageDebut!.hashCode) + (messageFin == null ? 0 : messageFin!.hashCode) + - (image == null ? 0 : image!.hashCode); + (image == null ? 0 : image!.hashCode) + + (rows == null ? 0 : rows!.hashCode) + + (cols == null ? 0 : cols!.hashCode); @override - String toString() => 'PuzzleDTO[messageDebut=$messageDebut, messageFin=$messageFin, image=$image]'; + String toString() => 'PuzzleDTO[messageDebut=$messageDebut, messageFin=$messageFin, image=$image, rows=$rows, cols=$cols]'; Map toJson() { final json = {}; @@ -57,6 +79,16 @@ class PuzzleDTO { } else { json[r'image'] = null; } + if (this.rows != null) { + json[r'rows'] = this.rows; + } else { + json[r'rows'] = null; + } + if (this.cols != null) { + json[r'cols'] = this.cols; + } else { + json[r'cols'] = null; + } return json; } @@ -82,6 +114,8 @@ class PuzzleDTO { messageDebut: TranslationAndResourceDTO.listFromJson(json[r'messageDebut']), messageFin: TranslationAndResourceDTO.listFromJson(json[r'messageFin']), image: PuzzleDTOImage.fromJson(json[r'image']), + rows: mapValueOfType(json, r'rows'), + cols: mapValueOfType(json, r'cols'), ); } return null; diff --git a/manager_api/lib/model/resource_type.dart b/manager_api/lib/model/resource_type.dart index 14ee7c1..8cc1f79 100644 --- a/manager_api/lib/model/resource_type.dart +++ b/manager_api/lib/model/resource_type.dart @@ -23,28 +23,28 @@ class ResourceType { int toJson() => value; - static const image = ResourceType._(0); - static const video = ResourceType._(1); - static const imageUrl = ResourceType._(2); - static const videoUrl = ResourceType._(3); - static const audio = ResourceType._(4); - static const PDF = ResourceType._(5); - static const JSON = ResourceType._(6); + static const Image = ResourceType._(0); + static const Video = ResourceType._(1); + static const ImageUrl = ResourceType._(2); + static const VideoUrl = ResourceType._(3); + static const Audio = ResourceType._(4); + static const Pdf = ResourceType._(5); + static const Json = ResourceType._(6); /// List of all possible values in this [enum][ResourceType]. static const values = [ - image, - video, - imageUrl, - videoUrl, - audio, - PDF, - JSON + Image, + Video, + ImageUrl, + VideoUrl, + Audio, + Pdf, + Json ]; static ResourceType? fromJson(dynamic value) => ResourceTypeTypeTransformer().decode(value); - static List listFromJson(dynamic json, {bool growable = false,}) { + static List? listFromJson(dynamic json, {bool growable = false,}) { final result = []; if (json is List && json.isNotEmpty) { for (final row in json) { @@ -77,18 +77,36 @@ class ResourceTypeTypeTransformer { /// and users are still using an old app with the old code. ResourceType? decode(dynamic data, {bool allowNull = true}) { if (data != null) { - switch (data.toString()) { - case r'Image': return ResourceType.image; - case r'Video': return ResourceType.video; - case r'ImageUrl': return ResourceType.imageUrl; - case r'VideoUrl': return ResourceType.videoUrl; - case r'Audio': return ResourceType.audio; - case r'PDF': return ResourceType.PDF; - case r'JSON': return ResourceType.JSON; - default: - if (!allowNull) { - throw ArgumentError('Unknown enum value to decode: $data'); + if(data.runtimeType == String) { + switch (data.toString()) { + case "Image": return ResourceType.Image; + case "Video": return ResourceType.Video; + case "ImageUrl": return ResourceType.ImageUrl; + case "VideoUrl": return ResourceType.VideoUrl; + case "Audio": return ResourceType.Audio; + case "PDF": return ResourceType.Pdf; + case "JSON": return ResourceType.Json; + default: + if (!allowNull) { + throw ArgumentError('Unknown enum value to decode: $data'); + } + } + } else { + if(data.runtimeType == int) { + switch (data) { + case 0: return ResourceType.Image; + case 1: return ResourceType.Video; + case 2: return ResourceType.ImageUrl; + case 3: return ResourceType.VideoUrl; + case 4: return ResourceType.Audio; + case 5: return ResourceType.Pdf; + case 6: return ResourceType.Json; + default: + if (!allowNull) { + throw ArgumentError('Unknown enum value to decode: $data'); + } } + } } } return null;