mirror of
https://bitbucket.org/FransoletThomas/tablet-app.git
synced 2025-12-06 08:31:19 +00:00
wip customCachedResources
This commit is contained in:
parent
7a5342dc24
commit
29e4863493
@ -1,5 +1,8 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="be.musee.de.la.fraise.tablet_app">
|
package="be.musee.de.la.fraise.tablet_app">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<application
|
<application
|
||||||
android:label="MyMuseum"
|
android:label="MyMuseum"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -9,8 +10,9 @@ import 'package:tablet_app/app_context.dart';
|
|||||||
|
|
||||||
|
|
||||||
class AudioPlayerFloatingContainer extends StatefulWidget {
|
class AudioPlayerFloatingContainer extends StatefulWidget {
|
||||||
const AudioPlayerFloatingContainer({Key? key, required this.audioBytes, required this.resourceURl, required this.isAuto}) : super(key: key);
|
const AudioPlayerFloatingContainer({Key? key, required this.file, required this.audioBytes, required this.resourceURl, required this.isAuto}) : super(key: key);
|
||||||
|
|
||||||
|
final File? file;
|
||||||
final Uint8List? audioBytes;
|
final Uint8List? audioBytes;
|
||||||
final String resourceURl;
|
final String resourceURl;
|
||||||
final bool isAuto;
|
final bool isAuto;
|
||||||
@ -21,7 +23,7 @@ class AudioPlayerFloatingContainer extends StatefulWidget {
|
|||||||
|
|
||||||
class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContainer> {
|
class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContainer> {
|
||||||
AudioPlayer player = AudioPlayer();
|
AudioPlayer player = AudioPlayer();
|
||||||
late Uint8List audiobytes;
|
Uint8List? audiobytes = null;
|
||||||
bool isplaying = false;
|
bool isplaying = false;
|
||||||
bool audioplayed = false;
|
bool audioplayed = false;
|
||||||
int currentpos = 0;
|
int currentpos = 0;
|
||||||
@ -37,6 +39,10 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
audiobytes = widget.audioBytes!;
|
audiobytes = widget.audioBytes!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(widget.file != null) {
|
||||||
|
audiobytes = await fileToUint8List(widget.file!);
|
||||||
|
}
|
||||||
|
|
||||||
player.durationStream.listen((Duration? d) { //get the duration of audio
|
player.durationStream.listen((Duration? d) { //get the duration of audio
|
||||||
if(d != null) {
|
if(d != null) {
|
||||||
maxduration = d.inSeconds;
|
maxduration = d.inSeconds;
|
||||||
@ -101,10 +107,17 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
});
|
});
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
await player.dynamicSet(url: widget.resourceURl);
|
if(audiobytes != null) {
|
||||||
|
print("GOT AUDIOBYYYTES - LOCALLY SOSO");
|
||||||
|
await player.setAudioSource(LoadedSource(audiobytes!));
|
||||||
|
} else {
|
||||||
|
print("GET SOUND BY URL");
|
||||||
|
await player.dynamicSet(url: widget.resourceURl);
|
||||||
|
}
|
||||||
|
|
||||||
if(widget.isAuto) {
|
if(widget.isAuto) {
|
||||||
//player.play(BytesSource(audiobytes));
|
//player.play(BytesSource(audiobytes));
|
||||||
//await player.setAudioSource(LoadedSource(audiobytes));
|
//
|
||||||
player.play();
|
player.play();
|
||||||
setState(() {
|
setState(() {
|
||||||
isplaying = true;
|
isplaying = true;
|
||||||
@ -122,6 +135,11 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> fileToUint8List(File file) async {
|
||||||
|
List<int> bytes = await file.readAsBytes();
|
||||||
|
return Uint8List.fromList(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final appContext = Provider.of<AppContext>(context);
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
|||||||
122
lib/Components/cached_custom_resource.dart
Normal file
122
lib/Components/cached_custom_resource.dart
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:manager_api/api.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:provider/provider.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';
|
||||||
|
|
||||||
|
class CachedCustomResource extends StatelessWidget {
|
||||||
|
final ResourceDTO resourceDTO;
|
||||||
|
final bool isAuto;
|
||||||
|
final bool webView;
|
||||||
|
final BoxFit fit;
|
||||||
|
|
||||||
|
CachedCustomResource({
|
||||||
|
required this.resourceDTO,
|
||||||
|
required this.isAuto,
|
||||||
|
required this.webView,
|
||||||
|
this.fit = BoxFit.cover,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
TabletAppContext tabletAppContext = appContext.getContext();
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
Color primaryColor = new Color(int.parse(tabletAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16));
|
||||||
|
|
||||||
|
if(resourceDTO.type == ResourceType.ImageUrl || resourceDTO.type == ResourceType.VideoUrl)
|
||||||
|
{
|
||||||
|
// Image Url or Video Url don't care, just get resource
|
||||||
|
if(resourceDTO.type == ResourceType.ImageUrl) {
|
||||||
|
return CachedNetworkImage(
|
||||||
|
imageUrl: resourceDTO.url!,
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
progressIndicatorBuilder: (context, url, downloadProgress) =>
|
||||||
|
CircularProgressIndicator(value: downloadProgress.progress, color: primaryColor),
|
||||||
|
errorWidget: (context, url, error) => Icon(Icons.error),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if(resourceDTO.url == null) {
|
||||||
|
return Center(child: Text("Error loading video"));
|
||||||
|
} else {
|
||||||
|
return VideoViewerYoutube(videoUrl: resourceDTO.url!, isAuto: isAuto, webView: webView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check if exist on local storage, if no, just show it via url
|
||||||
|
print("Check local storage in cached custom resource");
|
||||||
|
return FutureBuilder<File?>(
|
||||||
|
future: _checkIfLocalResourceExists(tabletAppContext),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
// Loader ou indicateur de chargement pendant la vérification
|
||||||
|
return CircularProgressIndicator();
|
||||||
|
} else if (snapshot.hasError || snapshot.data == null) {
|
||||||
|
// Si la ressource locale n'existe pas ou s'il y a une erreur
|
||||||
|
|
||||||
|
switch(resourceDTO.type) {
|
||||||
|
case ResourceType.Image :
|
||||||
|
return CachedNetworkImage(
|
||||||
|
imageUrl: resourceDTO.url!,
|
||||||
|
fit: fit,
|
||||||
|
placeholder: (context, url) => CircularProgressIndicator(),
|
||||||
|
errorWidget: (context, url, error) => Icon(Icons.error),
|
||||||
|
);
|
||||||
|
case ResourceType.Video :
|
||||||
|
return VideoViewer(file: null, videoUrl: resourceDTO.url!);
|
||||||
|
case ResourceType.Audio :
|
||||||
|
return AudioPlayerFloatingContainer(file: null, audioBytes: null, resourceURl: resourceDTO.url!, isAuto: isAuto);
|
||||||
|
default:
|
||||||
|
return Text("Not supported type");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
switch(resourceDTO.type) {
|
||||||
|
case ResourceType.Image :
|
||||||
|
return Image.file(
|
||||||
|
snapshot.data!,
|
||||||
|
fit: fit,
|
||||||
|
);
|
||||||
|
case ResourceType.Video :
|
||||||
|
return VideoViewer(file: snapshot.data!, videoUrl: resourceDTO.url!);
|
||||||
|
case ResourceType.Audio :
|
||||||
|
return AudioPlayerFloatingContainer(file: snapshot.data!, audioBytes: null, resourceURl: resourceDTO.url!, isAuto: isAuto);
|
||||||
|
default:
|
||||||
|
return Text("Not supported type");
|
||||||
|
}
|
||||||
|
// Utilisation de l'image locale
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<File?> _checkIfLocalResourceExists(TabletAppContext tabletAppContext) async {
|
||||||
|
Directory? appDocumentsDirectory = await getDownloadsDirectory();
|
||||||
|
String localPath = appDocumentsDirectory!.path;
|
||||||
|
Directory configurationDirectory = Directory('$localPath/${tabletAppContext.configuration!.id}');
|
||||||
|
List<FileSystemEntity> fileList = configurationDirectory.listSync();
|
||||||
|
|
||||||
|
if(fileList.any((fileL) => fileL.uri.pathSegments.last.contains(resourceDTO.id!))) {
|
||||||
|
File file = File(fileList.firstWhere((fileL) => fileL.uri.pathSegments.last.contains(resourceDTO.id!)).path);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> get localPath async {
|
||||||
|
Directory? appDocumentsDirectory = await getDownloadsDirectory();
|
||||||
|
return appDocumentsDirectory!.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,10 +11,14 @@ import 'package:tablet_app/Components/video_viewer_youtube.dart';
|
|||||||
import 'package:tablet_app/Models/tabletContext.dart';
|
import 'package:tablet_app/Models/tabletContext.dart';
|
||||||
import 'package:tablet_app/app_context.dart';
|
import 'package:tablet_app/app_context.dart';
|
||||||
|
|
||||||
|
import 'cached_custom_resource.dart';
|
||||||
|
|
||||||
showElementForResource(ResourceDTO resourceDTO, AppContext appContext, bool isAuto, bool webView) {
|
showElementForResource(ResourceDTO resourceDTO, AppContext appContext, bool isAuto, bool webView) {
|
||||||
TabletAppContext tabletAppContext = appContext.getContext();
|
TabletAppContext tabletAppContext = appContext.getContext();
|
||||||
Color primaryColor = new Color(int.parse(tabletAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16));
|
Color primaryColor = new Color(int.parse(tabletAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16));
|
||||||
|
|
||||||
|
return CachedCustomResource(resourceDTO: resourceDTO, isAuto: isAuto, webView: webView);
|
||||||
|
|
||||||
switch(resourceDTO.type) {
|
switch(resourceDTO.type) {
|
||||||
case ResourceType.Image:
|
case ResourceType.Image:
|
||||||
case ResourceType.ImageUrl:
|
case ResourceType.ImageUrl:
|
||||||
@ -45,7 +49,7 @@ showElementForResource(ResourceDTO resourceDTO, AppContext appContext, bool isAu
|
|||||||
},
|
},
|
||||||
);*/
|
);*/
|
||||||
case ResourceType.Audio:
|
case ResourceType.Audio:
|
||||||
return AudioPlayerFloatingContainer(audioBytes: null, resourceURl: resourceDTO.url!, isAuto: isAuto);
|
return AudioPlayerFloatingContainer(file: null, audioBytes: null, resourceURl: resourceDTO.url!, isAuto: isAuto);
|
||||||
/*return FutureBuilder(
|
/*return FutureBuilder(
|
||||||
future: getAudio(resourceDTO.url, appContext),
|
future: getAudio(resourceDTO.url, appContext),
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
@ -76,7 +80,7 @@ showElementForResource(ResourceDTO resourceDTO, AppContext appContext, bool isAu
|
|||||||
if(resourceDTO.url == null) {
|
if(resourceDTO.url == null) {
|
||||||
return Center(child: Text("Error loading video"));
|
return Center(child: Text("Error loading video"));
|
||||||
} else {
|
} else {
|
||||||
return VideoViewer(videoUrl: resourceDTO.url!);
|
return VideoViewer(file: null, videoUrl: resourceDTO.url!);
|
||||||
}
|
}
|
||||||
case ResourceType.VideoUrl:
|
case ResourceType.VideoUrl:
|
||||||
if(resourceDTO.url == null) {
|
if(resourceDTO.url == null) {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cached_video_player/cached_video_player.dart';
|
import 'package:cached_video_player/cached_video_player.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tablet_app/Components/loading_common.dart';
|
import 'package:tablet_app/Components/loading_common.dart';
|
||||||
@ -6,7 +8,8 @@ import '../../constants.dart';
|
|||||||
|
|
||||||
class VideoViewer extends StatefulWidget {
|
class VideoViewer extends StatefulWidget {
|
||||||
final String videoUrl;
|
final String videoUrl;
|
||||||
VideoViewer({required this.videoUrl});
|
final File? file;
|
||||||
|
VideoViewer({required this.videoUrl, required this.file});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_VideoViewer createState() => _VideoViewer();
|
_VideoViewer createState() => _VideoViewer();
|
||||||
@ -18,11 +21,19 @@ class _VideoViewer extends State<VideoViewer> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller = CachedVideoPlayerController.network(widget.videoUrl) // Uri.parse()
|
if(widget.file != null) {
|
||||||
..initialize().then((_) {
|
_controller = CachedVideoPlayerController.file(widget.file!) // Uri.parse()
|
||||||
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
|
..initialize().then((_) {
|
||||||
setState(() {});
|
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
|
||||||
});
|
setState(() {});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
_controller = CachedVideoPlayerController.network(widget.videoUrl) // Uri.parse()
|
||||||
|
..initialize().then((_) {
|
||||||
|
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -17,6 +17,7 @@ class TabletAppContext with ChangeNotifier{
|
|||||||
String? deviceId;
|
String? deviceId;
|
||||||
String? instanceId;
|
String? instanceId;
|
||||||
Size? puzzleSize;
|
Size? puzzleSize;
|
||||||
|
String? localPath;
|
||||||
|
|
||||||
TabletAppContext({this.id, this.deviceId, this.host, this.configuration, this.language, this.instanceId, this.clientAPI});
|
TabletAppContext({this.id, this.deviceId, this.host, this.configuration, this.language, this.instanceId, this.clientAPI});
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import 'package:tablet_app/Screens/Puzzle/puzzle_view.dart';
|
|||||||
import 'package:tablet_app/Screens/Slider/slider_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/Video/video_view.dart';
|
||||||
import 'package:tablet_app/Screens/Web/web_view.dart';
|
import 'package:tablet_app/Screens/Web/web_view.dart';
|
||||||
|
import 'package:tablet_app/Services/downloadService.dart';
|
||||||
import 'package:tablet_app/app_context.dart';
|
import 'package:tablet_app/app_context.dart';
|
||||||
import 'package:tablet_app/constants.dart';
|
import 'package:tablet_app/constants.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
@ -418,7 +419,32 @@ class _MainViewWidget extends State<MainViewWidget> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
)
|
),
|
||||||
|
floatingActionButton: InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
var result = await showDialog(
|
||||||
|
builder: (BuildContext dialogContext) => AlertDialog(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||||
|
),
|
||||||
|
content: Container(
|
||||||
|
width: size.width *0.5,
|
||||||
|
height: size.height *0.5,
|
||||||
|
child: DownloadConfigurationWidget(),
|
||||||
|
),
|
||||||
|
actions: <Widget>[],
|
||||||
|
), context: context
|
||||||
|
);
|
||||||
|
|
||||||
|
print("RESULLLLT");
|
||||||
|
print(result);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 150,
|
||||||
|
height: 150,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:carousel_slider/carousel_slider.dart';
|
import 'package:carousel_slider/carousel_slider.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -6,9 +7,11 @@ import 'package:flutter/gestures.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||||
import 'package:manager_api/api.dart';
|
import 'package:manager_api/api.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tablet_app/Components/show_element_for_resource.dart';
|
import 'package:tablet_app/Components/show_element_for_resource.dart';
|
||||||
import 'package:tablet_app/Components/video_viewer.dart';
|
import 'package:tablet_app/Components/video_viewer.dart';
|
||||||
|
import 'package:tablet_app/Models/tabletContext.dart';
|
||||||
import 'package:tablet_app/app_context.dart';
|
import 'package:tablet_app/app_context.dart';
|
||||||
import 'package:tablet_app/constants.dart';
|
import 'package:tablet_app/constants.dart';
|
||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:photo_view/photo_view.dart';
|
||||||
@ -251,6 +254,29 @@ class _SliderView extends State<SliderView> {
|
|||||||
|
|
||||||
switch(i.resourceType) {
|
switch(i.resourceType) {
|
||||||
case ResourceType.Image:
|
case ResourceType.Image:
|
||||||
|
TabletAppContext tabletAppContext = appContext.getContext();
|
||||||
|
Directory configurationDirectory = Directory('${tabletAppContext.localPath}/${tabletAppContext.configuration!.id}');
|
||||||
|
List<FileSystemEntity> fileList = configurationDirectory.listSync();
|
||||||
|
|
||||||
|
var imageProvider = null;
|
||||||
|
if(fileList.any((fileL) => fileL.uri.pathSegments.last.contains(i.resourceId!))) {
|
||||||
|
File file = File(fileList.firstWhere((fileL) => fileL.uri.pathSegments.last.contains(i.resourceId!)).path);
|
||||||
|
imageProvider = FileImage(file);
|
||||||
|
} else {
|
||||||
|
imageProvider = new CachedNetworkImageProvider(i.resourceUrl!,);
|
||||||
|
}
|
||||||
|
|
||||||
|
widgetToInclude = PhotoView(
|
||||||
|
imageProvider: imageProvider,
|
||||||
|
minScale: PhotoViewComputedScale.contained * 0.8,
|
||||||
|
maxScale: PhotoViewComputedScale.contained * 3.0,
|
||||||
|
backgroundDecoration: BoxDecoration(
|
||||||
|
color: kBackgroundSecondGrey,
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
break;
|
||||||
case ResourceType.ImageUrl:
|
case ResourceType.ImageUrl:
|
||||||
widgetToInclude = PhotoView(
|
widgetToInclude = PhotoView(
|
||||||
imageProvider: CachedNetworkImageProvider(i.resourceUrl!),/*new NetworkImage(
|
imageProvider: CachedNetworkImageProvider(i.resourceUrl!),/*new NetworkImage(
|
||||||
|
|||||||
219
lib/Services/downloadService.dart
Normal file
219
lib/Services/downloadService.dart
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api/api.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tablet_app/Models/tabletContext.dart';
|
||||||
|
import 'package:tablet_app/app_context.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
|
class DownloadConfigurationWidget extends StatefulWidget {
|
||||||
|
DownloadConfigurationWidget();
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DownloadConfigurationWidget> createState() => _DownloadConfigurationWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DownloadConfigurationWidgetState extends State<DownloadConfigurationWidget> {
|
||||||
|
int? nbrResources;
|
||||||
|
ValueNotifier<int> currentResourceIndex = ValueNotifier<int>(0);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> download(BuildContext buildContext, TabletAppContext tabletAppContext) async {
|
||||||
|
bool isAllLanguages = true;
|
||||||
|
|
||||||
|
ExportConfigurationDTO? exportConfigurationDTO;
|
||||||
|
try{
|
||||||
|
print(tabletAppContext.configuration!.id!);
|
||||||
|
print("essai");
|
||||||
|
|
||||||
|
// Retrieve all url from resource to download (get all resource from configuration en somme)
|
||||||
|
exportConfigurationDTO = await tabletAppContext.clientAPI!.configurationApi!.configurationExport(tabletAppContext.configuration!.id!);
|
||||||
|
} catch(e) {
|
||||||
|
print("Erreur lors du téléchargement de la configuration et de ses ressources !");
|
||||||
|
print(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("COUCUO heeere");
|
||||||
|
print(exportConfigurationDTO);
|
||||||
|
print(exportConfigurationDTO.resources!.length);
|
||||||
|
|
||||||
|
exportConfigurationDTO.resources!.forEach((element) {
|
||||||
|
print(element.id);
|
||||||
|
print(element.label);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if(exportConfigurationDTO != null && exportConfigurationDTO.resources != null && exportConfigurationDTO.resources!.isNotEmpty) {
|
||||||
|
nbrResources = exportConfigurationDTO.resources!.where((resource) => resource.type != ResourceType.ImageUrl && resource.type != ResourceType.VideoUrl && resource.url != null).length;
|
||||||
|
|
||||||
|
print("i'm here");
|
||||||
|
print(nbrResources);
|
||||||
|
Directory? appDocumentsDirectory = await getDownloadsDirectory();
|
||||||
|
String localPath = appDocumentsDirectory!.path;
|
||||||
|
|
||||||
|
print(localPath);
|
||||||
|
|
||||||
|
Map<Permission, PermissionStatus> statuses = await [
|
||||||
|
Permission.storage,
|
||||||
|
].request();
|
||||||
|
|
||||||
|
print(statuses[Permission.storage]);
|
||||||
|
print(statuses);
|
||||||
|
|
||||||
|
if(statuses[Permission.storage] == PermissionStatus.granted) {
|
||||||
|
|
||||||
|
try{
|
||||||
|
Directory directory = Directory('$localPath');
|
||||||
|
List<FileSystemEntity> allConfigurations = directory.listSync();
|
||||||
|
|
||||||
|
for (var file in allConfigurations) {
|
||||||
|
print('file.uri.pathSegments');
|
||||||
|
print(file.uri.pathSegments);
|
||||||
|
print('file.uri.pathSegments.last');
|
||||||
|
print(file.uri.pathSegments.last);
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory configurationDirectory = Directory('$localPath/${tabletAppContext.configuration!.id}');
|
||||||
|
|
||||||
|
if(!allConfigurations.any((configurationDirectory) => configurationDirectory.uri.pathSegments.any((element) => element == tabletAppContext.configuration!.id))) {
|
||||||
|
// create directory
|
||||||
|
configurationDirectory.createSync(recursive: true);
|
||||||
|
print('Répertoire créé avec succès.');
|
||||||
|
} else {
|
||||||
|
print('EXISTE D2J0 NIGAUD.');
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FileSystemEntity> fileList = configurationDirectory.listSync();
|
||||||
|
|
||||||
|
print("HERE LIST in directory");
|
||||||
|
|
||||||
|
for (var file in fileList) {
|
||||||
|
print(file.uri.pathSegments.last);
|
||||||
|
}
|
||||||
|
|
||||||
|
// foreach ou on va tout télécharger - avec un joli etape 0 / length - on peut rendre tout lent on s'en fou ça ne ce fait qu'une fois
|
||||||
|
exportConfigurationDTO.resources!.forEach((resource) async {
|
||||||
|
|
||||||
|
if(fileList.any((fileL) => fileL.uri.pathSegments.last.contains(resource.id!))) {
|
||||||
|
print("Already exist TRIPLE NIGAUD!");
|
||||||
|
currentResourceIndex.value++;
|
||||||
|
} else {
|
||||||
|
if(resource.type != ResourceType.ImageUrl && resource.type != ResourceType.VideoUrl && resource.url != null) {
|
||||||
|
bool success = await downloadResource(tabletAppContext, resource, localPath);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
currentResourceIndex.value++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
print("ERRORRRR");
|
||||||
|
print(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Puis après faudra changer tous les appels à une resourceUrl avec un get local de la resource
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
TabletAppContext tabletAppContext = appContext.getContext();
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
FutureBuilder(future: download(context, tabletAppContext), builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
// Loader ou indicateur de chargement pendant la vérification
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
} else {
|
||||||
|
return Text("Mise à jour finie");
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
ValueListenableBuilder<int>(
|
||||||
|
valueListenable: currentResourceIndex,
|
||||||
|
builder: (context, value, _) {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
value.toString()+'/'+nbrResources.toString(),
|
||||||
|
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> downloadResource(TabletAppContext tabletAppContext, ResourceDTO resourceDTO, String localPath) async {
|
||||||
|
try {
|
||||||
|
// Téléchargement de la ressource depuis l'URL
|
||||||
|
http.Response response = await http.get(Uri.parse(resourceDTO.url!));
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
// Vérification de l'en-tête Content-Type
|
||||||
|
String contentType = response.headers["content-type"] ?? "";
|
||||||
|
|
||||||
|
// Déduction de l'extension en fonction du Content-Type
|
||||||
|
String extension = _getExtensionFromContentType(contentType);
|
||||||
|
|
||||||
|
print("LOCAL PATTH");
|
||||||
|
print(localPath);
|
||||||
|
|
||||||
|
File file = File('$localPath/${tabletAppContext.configuration!.id}/${resourceDTO.id}.$extension');
|
||||||
|
|
||||||
|
// Écriture du contenu téléchargé dans le fichier local
|
||||||
|
await file.writeAsBytes(response.bodyBytes);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
print("Échec du téléchargement de la ressource - ${response.statusCode}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Erreur lors du téléchargement de la ressource !");
|
||||||
|
print(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getExtensionFromContentType(String contentType) {
|
||||||
|
Map<String, String> contentTypeToExtension = {
|
||||||
|
"image/jpeg": "jpg",
|
||||||
|
"image/jpg": "jpg",
|
||||||
|
"image/png": "png",
|
||||||
|
"image/gif": "gif",
|
||||||
|
"audio/mp3": "mp3",
|
||||||
|
"video/mp4": "mp4",
|
||||||
|
"video/webm": "webm",
|
||||||
|
"video/avi": "avi",
|
||||||
|
"video/quicktime": "mov",
|
||||||
|
"application/pdf": "pdf",
|
||||||
|
"application/json": "json"
|
||||||
|
};
|
||||||
|
|
||||||
|
return contentTypeToExtension[contentType] ?? "unknown";
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import 'package:firebase_core/firebase_core.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:manager_api/api.dart';
|
import 'package:manager_api/api.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tablet_app/client.dart';
|
import 'package:tablet_app/client.dart';
|
||||||
import 'Helpers/DatabaseHelper.dart';
|
import 'Helpers/DatabaseHelper.dart';
|
||||||
@ -24,6 +25,9 @@ void main() async {
|
|||||||
localContext = await DatabaseHelper.instance.getData();
|
localContext = await DatabaseHelper.instance.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Directory? appDocumentsDirectory = await getDownloadsDirectory();
|
||||||
|
String localPath = appDocumentsDirectory!.path;
|
||||||
|
|
||||||
if(localContext != null && localContext.host != null) {
|
if(localContext != null && localContext.host != null) {
|
||||||
print("we've got an local db !");
|
print("we've got an local db !");
|
||||||
print(localContext);
|
print(localContext);
|
||||||
@ -38,6 +42,8 @@ void main() async {
|
|||||||
DeviceDetailDTO? device = await localContext.clientAPI!.deviceApi!.deviceGetDetail(localContext.deviceId!);
|
DeviceDetailDTO? device = await localContext.clientAPI!.deviceApi!.deviceGetDetail(localContext.deviceId!);
|
||||||
localContext.configuration!.id = device!.configurationId;
|
localContext.configuration!.id = device!.configurationId;
|
||||||
localContext.instanceId = device.instanceId;
|
localContext.instanceId = device.instanceId;
|
||||||
|
localContext.localPath = localPath;
|
||||||
|
|
||||||
if (device.configurationId == null) {
|
if (device.configurationId == null) {
|
||||||
print("device.configurationId == null");
|
print("device.configurationId == null");
|
||||||
localContext.configuration = null;
|
localContext.configuration = null;
|
||||||
@ -46,6 +52,8 @@ void main() async {
|
|||||||
} else {
|
} else {
|
||||||
print("NO LOCAL DB !");
|
print("NO LOCAL DB !");
|
||||||
localContext = TabletAppContext(host: "https://api.myinfomate.be");
|
localContext = TabletAppContext(host: "https://api.myinfomate.be");
|
||||||
|
|
||||||
|
localContext.localPath = localPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(kIsWeb) {
|
if(kIsWeb) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// This is a generated file; do not edit or check into version control.
|
// This is a generated file; do not edit or check into version control.
|
||||||
FLUTTER_ROOT=/Users/thomasfransolet/Documents/flutter
|
FLUTTER_ROOT=C:\PROJ\flutter
|
||||||
FLUTTER_APPLICATION_PATH=/Users/thomasfransolet/Documents/Proj/MyMuseum/tablet_app
|
FLUTTER_APPLICATION_PATH=C:\Users\ThomasFransolet\Documents\Documents\Perso\MuseeDeLaFraise\tablet-app
|
||||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||||
FLUTTER_BUILD_DIR=build
|
FLUTTER_BUILD_DIR=build
|
||||||
FLUTTER_BUILD_NAME=2.0.0
|
FLUTTER_BUILD_NAME=2.0.0
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# This is a generated file; do not edit or check into version control.
|
# This is a generated file; do not edit or check into version control.
|
||||||
export "FLUTTER_ROOT=/Users/thomasfransolet/Documents/flutter"
|
export "FLUTTER_ROOT=C:\PROJ\flutter"
|
||||||
export "FLUTTER_APPLICATION_PATH=/Users/thomasfransolet/Documents/Proj/MyMuseum/tablet_app"
|
export "FLUTTER_APPLICATION_PATH=C:\Users\ThomasFransolet\Documents\Documents\Perso\MuseeDeLaFraise\tablet-app"
|
||||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||||
export "FLUTTER_BUILD_DIR=build"
|
export "FLUTTER_BUILD_DIR=build"
|
||||||
export "FLUTTER_BUILD_NAME=2.0.0"
|
export "FLUTTER_BUILD_NAME=2.0.0"
|
||||||
|
|||||||
@ -152,8 +152,8 @@ class ConfigurationApi {
|
|||||||
/// * [String] id (required):
|
/// * [String] id (required):
|
||||||
///
|
///
|
||||||
/// * [String] language:
|
/// * [String] language:
|
||||||
Future<MultipartFile?> configurationExport(String id, { String? language, }) async {
|
Future<ExportConfigurationDTO> configurationExport(String id,) async {
|
||||||
final response = await configurationExportWithHttpInfo(id, language: language, );
|
final response = await configurationExportWithHttpInfo(id,);
|
||||||
if (response.statusCode >= HttpStatus.badRequest) {
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
}
|
}
|
||||||
@ -161,10 +161,10 @@ class ConfigurationApi {
|
|||||||
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
|
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
|
||||||
// FormatException when trying to decode an empty string.
|
// FormatException when trying to decode an empty string.
|
||||||
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
|
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
|
||||||
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'MultipartFile',) as MultipartFile;
|
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ExportConfigurationDTO',) as ExportConfigurationDTO;
|
||||||
|
|
||||||
}
|
}
|
||||||
return null;
|
return Future<ExportConfigurationDTO>.value(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs an HTTP 'GET /api/Configuration' operation and returns the [Response].
|
/// Performs an HTTP 'GET /api/Configuration' operation and returns the [Response].
|
||||||
|
|||||||
@ -36,7 +36,7 @@ dependencies:
|
|||||||
|
|
||||||
flare_flutter: ^3.0.2
|
flare_flutter: ^3.0.2
|
||||||
provider: ^6.0.5
|
provider: ^6.0.5
|
||||||
http: ^1.1.0
|
http: ^1.2.0
|
||||||
auto_size_text: ^3.0.0
|
auto_size_text: ^3.0.0
|
||||||
fluttertoast:
|
fluttertoast:
|
||||||
device_info: ^2.0.2 # DISCONTINUED
|
device_info: ^2.0.2 # DISCONTINUED
|
||||||
@ -55,6 +55,8 @@ dependencies:
|
|||||||
cached_video_player: ^2.0.4
|
cached_video_player: ^2.0.4
|
||||||
cached_network_image: ^3.3.1
|
cached_network_image: ^3.3.1
|
||||||
just_audio_cache: ^0.1.2
|
just_audio_cache: ^0.1.2
|
||||||
|
path_provider: ^2.1.2
|
||||||
|
permission_handler: ^11.2.0
|
||||||
|
|
||||||
openapi_generator_cli: ^4.13.1
|
openapi_generator_cli: ^4.13.1
|
||||||
openapi_generator: ^4.13.1
|
openapi_generator: ^4.13.1
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||||
#include <firebase_storage/firebase_storage_plugin_c_api.h>
|
#include <firebase_storage/firebase_storage_plugin_c_api.h>
|
||||||
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||||||
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
|
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
|
||||||
FirebaseStoragePluginCApiRegisterWithRegistrar(
|
FirebaseStoragePluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi"));
|
registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi"));
|
||||||
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
firebase_core
|
firebase_core
|
||||||
firebase_storage
|
firebase_storage
|
||||||
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user