Handle resource viewer + add rows and cols to puzzle

This commit is contained in:
Thomas Fransolet 2023-12-29 14:59:21 +01:00
parent ce815f9950
commit 1d81997a99
20 changed files with 380 additions and 74 deletions

View File

@ -30,7 +30,7 @@ class _RoundedPasswordFieldState extends State<RoundedPasswordField> {
style: TextStyle(fontSize: 20, color: kBlack),
decoration: InputDecoration(
hintText: "Mot de passe",
hintStyle: TextStyle(fontSize: 20.0, color: kBlack),
hintStyle: TextStyle(fontSize: 20.0, color: kBlack, fontWeight: FontWeight.normal),
icon: Icon(
Icons.lock,
color: kPrimaryColor,

View File

@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import 'package:manager_app/Components/loading_common.dart';
import 'package:video_player/video_player.dart';
import '../../constants.dart';
class VideoViewer extends StatefulWidget {
final String videoUrl;
VideoViewer({required this.videoUrl});
@override
_VideoViewer createState() => _VideoViewer();
}
class _VideoViewer extends State<VideoViewer> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.networkUrl(Uri.parse(
widget.videoUrl))
..initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Center(
child: InkWell(
onTap: () {
setState(() {
if(_controller.value.isInitialized) {
if(_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
}
});
},
child: _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Center(
child: Container(
child: LoadingCommon()
)
),
),
),
if(!_controller.value.isPlaying && _controller.value.isInitialized)
Center(
child: FloatingActionButton(
backgroundColor: kPrimaryColor.withOpacity(0.8),
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white),
),
)
],
);
}
}

View File

@ -0,0 +1,91 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:youtube_player_iframe/youtube_player_iframe.dart' as iframe;
import 'package:youtube_player_iframe/youtube_player_iframe.dart';
class VideoViewerYoutube extends StatefulWidget {
final String videoUrl;
VideoViewerYoutube({required this.videoUrl});
@override
_VideoViewerYoutube createState() => _VideoViewerYoutube();
}
class _VideoViewerYoutube extends State<VideoViewerYoutube> {
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: 12)));
}

View File

@ -1,7 +1,9 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:manager_app/Components/message_notification.dart';
import 'package:manager_app/Components/multi_string_input_and_resource_container.dart';
import 'package:manager_app/Components/multi_string_input_container.dart';
import 'package:manager_app/Components/number_input_container.dart';
import 'package:manager_app/Components/resource_input_container.dart';
import 'package:manager_api_new/api.dart';
import 'dart:convert';
@ -35,12 +37,19 @@ class _PuzzleConfigState extends State<PuzzleConfig> {
test.image = PuzzleDTOImage();
}
puzzleDTO = test;
puzzleDTO.rows = puzzleDTO.rows == null ? 3 : puzzleDTO.rows;
puzzleDTO.cols = puzzleDTO.cols == null ? 3 : puzzleDTO.cols;
super.initState();
}
@override
Widget build(BuildContext context) {
return Row(
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ResourceInputContainer(
@ -69,6 +78,7 @@ class _PuzzleConfigState extends State<PuzzleConfig> {
print(value);
if (puzzleDTO.messageDebut != value) {
setState(() {
print(puzzleDTO.messageDebut);
puzzleDTO.messageDebut = value;
widget.onChanged(jsonEncode(puzzleDTO).toString());
});
@ -99,6 +109,53 @@ class _PuzzleConfigState extends State<PuzzleConfig> {
)
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
height: 100,
child: NumberInputContainer(
label: "Nombre de lignes :",
initialValue: puzzleDTO.rows!,
isSmall: true,
maxLength: 2,
onChanged: (value) {
try {
puzzleDTO.rows = int.parse(value);
setState(() {
widget.onChanged(jsonEncode(puzzleDTO).toString());
});
} catch (e) {
print('Puzzle rows not a number');
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
}
},
),
),
Container(
height: 100,
child: NumberInputContainer(
label: "Nombre de colonnes :",
initialValue: puzzleDTO.cols!,
isSmall: true,
maxLength: 2,
onChanged: (value) {
try {
puzzleDTO.cols = int.parse(value);
setState(() {
widget.onChanged(jsonEncode(puzzleDTO).toString());
});
} catch (e) {
print('Puzzle rows not a number');
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);
}
},
),
),
],)
],
),
);
}
}

View File

@ -206,14 +206,14 @@ class _SectionDetailScreenState extends State<SectionDetailScreen> {
});
},
),
if(sectionDTO!.isBeacon!)
if(sectionDTO.isBeacon!)
NumberInputContainer(
label: "Identifiant Beacon :",
initialValue: sectionDTO!.beaconId != null ? sectionDTO.beaconId! : 0,
initialValue: sectionDTO.beaconId != null ? sectionDTO.beaconId! : 0,
isSmall: true,
onChanged: (value) {
try {
sectionDTO!.beaconId = int.parse(value);
sectionDTO.beaconId = int.parse(value);
} catch (e) {
print('BeaconId not a number');
showNotification(Colors.orange, kWhite, 'Cela doit être un chiffre', context, null);

View File

@ -3,6 +3,8 @@ import 'dart:typed_data';
import 'package:manager_app/Components/audio_player.dart';
import 'package:manager_app/Components/loading_common.dart';
import 'package:manager_app/Components/video_viewer.dart';
import 'package:manager_app/Components/video_viewer_youtube.dart';
import 'package:manager_app/Models/managerContext.dart';
import 'package:manager_app/app_context.dart';
import 'package:manager_app/constants.dart';
@ -84,11 +86,25 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
);*/
//return Text("Fichier audio - aucune visualisation possible");
case ResourceType.Video:
return Text("Vidéo locale - aucune visualisation possible");
if(resourceDTO.url == null) {
return Center(child: Text("Error loading video"));
} else {
return VideoViewer(videoUrl: resourceDTO.url!);
}
case ResourceType.VideoUrl:
return Text(resourceDTO.url);
return SelectableText(resourceDTO.url!);
/*case ResourceType.VideoUrl:
if(resourceDTO.url == null) {
return Center(child: Text("Error loading video"));
} else {
return VideoViewerYoutube(videoUrl: resourceDTO.url!);
}*/ // TODO
case ResourceType.Pdf:
return Text("Fichier pdf - aucune visualisation possible");
case ResourceType.Json:
return Text("Fichier json - aucune visualisation possible");
}

View File

@ -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

View File

@ -60,7 +60,7 @@ try {
## Documentation for API Endpoints
All URIs are relative to *http://localhost:5000*
All URIs are relative to *https://api.myinfomate.be*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------

View File

@ -5,7 +5,7 @@
import 'package:manager_api_new/api.dart';
```
All URIs are relative to *http://localhost:5000*
All URIs are relative to *https://api.myinfomate.be*
Method | HTTP request | Description
------------- | ------------- | -------------

View File

@ -5,7 +5,7 @@
import 'package:manager_api_new/api.dart';
```
All URIs are relative to *http://localhost:5000*
All URIs are relative to *https://api.myinfomate.be*
Method | HTTP request | Description
------------- | ------------- | -------------

View File

@ -5,7 +5,7 @@
import 'package:manager_api_new/api.dart';
```
All URIs are relative to *http://localhost:5000*
All URIs are relative to *https://api.myinfomate.be*
Method | HTTP request | Description
------------- | ------------- | -------------

View File

@ -5,7 +5,7 @@
import 'package:manager_api_new/api.dart';
```
All URIs are relative to *http://localhost:5000*
All URIs are relative to *https://api.myinfomate.be*
Method | HTTP request | Description
------------- | ------------- | -------------

View File

@ -11,6 +11,8 @@ Name | Type | Description | Notes
**messageDebut** | [**List<TranslationAndResourceDTO>**](TranslationAndResourceDTO.md) | | [optional] [default to const []]
**messageFin** | [**List<TranslationAndResourceDTO>**](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)

View File

@ -5,7 +5,7 @@
import 'package:manager_api_new/api.dart';
```
All URIs are relative to *http://localhost:5000*
All URIs are relative to *https://api.myinfomate.be*
Method | HTTP request | Description
------------- | ------------- | -------------

View File

@ -5,7 +5,7 @@
import 'package:manager_api_new/api.dart';
```
All URIs are relative to *http://localhost:5000*
All URIs are relative to *https://api.myinfomate.be*
Method | HTTP request | Description
------------- | ------------- | -------------

View File

@ -5,7 +5,7 @@
import 'package:manager_api_new/api.dart';
```
All URIs are relative to *http://localhost:5000*
All URIs are relative to *https://api.myinfomate.be*
Method | HTTP request | Description
------------- | ------------- | -------------

View File

@ -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;

View File

@ -16,6 +16,8 @@ class PuzzleDTO {
this.messageDebut = const [],
this.messageFin = const [],
this.image,
this.rows,
this.cols,
});
List<TranslationAndResourceDTO>? 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<String, dynamic> toJson() {
final json = <String, dynamic>{};
@ -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<int>(json, r'rows'),
cols: mapValueOfType<int>(json, r'cols'),
);
}
return null;

View File

@ -1388,6 +1388,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.2"
youtube_player_iframe:
dependency: "direct main"
description:
name: youtube_player_iframe
sha256: d7aec9083430db4e5da83a3b5d7b7fcbb93cfa027d9f680ce3c7e7cd20724305
url: "https://pub.dev"
source: hosted
version: "4.0.4"
youtube_player_iframe_web:
dependency: transitive
description:
name: youtube_player_iframe_web
sha256: c7020816031600349b56d2729d4e8be011fcb723ff7dc2dd0cdf72096a0e5ff4
url: "https://pub.dev"
source: hosted
version: "2.0.2"
sdks:
dart: ">=3.2.0-194.0.dev <4.0.0"
flutter: ">=3.13.0"

View File

@ -44,6 +44,7 @@ dependencies:
just_audio: ^0.9.35
pdf: ^3.10.4
multi_select_flutter: ^4.1.3
youtube_player_iframe: ^4.0.4
#msix: ^2.1.3
#window_size:
# git: