update logic from resource in DB to resources in file + others
This commit is contained in:
parent
14ba287872
commit
fb8b564456
@ -21,7 +21,7 @@ class AdminPopup extends StatefulWidget {
|
|||||||
class _AdminPopupState extends State<AdminPopup> {
|
class _AdminPopupState extends State<AdminPopup> {
|
||||||
final TextEditingController _controller = TextEditingController();
|
final TextEditingController _controller = TextEditingController();
|
||||||
bool isPasswordOk = false;
|
bool isPasswordOk = false;
|
||||||
String password = "FORT2023!";
|
String password = "ADMIN2024!"; //FORT2023!
|
||||||
VisitAppContext? visitAppContext;
|
VisitAppContext? visitAppContext;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class BuilderImageSlider extends StatelessWidget {
|
|||||||
//width: size.width * 0.95,
|
//width: size.width * 0.95,
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(15.0),
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
child: Image.memory(base64Decode(i.data!))/*PhotoView(
|
child: Image.memory(base64Decode(i.path!))/*PhotoView(
|
||||||
imageProvider: Image.memory(base64Decode(i!.data!)).image,
|
imageProvider: Image.memory(base64Decode(i!.data!)).image,
|
||||||
minScale: PhotoViewComputedScale.contained * 0.8,
|
minScale: PhotoViewComputedScale.contained * 0.8,
|
||||||
maxScale: PhotoViewComputedScale.contained * 3.0,
|
maxScale: PhotoViewComputedScale.contained * 3.0,
|
||||||
|
|||||||
@ -28,6 +28,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final appContext = Provider.of<AppContext>(context);
|
final appContext = Provider.of<AppContext>(context);
|
||||||
VisitAppContext visitAppContext = appContext.getContext();
|
VisitAppContext visitAppContext = appContext.getContext();
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
//final notchInset = MediaQuery.of(context).padding;
|
//final notchInset = MediaQuery.of(context).padding;
|
||||||
return AppBar(
|
return AppBar(
|
||||||
@ -45,7 +46,17 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
), context: context
|
), context: context
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: HtmlWidget(widget.title, textStyle: TextStyle(color: Colors.white),),
|
child: SizedBox(
|
||||||
|
width: widget.isHomeButton ? size.width * 0.8 : null,
|
||||||
|
child: HtmlWidget(
|
||||||
|
widget.title,
|
||||||
|
textStyle: const TextStyle(color: Colors.white),
|
||||||
|
customStylesBuilder: (element)
|
||||||
|
{
|
||||||
|
return {'text-align': 'center', 'font-family': "Roboto", '-webkit-line-clamp': "2",};
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
leading: widget.isHomeButton ? IconButton(
|
leading: widget.isHomeButton ? IconButton(
|
||||||
@ -73,7 +84,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
},
|
},
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 50,
|
width: 50,
|
||||||
child: visitAppContext.isMaximizeTextSize ? const Icon(Icons.text_fields) : const Icon(Icons.format_size)
|
child: visitAppContext.isMaximizeTextSize ? const Icon(Icons.text_fields, color: Colors.white) : const Icon(Icons.format_size, color: Colors.white)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
@ -97,8 +108,10 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
Color(0xFF7633B8),
|
Color(0xFF7633B8),
|
||||||
Color(0xFF6528B6),
|
Color(0xFF6528B6),
|
||||||
Color(0xFF6025B6)*/
|
Color(0xFF6025B6)*/
|
||||||
|
Color(0xFFf6b3c4),
|
||||||
kMainColor1,
|
kMainColor1,
|
||||||
kMainColor2,
|
kMainColor2,
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
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';
|
||||||
@ -10,7 +11,7 @@ import 'package:mymuseum_visitapp/app_context.dart';
|
|||||||
import 'package:mymuseum_visitapp/constants.dart';
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:photo_view/photo_view.dart';
|
||||||
|
|
||||||
void showImagePopup(ContentDTO contentDTO, ResourceModel resourceModel, AppContext appContext, BuildContext context, Size size) {
|
void showImagePopup(ContentDTO contentDTO, ResourceModel resourceModel, AppContext appContext, BuildContext context, Size size, File? resourceModelFile) {
|
||||||
showDialog(
|
showDialog(
|
||||||
builder: (BuildContext context) => AlertDialog(
|
builder: (BuildContext context) => AlertDialog(
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
@ -33,8 +34,8 @@ void showImagePopup(ContentDTO contentDTO, ResourceModel resourceModel, AppConte
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left:8.0, right: 8.0, bottom: 8.0, top: 8.0),
|
padding: const EdgeInsets.only(left:8.0, right: 8.0, bottom: 8.0, top: 8.0),
|
||||||
child: PhotoView(
|
child: PhotoView(
|
||||||
imageProvider: (appContext.getContext() as VisitAppContext).configuration!.isOffline! ?
|
imageProvider: (appContext.getContext() as VisitAppContext).configuration!.isOffline! && resourceModelFile != null ?
|
||||||
Image.memory(base64Decode(resourceModel.data!)).image :
|
Image.file(resourceModelFile).image : // GET FROM FILE
|
||||||
Image.network(resourceModel.source!).image,
|
Image.network(resourceModel.source!).image,
|
||||||
minScale: PhotoViewComputedScale.contained * 1.0,
|
minScale: PhotoViewComputedScale.contained * 1.0,
|
||||||
maxScale: PhotoViewComputedScale.contained * 3.0,
|
maxScale: PhotoViewComputedScale.contained * 3.0,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:manager_api/api.dart';
|
|||||||
import 'package:mymuseum_visitapp/Components/ShowImagePopup.dart';
|
import 'package:mymuseum_visitapp/Components/ShowImagePopup.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Services/apiService.dart';
|
||||||
import 'package:mymuseum_visitapp/app_context.dart';
|
import 'package:mymuseum_visitapp/app_context.dart';
|
||||||
import 'package:mymuseum_visitapp/constants.dart';
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@ -69,18 +70,25 @@ class _SliderImagesWidget extends State<SliderImagesWidget> {
|
|||||||
return Builder(
|
return Builder(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
//print(widget.imagesDTO[currentIndex-1]);
|
//print(widget.imagesDTO[currentIndex-1]);
|
||||||
|
return FutureBuilder(
|
||||||
|
future: ApiService.getResource(appContext, visitAppContext.configuration!, i!.id!),
|
||||||
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(top: 5.0),
|
padding: const EdgeInsets.only(top: 5.0),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showImagePopup(widget.contentsDTO[currentIndex.value-1]!, i!, appContext, context, size);
|
showImagePopup(widget.contentsDTO[currentIndex.value-1]!, i, appContext, context, size, snapshot.data);
|
||||||
},
|
},
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(15.0),
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
child: visitAppContext.configuration!.isOffline! ?
|
child: visitAppContext.configuration!.isOffline! ?
|
||||||
Image.memory(base64Decode(i!.data!)) :
|
snapshot.data != null ?
|
||||||
|
Image.file(
|
||||||
|
snapshot.data!,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
) : null :
|
||||||
Image.network(
|
Image.network(
|
||||||
i!.source!,
|
i.source!,
|
||||||
loadingBuilder: (BuildContext context, Widget child,
|
loadingBuilder: (BuildContext context, Widget child,
|
||||||
ImageChunkEvent? loadingProgress) {
|
ImageChunkEvent? loadingProgress) {
|
||||||
if (loadingProgress == null) {
|
if (loadingProgress == null) {
|
||||||
@ -109,6 +117,8 @@ class _SliderImagesWidget extends State<SliderImagesWidget> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|||||||
@ -27,6 +27,7 @@ class DatabaseHelper {
|
|||||||
static const columnLabel = 'label';
|
static const columnLabel = 'label';
|
||||||
static const columnId = 'id';
|
static const columnId = 'id';
|
||||||
static const columnInstanceId = 'instanceId';
|
static const columnInstanceId = 'instanceId';
|
||||||
|
static const columnPath = 'path';
|
||||||
static const columnData = 'data';
|
static const columnData = 'data';
|
||||||
static const columnType = 'type';
|
static const columnType = 'type';
|
||||||
static const columnDateCreation = 'dateCreation';
|
static const columnDateCreation = 'dateCreation';
|
||||||
@ -204,7 +205,7 @@ class DatabaseHelper {
|
|||||||
db.execute('''
|
db.execute('''
|
||||||
CREATE TABLE $resourcesTable (
|
CREATE TABLE $resourcesTable (
|
||||||
$columnId TEXT NOT NULL PRIMARY KEY,
|
$columnId TEXT NOT NULL PRIMARY KEY,
|
||||||
$columnData TEXT NOT NULL,
|
$columnPath TEXT NOT NULL,
|
||||||
$columnSource TEXT NOT NULL,
|
$columnSource TEXT NOT NULL,
|
||||||
$columnType INT NOT NULL
|
$columnType INT NOT NULL
|
||||||
)
|
)
|
||||||
@ -406,9 +407,10 @@ class DatabaseHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResourceModel getResourceFromDB(dynamic element) {
|
ResourceModel getResourceFromDB(dynamic element) {
|
||||||
|
// Here retrieve file from path ?
|
||||||
return ResourceModel(
|
return ResourceModel(
|
||||||
id: element["id"],
|
id: element["id"],
|
||||||
data: element["data"],
|
path: element["path"],
|
||||||
source: element["source"],
|
source: element["source"],
|
||||||
type: ResourceType.values[element["type"]]
|
type: ResourceType.values[element["type"]]
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import 'package:manager_api/api.dart';
|
import 'package:manager_api/api.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
import 'package:mymuseum_visitapp/app_context.dart';
|
|
||||||
import 'package:mymuseum_visitapp/translations.dart';
|
import 'package:mymuseum_visitapp/translations.dart';
|
||||||
|
|
||||||
class TranslationHelper {
|
class TranslationHelper {
|
||||||
|
|||||||
@ -3,17 +3,17 @@ import 'package:manager_api/api.dart';
|
|||||||
|
|
||||||
class ResourceModel {
|
class ResourceModel {
|
||||||
String? id = "";
|
String? id = "";
|
||||||
String? data = "";
|
String? path = "";
|
||||||
String? source = "";
|
String? source = "";
|
||||||
String? label = "";
|
String? label = "";
|
||||||
ResourceType? type;
|
ResourceType? type;
|
||||||
|
|
||||||
ResourceModel({this.id, this.data, this.source, this.type});
|
ResourceModel({this.id, this.path, this.source, this.type});
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
return {
|
return {
|
||||||
'id': id,
|
'id': id,
|
||||||
'data': data,
|
'path': path,
|
||||||
'source': source,
|
'source': source,
|
||||||
'type': type?.value
|
'type': type?.value
|
||||||
};
|
};
|
||||||
@ -22,7 +22,7 @@ class ResourceModel {
|
|||||||
factory ResourceModel.fromJson(Map<String, dynamic> json) {
|
factory ResourceModel.fromJson(Map<String, dynamic> json) {
|
||||||
return ResourceModel(
|
return ResourceModel(
|
||||||
id: json['id'] as String,
|
id: json['id'] as String,
|
||||||
data: json['data'] as String,
|
path: json['path'] as String,
|
||||||
source: json['source'] as String,
|
source: json['source'] as String,
|
||||||
type: json['type'] as ResourceType
|
type: json['type'] as ResourceType
|
||||||
);
|
);
|
||||||
@ -30,6 +30,6 @@ class ResourceModel {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'ResourceModel{id: $id, type: $type, source: $source, data: $data, label: $label}';
|
return 'ResourceModel{id: $id, type: $type, source: $source, path: $path, label: $label}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,13 +3,15 @@ import 'package:manager_api/api.dart';
|
|||||||
import 'package:mymuseum_visitapp/Models/articleRead.dart';
|
import 'package:mymuseum_visitapp/Models/articleRead.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/beaconSection.dart';
|
import 'package:mymuseum_visitapp/Models/beaconSection.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
||||||
|
import 'package:mymuseum_visitapp/client.dart';
|
||||||
|
|
||||||
|
class VisitAppContext with ChangeNotifier {
|
||||||
|
Client clientAPI = Client("https://api.myinfomate.be"); // Replace by https://api.mymuseum.be //http://192.168.31.140:8089
|
||||||
|
|
||||||
class VisitAppContext with ChangeNotifier{
|
|
||||||
String? id = "";
|
String? id = "";
|
||||||
String? language = "";
|
String? language = "";
|
||||||
String? instanceId = "63514fd67ed8c735aaa4b8f2"; // 63514fd67ed8c735aaa4b8f2 MyInfoMate test instance -- Fort de Saint-Héribert Mymuseum instance id : 633ee379d9405f32f166f047 // 63514fd67ed8c735aaa4b8f1 Mymuseum test
|
String? instanceId = "63514fd67ed8c735aaa4b8f2"; // 63514fd67ed8c735aaa4b8f2 MyInfoMate test instance -- Fort de Saint-Héribert Mymuseum instance id : 633ee379d9405f32f166f047 // 63514fd67ed8c735aaa4b8f1 Mymuseum test
|
||||||
|
|
||||||
|
|
||||||
List<ConfigurationDTO>? configurations;
|
List<ConfigurationDTO>? configurations;
|
||||||
ConfigurationDTO? configuration;
|
ConfigurationDTO? configuration;
|
||||||
List<String?>? sectionIds; // Use to valid QR code found
|
List<String?>? sectionIds; // Use to valid QR code found
|
||||||
@ -26,6 +28,8 @@ class VisitAppContext with ChangeNotifier{
|
|||||||
bool? isAdmin = false;
|
bool? isAdmin = false;
|
||||||
bool? isAllLanguages = false;
|
bool? isAllLanguages = false;
|
||||||
|
|
||||||
|
String? localPath;
|
||||||
|
|
||||||
VisitAppContext({this.language, this.id, this.configuration, this.isAdmin, this.isAllLanguages, this.instanceId});
|
VisitAppContext({this.language, this.id, this.configuration, this.isAdmin, this.isAllLanguages, this.instanceId});
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -18,6 +19,7 @@ import 'package:mymuseum_visitapp/app_context.dart';
|
|||||||
import 'package:mymuseum_visitapp/client.dart';
|
import 'package:mymuseum_visitapp/client.dart';
|
||||||
import 'package:mymuseum_visitapp/constants.dart';
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
import 'audio_player_floating.dart';
|
import 'audio_player_floating.dart';
|
||||||
|
|
||||||
@ -37,8 +39,8 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
List<ResourceModel?> resourcesModel = <ResourceModel?>[];
|
List<ResourceModel?> resourcesModel = <ResourceModel?>[];
|
||||||
ResourceModel? audioResourceModel;
|
ResourceModel? audioResourceModel;
|
||||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
late Uint8List audiobytes;
|
late File audioFile;
|
||||||
VisitAppContext? visitAppContext;
|
late VisitAppContext visitAppContext;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -48,7 +50,7 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
visitAppContext!.isContentCurrentlyShown = false;
|
visitAppContext.isContentCurrentlyShown = false;
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,12 +65,12 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
key: _scaffoldKey,
|
key: _scaffoldKey,
|
||||||
appBar: CustomAppBar(
|
appBar: CustomAppBar(
|
||||||
title: sectionDTO != null ? TranslationHelper.get(sectionDTO!.title, visitAppContext!) : "",
|
title: sectionDTO != null ? TranslationHelper.get(sectionDTO!.title, visitAppContext) : "",
|
||||||
isHomeButton: false,
|
isHomeButton: false,
|
||||||
isTextSizeButton: true,
|
isTextSizeButton: true,
|
||||||
),
|
),
|
||||||
body: FutureBuilder(
|
body: FutureBuilder(
|
||||||
future: getArticle(appContext, appContext.clientAPI, widget.articleId, false),
|
future: getArticle(appContext, visitAppContext.clientAPI, widget.articleId, false),
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
if(articleDTO != null && sectionDTO != null) {
|
if(articleDTO != null && sectionDTO != null) {
|
||||||
if(size.height > size.width) {
|
if(size.height > size.width) {
|
||||||
@ -89,7 +91,7 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Container(
|
return SizedBox(
|
||||||
height: size.height,
|
height: size.height,
|
||||||
width: size.width,
|
width: size.width,
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -120,11 +122,11 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
floatingActionButton: FutureBuilder(
|
floatingActionButton: FutureBuilder(
|
||||||
future: getArticle(appContext, appContext.clientAPI, widget.articleId, true),
|
future: getArticle(appContext, visitAppContext.clientAPI, widget.articleId, true),
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(right: 0, top: 0), //size.height*0.1
|
padding: EdgeInsets.only(right: 0, top: 0), //size.height*0.1
|
||||||
child: audioResourceModel != null && audioResourceModel!.source != null ? AudioPlayerFloatingContainer(file: null, audioBytes: null, resourceURl: audioResourceModel!.source!, isAuto: articleDTO!.isReadAudioAuto!) : null,
|
child: audioResourceModel != null && audioResourceModel!.source != null ? AudioPlayerFloatingContainer(file: audioFile, resourceURl: "", isAuto: articleDTO!.isReadAudioAuto!) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@ -212,6 +214,10 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
child: HtmlWidget(
|
child: HtmlWidget(
|
||||||
TranslationHelper.get(articleDTO!.content, appContext.getContext()),
|
TranslationHelper.get(articleDTO!.content, appContext.getContext()),
|
||||||
textStyle: TextStyle(fontSize: (appContext.getContext() as VisitAppContext).isMaximizeTextSize ? kArticleContentBiggerSize : kArticleContentSize),
|
textStyle: TextStyle(fontSize: (appContext.getContext() as VisitAppContext).isMaximizeTextSize ? kArticleContentBiggerSize : kArticleContentSize),
|
||||||
|
customStylesBuilder: (element)
|
||||||
|
{
|
||||||
|
return {'font-family': "Roboto"};
|
||||||
|
}
|
||||||
//textAlign: TextAlign.left,
|
//textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -245,7 +251,7 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
child: HtmlWidget(
|
child: HtmlWidget(
|
||||||
TranslationHelper.get(articleDTO!.content, appContext.getContext()),
|
TranslationHelper.get(articleDTO!.content, appContext.getContext()),
|
||||||
//textAlign: TextAlign.left,
|
//textAlign: TextAlign.left,
|
||||||
textStyle: TextStyle(fontSize: (appContext.getContext() as VisitAppContext).isMaximizeTextSize ? kArticleContentBiggerSize : kArticleContentSize)
|
textStyle: TextStyle(fontSize: (appContext.getContext() as VisitAppContext).isMaximizeTextSize ? kArticleContentBiggerSize : kArticleContentSize, fontFamily: "Arial"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -270,9 +276,9 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
try {
|
try {
|
||||||
SectionRead articleRead = SectionRead(id: sectionDTO!.id!, readTime: DateTime.now().millisecondsSinceEpoch);
|
SectionRead articleRead = SectionRead(id: sectionDTO!.id!, readTime: DateTime.now().millisecondsSinceEpoch);
|
||||||
await DatabaseHelper.instance.insert(DatabaseTableType.articleRead, articleRead.toMap());
|
await DatabaseHelper.instance.insert(DatabaseTableType.articleRead, articleRead.toMap());
|
||||||
visitAppContext!.readSections.add(articleRead);
|
visitAppContext.readSections.add(articleRead);
|
||||||
|
|
||||||
appContext.setContext(visitAppContext!);
|
appContext.setContext(visitAppContext);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("DATABASE ERROR ARTICLEREAD");
|
print("DATABASE ERROR ARTICLEREAD");
|
||||||
print(e);
|
print(e);
|
||||||
@ -289,9 +295,9 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
try {
|
try {
|
||||||
SectionRead articleRead = SectionRead(id: sectionDTO!.id!, readTime: DateTime.now().millisecondsSinceEpoch);
|
SectionRead articleRead = SectionRead(id: sectionDTO!.id!, readTime: DateTime.now().millisecondsSinceEpoch);
|
||||||
await DatabaseHelper.instance.insert(DatabaseTableType.articleRead, articleRead.toMap());
|
await DatabaseHelper.instance.insert(DatabaseTableType.articleRead, articleRead.toMap());
|
||||||
visitAppContext!.readSections.add(articleRead);
|
visitAppContext.readSections.add(articleRead);
|
||||||
|
|
||||||
appContext.setContext(visitAppContext!);
|
appContext.setContext(visitAppContext);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("DATABASE ERROR ARTICLEREAD");
|
print("DATABASE ERROR ARTICLEREAD");
|
||||||
print(e);
|
print(e);
|
||||||
@ -311,32 +317,50 @@ class _ArticlePageState extends State<ArticlePage> {
|
|||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
// OFFLINE
|
// OFFLINE
|
||||||
|
|
||||||
List<Map<String, dynamic>> ressourceTest = await DatabaseHelper
|
List<Map<String, dynamic>> ressourceTest = await DatabaseHelper
|
||||||
.instance.queryWithColumnId(
|
.instance.queryWithColumnId(
|
||||||
DatabaseTableType.resources, audioIdArticle.first.value!);
|
DatabaseTableType.resources, audioIdArticle.first.value!);
|
||||||
|
|
||||||
|
if (ressourceTest.isNotEmpty) {
|
||||||
|
audioResourceModel = DatabaseHelper.instance.getResourceFromDB(ressourceTest.first);
|
||||||
|
print(audioResourceModel!.id);
|
||||||
|
if(audioResourceModel!.path != null) {
|
||||||
|
audioFile = File(audioResourceModel!.path!);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("EMPTY resourcesModel - first");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*List<Map<String, dynamic>> ressourceTest = await DatabaseHelper
|
||||||
|
.instance.queryWithColumnId(
|
||||||
|
DatabaseTableType.resources, audioIdArticle.first.value!);
|
||||||
if (ressourceTest.isNotEmpty) {
|
if (ressourceTest.isNotEmpty) {
|
||||||
audioResourceModel = DatabaseHelper.instance.getResourceFromDB(ressourceTest.first);
|
audioResourceModel = DatabaseHelper.instance.getResourceFromDB(ressourceTest.first);
|
||||||
print(audioResourceModel!.id);
|
print(audioResourceModel!.id);
|
||||||
Uint8List base64String = base64Decode(audioResourceModel!.data!);
|
Uint8List base64String = base64Decode(audioResourceModel!.path!); // TODO get from file
|
||||||
audiobytes = base64String;
|
audiobytes = base64String;
|
||||||
} else {
|
} else {
|
||||||
print("EMPTY resourcesModel - first");
|
print("EMPTY resourcesModel - first");
|
||||||
}
|
}*/
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
print("Error in audio loading: " + e.toString());
|
print("Error in audio loading: " + e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// TODO Get file instead.. if exist
|
||||||
|
|
||||||
ResourceDTO? resourceDTO = await client.resourceApi!.resourceGetDetail(audioIdArticle.first.value!);
|
ResourceDTO? resourceDTO = await client.resourceApi!.resourceGetDetail(audioIdArticle.first.value!);
|
||||||
|
if(resourceDTO != null && resourceDTO.url != null) {
|
||||||
// ONLINE
|
// ONLINE
|
||||||
ResourceModel? resourceAudioOnline = await ApiService.downloadAudio(client, audioIdArticle.first.value!);
|
//ResourceModel? resourceAudioOnline = await ApiService.downloadAudio(client, resourceDTO.url!, resourceDTO.id!);
|
||||||
if(resourceAudioOnline != null) {
|
ResourceModel resourceAudioOnline = ResourceModel();
|
||||||
resourceAudioOnline.source = resourceDTO!.url;
|
resourceAudioOnline.source = resourceDTO.url;
|
||||||
audioResourceModel = resourceAudioOnline;
|
audioResourceModel = resourceAudioOnline;
|
||||||
Uint8List base64String = base64Decode(resourceAudioOnline.data!);
|
|
||||||
audiobytes = base64String;
|
/*Uint8List base64String = base64Decode(resourceAudioOnline.path!); // GET FROM FILE
|
||||||
|
audiobytes = base64String;*/
|
||||||
} else {
|
} else {
|
||||||
print("EMPTY resourcesModel online - audio");
|
print("EMPTY resourcesModel online - audio");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,10 +11,9 @@ import 'package:just_audio_cache/just_audio_cache.dart';
|
|||||||
|
|
||||||
|
|
||||||
class AudioPlayerFloatingContainer extends StatefulWidget {
|
class AudioPlayerFloatingContainer extends StatefulWidget {
|
||||||
const AudioPlayerFloatingContainer({Key? key, required this.file, required this.audioBytes, required this.resourceURl, required this.isAuto}) : super(key: key);
|
const AudioPlayerFloatingContainer({Key? key, required this.file, required this.resourceURl, required this.isAuto}) : super(key: key);
|
||||||
|
|
||||||
final File? file;
|
final File? file;
|
||||||
final Uint8List? audioBytes;
|
|
||||||
final String resourceURl;
|
final String resourceURl;
|
||||||
final bool isAuto;
|
final bool isAuto;
|
||||||
|
|
||||||
@ -36,10 +35,6 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
void initState() {
|
void initState() {
|
||||||
//print("IN INITSTATE AUDDDIOOOO");
|
//print("IN INITSTATE AUDDDIOOOO");
|
||||||
Future.delayed(Duration.zero, () async {
|
Future.delayed(Duration.zero, () async {
|
||||||
if(widget.audioBytes != null) {
|
|
||||||
audiobytes = widget.audioBytes!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(widget.file != null) {
|
if(widget.file != null) {
|
||||||
audiobytes = await fileToUint8List(widget.file!);
|
audiobytes = await fileToUint8List(widget.file!);
|
||||||
}
|
}
|
||||||
@ -174,16 +169,16 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
child: isplaying ? Column(
|
child: isplaying ? Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.pause),
|
const Icon(Icons.pause, color: Colors.white),
|
||||||
Text(currentpostlabel),
|
Text(currentpostlabel, style: const TextStyle(color: Colors.white)),
|
||||||
],
|
],
|
||||||
) : audioplayed ? Column(
|
) : audioplayed ? Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.play_arrow),
|
const Icon(Icons.play_arrow, color: Colors.white),
|
||||||
Text(currentpostlabel),
|
Text(currentpostlabel, style: const TextStyle(color: Colors.white)),
|
||||||
],
|
],
|
||||||
): const Icon(Icons.play_arrow),
|
): const Icon(Icons.play_arrow, color: Colors.white),
|
||||||
|
|
||||||
/*Column(
|
/*Column(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -36,6 +36,8 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
List<String?> alreadyDownloaded = [];
|
List<String?> alreadyDownloaded = [];
|
||||||
VisitAppContext? visitAppContext;
|
VisitAppContext? visitAppContext;
|
||||||
|
|
||||||
|
bool isDialogOpen = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
configurations = widget.configurations;
|
configurations = widget.configurations;
|
||||||
@ -130,22 +132,21 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
width: size.width * 0.3,
|
width: size.width * 0.3,
|
||||||
child: FutureBuilder(
|
child: FutureBuilder(
|
||||||
future: ApiService.getResource(
|
future: ApiService.getResource(
|
||||||
appContext, configurations[index].imageId!),
|
appContext, configurations[index], configurations[index].imageId!),
|
||||||
builder:
|
builder:
|
||||||
(context, AsyncSnapshot<dynamic> snapshot) {
|
(context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
if (snapshot.connectionState ==
|
if (snapshot.connectionState ==
|
||||||
ConnectionState.done) {
|
ConnectionState.done) {
|
||||||
return snapshot.data != null
|
return ClipRRect(
|
||||||
? ClipRRect(
|
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.only(
|
||||||
topLeft: Radius.circular(20),
|
topLeft: Radius.circular(20),
|
||||||
bottomLeft: Radius.circular(20)),
|
bottomLeft: Radius.circular(20)),
|
||||||
child: snapshot.data.data != null
|
child: snapshot.data != null
|
||||||
? Image.memory(
|
? Image.file(
|
||||||
base64Decode(
|
snapshot.data!,
|
||||||
snapshot.data.data!),
|
fit: BoxFit.cover,
|
||||||
fit: BoxFit.cover)
|
):
|
||||||
: Image.network(
|
Image.network(
|
||||||
configurations[index]
|
configurations[index]
|
||||||
.imageSource!,
|
.imageSource!,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
@ -174,8 +175,7 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
);
|
||||||
: const Text("");
|
|
||||||
} else if (snapshot.connectionState ==
|
} else if (snapshot.connectionState ==
|
||||||
ConnectionState.none) {
|
ConnectionState.none) {
|
||||||
return Text(TranslationHelper.getFromLocale(
|
return Text(TranslationHelper.getFromLocale(
|
||||||
@ -270,7 +270,7 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
: TranslationHelper.getFromLocale(
|
: TranslationHelper.getFromLocale(
|
||||||
"downloadPromptUpdate",
|
"downloadPromptUpdate",
|
||||||
appContext.getContext()),
|
appContext.getContext()),
|
||||||
style: const TextStyle(color: kMainColor),
|
style: const TextStyle(color: kSecondGrey),
|
||||||
textAlign: TextAlign.center),
|
textAlign: TextAlign.center),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
@ -279,7 +279,7 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
Text(
|
Text(
|
||||||
TranslationHelper.getFromLocale(
|
TranslationHelper.getFromLocale(
|
||||||
"downloadLanguage", appContext.getContext()),
|
"downloadLanguage", appContext.getContext()),
|
||||||
style: const TextStyle(color: kMainColor),
|
style: const TextStyle(color: kSecondGrey),
|
||||||
textAlign: TextAlign.center),
|
textAlign: TextAlign.center),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 25,
|
height: 25,
|
||||||
@ -293,7 +293,7 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
TranslationHelper.getFromLocale(
|
TranslationHelper.getFromLocale(
|
||||||
"close", appContext.getContext()),
|
"close", appContext.getContext()),
|
||||||
style: TextStyle(color: kMainColor)),
|
style: TextStyle(color: kSecondGrey)),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
isCancel = true;
|
isCancel = true;
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
@ -303,7 +303,7 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
TranslationHelper.getFromLocale(
|
TranslationHelper.getFromLocale(
|
||||||
"download", appContext.getContext()),
|
"download", appContext.getContext()),
|
||||||
style: TextStyle(color: kMainColor)),
|
style: TextStyle(color: kSecondGrey)),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
@ -316,7 +316,7 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
if (!isCancel) {
|
if (!isCancel) {
|
||||||
String loadingText = TranslationHelper.getFromLocale(
|
/*String loadingText = TranslationHelper.getFromLocale(
|
||||||
"downloadConfiguration", appContext.getContext());
|
"downloadConfiguration", appContext.getContext());
|
||||||
showDialog(
|
showDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
@ -338,18 +338,40 @@ class _ConfigurationsListState extends State<ConfigurationsList> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});*/
|
||||||
|
|
||||||
var audiosNotWorking = await DownloadConfiguration.download(buildContext, appContext, configuration);
|
// DIALOG HERE
|
||||||
|
if(!isDialogOpen) {
|
||||||
|
isDialogOpen = true;
|
||||||
|
|
||||||
print("C'EST FINI. - nombre d'audios qui ne fonctionnent pas");
|
var result = await showDialog(
|
||||||
print(audiosNotWorking.length);
|
builder: (BuildContext dialogContext) => AlertDialog(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||||
|
),
|
||||||
|
content: Container(
|
||||||
|
width: 400,
|
||||||
|
height: 200,
|
||||||
|
child: DownloadConfigurationWidget(configuration: configuration),
|
||||||
|
),
|
||||||
|
actions: <Widget>[],
|
||||||
|
), context: context
|
||||||
|
);
|
||||||
|
isDialogOpen = false;
|
||||||
|
} else {
|
||||||
|
print("ALREADY OPEN LAAAA");
|
||||||
|
}
|
||||||
|
|
||||||
Navigator.of(context).pop();
|
//var audiosNotWorking = await DownloadConfiguration.download(buildContext, appContext, configuration);
|
||||||
|
|
||||||
|
/*print("C'EST FINI. - nombre d'audios qui ne fonctionnent pas");
|
||||||
|
print(audiosNotWorking.length);*/
|
||||||
|
|
||||||
|
//Navigator.of(context).pop();
|
||||||
|
|
||||||
VisitAppContext visitAppContext = appContext.getContext() as VisitAppContext;
|
VisitAppContext visitAppContext = appContext.getContext() as VisitAppContext;
|
||||||
visitAppContext.audiosNotWorking = [];
|
visitAppContext.audiosNotWorking = [];
|
||||||
visitAppContext.audiosNotWorking = audiosNotWorking;
|
//visitAppContext.audiosNotWorking = audiosNotWorking;
|
||||||
appContext.setContext(visitAppContext);
|
appContext.setContext(visitAppContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
|||||||
|
|
||||||
List<ConfigurationDTO> configurations = [];
|
List<ConfigurationDTO> configurations = [];
|
||||||
List<String?> alreadyDownloaded = [];
|
List<String?> alreadyDownloaded = [];
|
||||||
VisitAppContext? visitAppContext;
|
late VisitAppContext visitAppContext;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -54,7 +54,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
|||||||
width: size.width,
|
width: size.width,
|
||||||
height: size.height,
|
height: size.height,
|
||||||
child: FutureBuilder(
|
child: FutureBuilder(
|
||||||
future: getConfigurationsCall(appContext.clientAPI, appContext),
|
future: getConfigurationsCall(visitAppContext.clientAPI, appContext),
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
configurations = List<ConfigurationDTO>.from(snapshot.data).where((configuration) => configuration.isMobile!).toList();
|
configurations = List<ConfigurationDTO>.from(snapshot.data).where((configuration) => configuration.isMobile!).toList();
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class _QuizzPageState extends State<QuizzPage> {
|
|||||||
ResourceModel? audioResourceModel;
|
ResourceModel? audioResourceModel;
|
||||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
late Uint8List audiobytes;
|
late Uint8List audiobytes;
|
||||||
VisitAppContext? visitAppContext;
|
late VisitAppContext visitAppContext;
|
||||||
|
|
||||||
QuizzDTO? quizzDTO;
|
QuizzDTO? quizzDTO;
|
||||||
List<QuestionSubDTO> _questionsSubDTO = <QuestionSubDTO>[];
|
List<QuestionSubDTO> _questionsSubDTO = <QuestionSubDTO>[];
|
||||||
@ -67,7 +67,7 @@ class _QuizzPageState extends State<QuizzPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
visitAppContext!.isContentCurrentlyShown = false;
|
visitAppContext.isContentCurrentlyShown = false;
|
||||||
currentIndex = 1;
|
currentIndex = 1;
|
||||||
//_controllerCenter!.dispose();
|
//_controllerCenter!.dispose();
|
||||||
if(quizzDTO != null) {
|
if(quizzDTO != null) {
|
||||||
@ -94,7 +94,7 @@ class _QuizzPageState extends State<QuizzPage> {
|
|||||||
body: OrientationBuilder(
|
body: OrientationBuilder(
|
||||||
builder: (context, orientation) {
|
builder: (context, orientation) {
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: getQuizz(appContext, appContext.clientAPI, widget.sectionId), // MAYBE MOVE THAT TO PARENT ..
|
future: getQuizz(appContext, visitAppContext.clientAPI, widget.sectionId), // MAYBE MOVE THAT TO PARENT ..
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
if(quizzDTO != null && sectionDTO != null) {
|
if(quizzDTO != null && sectionDTO != null) {
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
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';
|
||||||
@ -18,6 +19,7 @@ import 'package:mymuseum_visitapp/client.dart';
|
|||||||
import 'package:mymuseum_visitapp/constants.dart';
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:photo_view/photo_view.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
class BeaconArticleFound extends StatefulWidget {
|
class BeaconArticleFound extends StatefulWidget {
|
||||||
const BeaconArticleFound({Key? key, required this.beaconSection}) : super(key: key);
|
const BeaconArticleFound({Key? key, required this.beaconSection}) : super(key: key);
|
||||||
@ -29,7 +31,7 @@ class BeaconArticleFound extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _BeaconArticleFoundState extends State<BeaconArticleFound> {
|
class _BeaconArticleFoundState extends State<BeaconArticleFound> {
|
||||||
VisitAppContext? visitAppContext;
|
late VisitAppContext visitAppContext;
|
||||||
SectionDTO? sectionFound;
|
SectionDTO? sectionFound;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -39,15 +41,15 @@ class _BeaconArticleFoundState extends State<BeaconArticleFound> {
|
|||||||
|
|
||||||
visitAppContext = appContext.getContext();
|
visitAppContext = appContext.getContext();
|
||||||
|
|
||||||
if(widget.beaconSection != null && visitAppContext!.currentSections != null && visitAppContext!.currentSections!.isNotEmpty)
|
if(widget.beaconSection != null && visitAppContext.currentSections != null && visitAppContext.currentSections!.isNotEmpty)
|
||||||
{
|
{
|
||||||
var testSection = visitAppContext!.currentSections!.where((section) => section!.id.toString() == widget.beaconSection!.sectionId.toString()).toList();
|
var testSection = visitAppContext.currentSections!.where((section) => section!.id.toString() == widget.beaconSection!.sectionId.toString()).toList();
|
||||||
sectionFound = testSection.isNotEmpty ? testSection.first : null;
|
sectionFound = testSection.isNotEmpty ? testSection.first : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: getSectionImage(appContext, appContext.clientAPI, sectionFound),
|
future: getSectionImage(appContext, visitAppContext.clientAPI, sectionFound),
|
||||||
builder: (context, AsyncSnapshot<ResourceModel?> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: size.height *0.4,
|
height: size.height *0.4,
|
||||||
width: size.width *0.9,
|
width: size.width *0.9,
|
||||||
@ -56,7 +58,7 @@ class _BeaconArticleFoundState extends State<BeaconArticleFound> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
if(snapshot.data != null && ((visitAppContext!.configuration!.isOffline! && snapshot.data!.data != null) || (visitAppContext!.configuration!.isOffline! && snapshot.data!.source != null)))
|
if(snapshot.data != null && ((visitAppContext.configuration!.isOffline! && snapshot.data!.path != null) || (visitAppContext.configuration!.isOffline! && snapshot.data!.source != null)))
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: size.height * 0.25,
|
height: size.height * 0.25,
|
||||||
width: size.width * 0.75,
|
width: size.width * 0.75,
|
||||||
@ -65,11 +67,12 @@ class _BeaconArticleFoundState extends State<BeaconArticleFound> {
|
|||||||
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
|
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||||
child: visitAppContext!.configuration!.isOffline! ?
|
child: visitAppContext.configuration!.isOffline! ?
|
||||||
Image.memory(
|
snapshot.data != null ?
|
||||||
base64Decode(snapshot.data!.data!),
|
Image.file(
|
||||||
fit: BoxFit.cover
|
snapshot.data!,
|
||||||
) :
|
fit: BoxFit.cover,
|
||||||
|
) : null :
|
||||||
Image.network(
|
Image.network(
|
||||||
snapshot.data!.source!,
|
snapshot.data!.source!,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
@ -120,7 +123,7 @@ class _BeaconArticleFoundState extends State<BeaconArticleFound> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ResourceModel?> getSectionImage(AppContext appContext, Client clientAPI, SectionDTO? sectionFound) async {
|
Future<dynamic> getSectionImage(AppContext appContext, Client clientAPI, SectionDTO? sectionFound) async {
|
||||||
if(sectionFound == null) {
|
if(sectionFound == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -128,7 +131,16 @@ class _BeaconArticleFoundState extends State<BeaconArticleFound> {
|
|||||||
if(isConfigOffline) {
|
if(isConfigOffline) {
|
||||||
List<Map<String, dynamic>> resource = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.resources, sectionFound.imageId!);
|
List<Map<String, dynamic>> resource = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.resources, sectionFound.imageId!);
|
||||||
if(resource.isNotEmpty) {
|
if(resource.isNotEmpty) {
|
||||||
return DatabaseHelper.instance.getResourceFromDB(resource.first);
|
Directory? appDocumentsDirectory = Platform.isIOS ? await getApplicationDocumentsDirectory() : await getDownloadsDirectory();
|
||||||
|
String localPath = appDocumentsDirectory!.path;
|
||||||
|
Directory configurationDirectory = Directory('$localPath/${sectionFound.configurationId}');
|
||||||
|
List<FileSystemEntity> fileList = configurationDirectory.listSync();
|
||||||
|
|
||||||
|
if(fileList.any((fileL) => fileL.uri.pathSegments.last.contains(sectionFound.imageId!))) {
|
||||||
|
File file = File(fileList.firstWhere((fileL) => fileL.uri.pathSegments.last.contains(sectionFound.imageId!)).path);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
print("EMPTY resourcesModel - getSectionImage");
|
print("EMPTY resourcesModel - getSectionImage");
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -163,7 +163,7 @@ class _BodyState extends State<Body> {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// ONLINE
|
// ONLINE
|
||||||
List<SectionDTO>? sectionsDownloaded = await ApiService.getAllSections(appContext.clientAPI, visitAppContext.configuration!.id!);
|
List<SectionDTO>? sectionsDownloaded = await ApiService.getAllSections(visitAppContext.clientAPI, visitAppContext.configuration!.id!);
|
||||||
//print(sectionsDownloaded);
|
//print(sectionsDownloaded);
|
||||||
if(sectionsDownloaded!.isNotEmpty) {
|
if(sectionsDownloaded!.isNotEmpty) {
|
||||||
sections = sectionsDownloaded.where((s) => s.type == SectionType.Article || s.type == SectionType.Quizz).toList(); // TODO Support more than Article and Quizz section type
|
sections = sectionsDownloaded.where((s) => s.type == SectionType.Article || s.type == SectionType.Quizz).toList(); // TODO Support more than Article and Quizz section type
|
||||||
|
|||||||
@ -82,15 +82,15 @@ class SectionCard extends StatelessWidget {
|
|||||||
// image is square but we add extra 20 + 20 padding thats why width is 200
|
// image is square but we add extra 20 + 20 padding thats why width is 200
|
||||||
width: size.width*0.5,
|
width: size.width*0.5,
|
||||||
child: FutureBuilder(
|
child: FutureBuilder(
|
||||||
future: ApiService.getResource(appContext, sectionDTO.imageId!),
|
future: ApiService.getResource(appContext, (appContext.getContext() as VisitAppContext).configuration!, sectionDTO.imageId!),
|
||||||
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
return snapshot.data != null ? ClipRRect(
|
return ClipRRect(
|
||||||
borderRadius: const BorderRadius.only(topRight: Radius.circular(20), bottomRight: Radius.circular(20)),
|
borderRadius: const BorderRadius.only(topRight: Radius.circular(20), bottomRight: Radius.circular(20)),
|
||||||
child: isOffline ?
|
child: isOffline && snapshot.data != null ?
|
||||||
Image.memory(
|
Image.file(
|
||||||
base64Decode(snapshot.data!.data!),
|
snapshot.data!,
|
||||||
fit: BoxFit.cover
|
fit: BoxFit.cover,
|
||||||
) :
|
) :
|
||||||
Image.network(
|
Image.network(
|
||||||
sectionDTO.imageSource!,
|
sectionDTO.imageSource!,
|
||||||
@ -111,7 +111,7 @@ class SectionCard extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
) : const Text("");
|
);
|
||||||
} else if (snapshot.connectionState == ConnectionState.none) {
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
return Text(TranslationHelper.getFromLocale("noData", appContext.getContext()));
|
return Text(TranslationHelper.getFromLocale("noData", appContext.getContext()));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -272,7 +272,7 @@ class _VisitPageState extends State<VisitPage> with WidgetsBindingObserver {
|
|||||||
content: BeaconArticleFound(beaconSection: beaconSection),
|
content: BeaconArticleFound(beaconSection: beaconSection),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(TranslationHelper.getFromLocale("close", visitAppContext), style: TextStyle(color: kMainColor)),
|
child: Text(TranslationHelper.getFromLocale("close", visitAppContext), style: const TextStyle(color: kSecondGrey)),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_isDialogShowing = false; // set it `false` since dialog is closed
|
_isDialogShowing = false; // set it `false` since dialog is closed
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
@ -280,7 +280,7 @@ class _VisitPageState extends State<VisitPage> with WidgetsBindingObserver {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(TranslationHelper.getFromLocale("open", visitAppContext), style: TextStyle(color: kMainColor)),
|
child: Text(TranslationHelper.getFromLocale("open", visitAppContext), style: const TextStyle(color: kSecondGrey)),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_isDialogShowing = false; // set it `false` since dialog is closed
|
_isDialogShowing = false; // set it `false` since dialog is closed
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
@ -364,13 +364,8 @@ class _VisitPageState extends State<VisitPage> with WidgetsBindingObserver {
|
|||||||
alignment: Alignment.bottomRight,
|
alignment: Alignment.bottomRight,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(right: 90, bottom: 1),
|
padding: const EdgeInsets.only(right: 90, bottom: 1),
|
||||||
child: SizedBox(
|
child: InkWell(
|
||||||
height: 75.0,
|
onTap: () async {
|
||||||
width: 65.0,
|
|
||||||
child: FittedBox(
|
|
||||||
child: FloatingActionButton(
|
|
||||||
heroTag: "beacon",
|
|
||||||
onPressed: () async {
|
|
||||||
bool isCancel = false;
|
bool isCancel = false;
|
||||||
|
|
||||||
if(!controller.authorizationStatusOk) {
|
if(!controller.authorizationStatusOk) {
|
||||||
@ -390,10 +385,10 @@ class _VisitPageState extends State<VisitPage> with WidgetsBindingObserver {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.my_location, color: kMainColor),
|
const Icon(Icons.my_location, color: kSecondGrey),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
child: Text(TranslationHelper.getFromLocale("locationWarning", visitAppContext), style: const TextStyle(color: kMainColor), textAlign: TextAlign.center),
|
child: Text(TranslationHelper.getFromLocale("locationWarning", visitAppContext), style: const TextStyle(color: kSecondGrey), textAlign: TextAlign.center),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -401,14 +396,14 @@ class _VisitPageState extends State<VisitPage> with WidgetsBindingObserver {
|
|||||||
),
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(TranslationHelper.getFromLocale("close", visitAppContext), style: TextStyle(color: kMainColor)),
|
child: Text(TranslationHelper.getFromLocale("close", visitAppContext), style: TextStyle(color: kSecondGrey)),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
isCancel = true;
|
isCancel = true;
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text(TranslationHelper.getFromLocale("ok", visitAppContext), style: TextStyle(color: kMainColor)),
|
child: Text(TranslationHelper.getFromLocale("ok", visitAppContext), style: TextStyle(color: kSecondGrey)),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
@ -501,10 +496,14 @@ class _VisitPageState extends State<VisitPage> with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tooltip: 'Beacon',
|
child: Container(
|
||||||
backgroundColor: visitAppContext.isScanningBeacons ? kMainColor1 : Colors.grey,
|
decoration: BoxDecoration(
|
||||||
child: const Icon(Icons.my_location),
|
shape: BoxShape.circle,
|
||||||
|
color: visitAppContext.isScanningBeacons ? kMainColor1 : Colors.grey,
|
||||||
),
|
),
|
||||||
|
height: 75.0,
|
||||||
|
width: 65.0,
|
||||||
|
child: const Icon(Icons.my_location, color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
|||||||
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
import 'package:mymuseum_visitapp/app_context.dart';
|
import 'package:mymuseum_visitapp/app_context.dart';
|
||||||
import 'package:mymuseum_visitapp/client.dart';
|
import 'package:mymuseum_visitapp/client.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
static Future<List<ConfigurationDTO>?> getConfigurations(Client client, VisitAppContext? visitAppContext) async {
|
static Future<List<ConfigurationDTO>?> getConfigurations(Client client, VisitAppContext? visitAppContext) async {
|
||||||
@ -117,7 +118,7 @@ class ApiService {
|
|||||||
await for(dynamic d in response) { _downloadData.addAll(d); }
|
await for(dynamic d in response) { _downloadData.addAll(d); }
|
||||||
//print("AFTER");
|
//print("AFTER");
|
||||||
final base64Str = base64.encode(_downloadData);
|
final base64Str = base64.encode(_downloadData);
|
||||||
ResourceModel resourceModel = ResourceModel(id: contentDTO.resourceId, source: contentDTO.resourceUrl, data: base64Str, type: ResourceType.Image);
|
ResourceModel resourceModel = ResourceModel(id: contentDTO.resourceId, source: contentDTO.resourceUrl, path: base64Str, type: ResourceType.Image);
|
||||||
return resourceModel;
|
return resourceModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +133,7 @@ class ApiService {
|
|||||||
} else {
|
} else {
|
||||||
bool isOnline = await hasNetwork();
|
bool isOnline = await hasNetwork();
|
||||||
if(isOnline) {
|
if(isOnline) {
|
||||||
ResourceModel? resourceModel = await downloadAudio(client, audioId);
|
ResourceModel? resourceModel = await downloadAudio(client, audioId, resourceTest.first[0]);
|
||||||
if(resourceModel != null) {
|
if(resourceModel != null) {
|
||||||
await DatabaseHelper.instance.insert(DatabaseTableType.resources, resourceModel.toMap());
|
await DatabaseHelper.instance.insert(DatabaseTableType.resources, resourceModel.toMap());
|
||||||
}
|
}
|
||||||
@ -148,33 +149,43 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<ResourceModel?> downloadAudio(Client client, String audioId) async {
|
static Future<ResourceModel?> downloadAudio(Client client, String resourceUrl, String audioId) async {
|
||||||
var url = "https://api.myinfomate.be/api/Resource/"+audioId; // TO TEST TODO UPDATE ROUTE
|
//var url = "https://api.myinfomate.be/api/Resource/"+audioId; // TO TEST TODO UPDATE ROUTE
|
||||||
HttpClient client2 = HttpClient();
|
HttpClient client2 = HttpClient();
|
||||||
var _downloadData = <int>[];
|
var _downloadData = <int>[];
|
||||||
final HttpClientRequest request = await client2.getUrl(Uri.parse(url));
|
final HttpClientRequest request = await client2.getUrl(Uri.parse(resourceUrl));
|
||||||
HttpClientResponse response = await request.close();
|
HttpClientResponse response = await request.close();
|
||||||
await for(dynamic d in response) { _downloadData.addAll(d); }
|
await for(dynamic d in response) { _downloadData.addAll(d); }
|
||||||
final base64Str = base64.encode(_downloadData);
|
final base64Str = base64.encode(_downloadData);
|
||||||
ResourceModel resourceModel = ResourceModel(id: audioId, data: base64Str, type: ResourceType.Audio, source: "");
|
ResourceModel resourceModel = ResourceModel(id: audioId, path: base64Str, type: ResourceType.Audio, source: "");
|
||||||
return resourceModel;
|
return resourceModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<ResourceModel?> getResource(AppContext appContext, String imageId) async {
|
static Future<File?> getResource(AppContext appContext, ConfigurationDTO configurationDTO, String imageId) async {
|
||||||
if((appContext.getContext() as VisitAppContext).configuration == null || (appContext.getContext() as VisitAppContext).configuration!.isOffline!)
|
if((appContext.getContext() as VisitAppContext).configuration == null || (appContext.getContext() as VisitAppContext).configuration!.isOffline!)
|
||||||
{
|
{
|
||||||
|
Directory? appDocumentsDirectory = Platform.isIOS ? await getApplicationDocumentsDirectory() : await getDownloadsDirectory();
|
||||||
|
String localPath = appDocumentsDirectory!.path;
|
||||||
|
Directory configurationDirectory = Directory('$localPath/${configurationDTO.id}');
|
||||||
|
List<FileSystemEntity> fileList = configurationDirectory.listSync();
|
||||||
|
|
||||||
|
if(fileList.any((fileL) => fileL.uri.pathSegments.last.contains(imageId))) {
|
||||||
|
File file = File(fileList.firstWhere((fileL) => fileL.uri.pathSegments.last.contains(imageId)).path);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
// OFFLINE
|
// OFFLINE
|
||||||
List<Map<String, dynamic>> resourceTest = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.resources, imageId);
|
/*List<Map<String, dynamic>> resourceTest = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.resources, imageId);
|
||||||
if(resourceTest.isNotEmpty) {
|
if(resourceTest.isNotEmpty) {
|
||||||
return DatabaseHelper.instance.getResourceFromDB(resourceTest.first);
|
return DatabaseHelper.instance.getResourceFromDB(resourceTest.first);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
{
|
|
||||||
// ONLINE
|
// ONLINE
|
||||||
return ResourceModel(); // To mock
|
return null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<ExportConfigurationDTO?> exportConfiguration(Client client, String configurationId, String? language) async {
|
static Future<ExportConfigurationDTO?> exportConfiguration(Client client, String configurationId, String? language) async {
|
||||||
|
|||||||
@ -1,17 +1,329 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:manager_api/api.dart';
|
import 'package:manager_api/api.dart';
|
||||||
import 'package:mymuseum_visitapp/Helpers/DatabaseHelper.dart';
|
import 'package:mymuseum_visitapp/Helpers/DatabaseHelper.dart';
|
||||||
import 'package:mymuseum_visitapp/Helpers/modelsHelper.dart';
|
import 'package:mymuseum_visitapp/Helpers/modelsHelper.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Helpers/translationHelper.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
import 'package:mymuseum_visitapp/Services/apiService.dart';
|
import 'package:mymuseum_visitapp/Services/apiService.dart';
|
||||||
import 'package:mymuseum_visitapp/app_context.dart';
|
import 'package:mymuseum_visitapp/app_context.dart';
|
||||||
import 'package:mymuseum_visitapp/constants.dart';
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
|
||||||
class DownloadConfiguration {
|
class DownloadConfigurationWidget extends StatefulWidget {
|
||||||
|
DownloadConfigurationWidget({Key? key, required this.configuration}) : super(key: key);
|
||||||
|
final ConfigurationDTO configuration;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DownloadConfigurationWidget> createState() => _DownloadConfigurationWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DownloadConfigurationWidgetState extends State<DownloadConfigurationWidget> {
|
||||||
|
ValueNotifier<int> currentResourceIndex = ValueNotifier<int>(0);
|
||||||
|
ValueNotifier<int> currentResourceNbr = ValueNotifier<int>(-1);
|
||||||
|
bool isAlreadyDownloading = false;
|
||||||
|
//OtaEvent? currentEvent;
|
||||||
|
|
||||||
|
Future<bool> download(BuildContext buildContext, VisitAppContext visitAppContext) async {
|
||||||
|
bool isAllLanguages = true;
|
||||||
|
|
||||||
|
if(visitAppContext.isAllLanguages != null) {
|
||||||
|
isAllLanguages = visitAppContext.isAllLanguages!;
|
||||||
|
if(isAllLanguages) {
|
||||||
|
print("Admin here and all download all audios !");
|
||||||
|
/*ScaffoldMessenger.of(buildContext).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text("Tous les audios vont être téléchargés"),
|
||||||
|
backgroundColor: kMainColor),
|
||||||
|
);*/
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isAlreadyDownloading) {
|
||||||
|
isAlreadyDownloading = true;
|
||||||
|
|
||||||
|
// HERE CHECK VERSION APK
|
||||||
|
if(true) {
|
||||||
|
Map<Permission, PermissionStatus> statuses = await [
|
||||||
|
Permission.requestInstallPackages,
|
||||||
|
].request();
|
||||||
|
//tryOtaUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportConfigurationDTO? exportConfigurationDTO;
|
||||||
|
try{
|
||||||
|
// Retrieve all url from resource to download (get all resource from configuration en somme)
|
||||||
|
exportConfigurationDTO = await visitAppContext.clientAPI.configurationApi!.configurationExport(widget.configuration.id!, isAllLanguages ? null : visitAppContext.language); // tabletAppContext.configuration!.id! // 65c5f0ee4c030e63ce16bff5 TODO Remove
|
||||||
|
} catch(e) {
|
||||||
|
print("Erreur lors du téléchargement de la configuration et de ses ressources !");
|
||||||
|
print(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
exportConfigurationDTO.resources!.forEach((element) {
|
||||||
|
print(element.id);
|
||||||
|
print(element.label);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(exportConfigurationDTO.resources != null && exportConfigurationDTO.resources!.isNotEmpty) {
|
||||||
|
Map<Permission, PermissionStatus> statuses = await [
|
||||||
|
Permission.storage,
|
||||||
|
].request();
|
||||||
|
//if(statuses[Permission.storage] == PermissionStatus.granted) {
|
||||||
|
try{
|
||||||
|
try {
|
||||||
|
Directory directory = Directory('${visitAppContext.localPath}');
|
||||||
|
List<FileSystemEntity> allConfigurations = directory.listSync();
|
||||||
|
Directory configurationDirectory = Directory('${visitAppContext.localPath}/${widget.configuration.id}');
|
||||||
|
if(!allConfigurations.any((configurationDirectory) => configurationDirectory.uri.pathSegments.any((element) => element == widget.configuration.id))) {
|
||||||
|
// create directory
|
||||||
|
print("Trying to create directory");
|
||||||
|
configurationDirectory.createSync(recursive: true);
|
||||||
|
print('Répertoire créé avec succès.');
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
print("Listing failed, so try to create directory");
|
||||||
|
Directory configurationDirectory = Directory('${visitAppContext.localPath}/${widget.configuration.id}');
|
||||||
|
|
||||||
|
configurationDirectory.createSync(recursive: true);
|
||||||
|
print('Répertoire créé avec succès.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory configurationDirectory = Directory('${visitAppContext.localPath}/${widget.configuration.id}');
|
||||||
|
List<FileSystemEntity> fileList = configurationDirectory.listSync();
|
||||||
|
|
||||||
|
for (var file in fileList) {
|
||||||
|
print(file.uri.pathSegments.last);
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourcesToDownload = exportConfigurationDTO.resources!.where((resource) => resource.type != ResourceType.ImageUrl && resource.type != ResourceType.VideoUrl && resource.type != ResourceType.JsonUrl && resource.url != null && !fileList.any((fileL) => fileL.uri.pathSegments.last.contains(resource.id!)));
|
||||||
|
|
||||||
|
currentResourceNbr.value = resourcesToDownload.length;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
for (var resource in resourcesToDownload) {
|
||||||
|
String? filePath = await downloadResource(visitAppContext, widget.configuration, resource, visitAppContext.localPath!);
|
||||||
|
|
||||||
|
if (filePath != null)
|
||||||
|
{
|
||||||
|
// Insert in database
|
||||||
|
ResourceModel resourceModel = ResourceModel(id: resource.id, source: resource.url, path: filePath, type: resource.type);
|
||||||
|
try {
|
||||||
|
await DatabaseHelper.instance.insert(DatabaseTableType.resources, resourceModel.toMap());
|
||||||
|
} catch (e) {
|
||||||
|
print("We got an issue inserting image metadata ${resource.id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
currentResourceIndex.value++;
|
||||||
|
} else {
|
||||||
|
print("NOT SUCCESSS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete others that are no more used
|
||||||
|
var resourceToDelete = fileList.where((fileL) =>
|
||||||
|
!exportConfigurationDTO!.resources!.any((resource) =>
|
||||||
|
resource.id != null && fileL.uri.pathSegments.last.contains(resource.id!)));
|
||||||
|
|
||||||
|
for (var resource in resourceToDelete) {
|
||||||
|
print("resource to DELETE");
|
||||||
|
print(resource.path);
|
||||||
|
// resource.deleteSync();
|
||||||
|
// Preserve call to firebase // TODO uncomment if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
await DatabaseHelper.instance.insert(DatabaseTableType.configurations, ModelsHelper.configurationToMap(widget.configuration));
|
||||||
|
|
||||||
|
List<SectionDTO>? sections = exportConfigurationDTO.sections;
|
||||||
|
List<String> usedImageOrAudioIds = [];
|
||||||
|
|
||||||
|
if(sections!.isNotEmpty) {
|
||||||
|
|
||||||
|
List<SectionDTO> sectionsInDB = await DatabaseHelper.instance.queryWithConfigurationId(DatabaseTableType.sections, widget.configuration.id!);
|
||||||
|
List<SectionDTO> sectionsToKeep = sections.where((s) => s.type == SectionType.Article || s.type == SectionType.Quizz).toList(); // TODO handle other type of section (for now, Article and Quizz)
|
||||||
|
|
||||||
|
sectionsToKeep.sort((a,b) => a.order!.compareTo(b.order!));
|
||||||
|
int newOrder = 0;
|
||||||
|
// Update local DB - Sections
|
||||||
|
for(var section in sectionsToKeep) {
|
||||||
|
section.order = newOrder;
|
||||||
|
try {
|
||||||
|
await DatabaseHelper.instance.insert(DatabaseTableType.sections, ModelsHelper.sectionToMap(section));
|
||||||
|
} catch (e) {
|
||||||
|
print("We got an issue inserting section data ${section.id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download section image
|
||||||
|
if(section.imageId != null) {
|
||||||
|
usedImageOrAudioIds.add(section.imageId!);
|
||||||
|
var imageData = exportConfigurationDTO.resources!.where((element) => element.id == section.imageId);
|
||||||
|
if(imageData.isNotEmpty) {
|
||||||
|
// TODO get all resources from API + store it in download directory of the app
|
||||||
|
ResourceModel resourceModel = ResourceModel(id: imageData.first.id, source: section.imageSource, /*data: imageData.first.data,*/ type: imageData.first.type);
|
||||||
|
try {
|
||||||
|
await DatabaseHelper.instance.insert(DatabaseTableType.resources, resourceModel.toMap());
|
||||||
|
} catch (e) {
|
||||||
|
print("We got an issue inserting image data ${imageData.first.id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download all images..
|
||||||
|
ArticleDTO? articleDTO = ArticleDTO.fromJson(jsonDecode(section.data!));
|
||||||
|
|
||||||
|
if(articleDTO != null) {
|
||||||
|
for(var image in articleDTO.contents!) {
|
||||||
|
usedImageOrAudioIds.add(image.resourceId!);
|
||||||
|
/*var imageData = exportConfigurationDTO.resources!.where((element) => element.id == image.resourceId);
|
||||||
|
if(imageData.isNotEmpty) {
|
||||||
|
// TODO get all resources from API + store it in download directory of the app
|
||||||
|
ResourceModel resourceModel = ResourceModel(id: imageData.first.id, source: image.resourceUrl, /*data: imageData.first.data,*/ type: imageData.first.type);
|
||||||
|
try {
|
||||||
|
await DatabaseHelper.instance.insert(DatabaseTableType.resources, resourceModel.toMap());
|
||||||
|
} catch (e) {
|
||||||
|
print("We got an issue inserting image data ${imageData.first.id}");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
var audioIdsArticle = isAllLanguages ? articleDTO.audioIds! : articleDTO.audioIds!.where((audioId) => audioId.language == visitAppContext.language);
|
||||||
|
for(var audioId in audioIdsArticle) {
|
||||||
|
if(audioId.value != null) {
|
||||||
|
usedImageOrAudioIds.add(audioId.value!);
|
||||||
|
//audiosNotWorking = await importAudio(visitAppContext, exportConfigurationDTO, audioId.value!, audiosNotWorking);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newOrder = newOrder + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String?> sectionIdsToRemove = sectionsInDB.map((s) => s.id).where((sectionId) => !sectionsToKeep.map((sk) => sk.id).contains(sectionId)).toList();
|
||||||
|
|
||||||
|
for(var sectionIdToRemove in sectionIdsToRemove) {
|
||||||
|
print("section with id removed");
|
||||||
|
print(sectionIdToRemove);
|
||||||
|
try {
|
||||||
|
await DatabaseHelper.instance.delete(sectionIdToRemove!, DatabaseTableType.sections);
|
||||||
|
} catch (e) {
|
||||||
|
print("We got an issue deleting section id: ${sectionIdToRemove}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO CLEAN AND REMOVE FILES !
|
||||||
|
//cleanLocalResources(usedImageOrAudioIds, widget.configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
print("ERRORRRR");
|
||||||
|
print(e);
|
||||||
|
|
||||||
|
if(statuses[Permission.storage] != PermissionStatus.granted) {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: "PermissionStatus not granted, issue may be linked to that. Please check os version (if less than 13, real issue).",
|
||||||
|
toastLength: Toast.LENGTH_SHORT,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
timeInSecForIosWeb: 1,
|
||||||
|
backgroundColor: Colors.redAccent,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 16.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*} else {
|
||||||
|
print("PermissionStatus.granted NOT GRANTED");
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: "PermissionStatus not granted",
|
||||||
|
toastLength: Toast.LENGTH_SHORT,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
timeInSecForIosWeb: 1,
|
||||||
|
backgroundColor: Colors.redAccent,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 16.0
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
VisitAppContext visitAppContext = appContext.getContext();
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Spacer(),
|
||||||
|
ValueListenableBuilder<int>(
|
||||||
|
valueListenable: currentResourceNbr,
|
||||||
|
builder: (context, valueNbr, _) {
|
||||||
|
return ValueListenableBuilder<int>(
|
||||||
|
valueListenable: currentResourceIndex,
|
||||||
|
builder: (context, valueIndex, _) {
|
||||||
|
return valueNbr != -1 && valueNbr != 0 ? Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
|
child: Text(
|
||||||
|
"${valueIndex.toString()}/${valueNbr.toString()}",
|
||||||
|
style: TextStyle(fontSize: 45, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) : SizedBox(height: 0,width: 0);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
FutureBuilder(future: download(context, visitAppContext), builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
// Loader ou indicateur de chargement pendant la vérification
|
||||||
|
Color primaryColor = kMainColor1;
|
||||||
|
return Center(child: CircularProgressIndicator(color: primaryColor));
|
||||||
|
} else {
|
||||||
|
return ValueListenableBuilder<int>(
|
||||||
|
valueListenable: currentResourceNbr,
|
||||||
|
builder: (context, valueNbr, _) {
|
||||||
|
return ValueListenableBuilder<int>(
|
||||||
|
valueListenable: currentResourceIndex,
|
||||||
|
builder: (context, valueIndex, _) {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
valueIndex == valueNbr && valueNbr != -1 ? valueNbr == 0 ?
|
||||||
|
TranslationHelper.getFromLocale(
|
||||||
|
"upToDate",
|
||||||
|
appContext.getContext()) : TranslationHelper.getFromLocale(
|
||||||
|
"downloadFinish",
|
||||||
|
appContext.getContext()) : TranslationHelper.getFromLocale(
|
||||||
|
"downloadInProgress",
|
||||||
|
appContext.getContext()),
|
||||||
|
style: const TextStyle(fontSize: 20),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Spacer()
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*class DownloadConfiguration {
|
||||||
static Future<List<ResourceModel>> download(BuildContext buildContext, AppContext appContext, ConfigurationDTO configuration) async {
|
static Future<List<ResourceModel>> download(BuildContext buildContext, AppContext appContext, ConfigurationDTO configuration) async {
|
||||||
|
|
||||||
VisitAppContext visitAppContext = (appContext.getContext() as VisitAppContext);
|
VisitAppContext visitAppContext = (appContext.getContext() as VisitAppContext);
|
||||||
@ -35,7 +347,7 @@ class DownloadConfiguration {
|
|||||||
|
|
||||||
ExportConfigurationDTO? exportConfigurationDTO;
|
ExportConfigurationDTO? exportConfigurationDTO;
|
||||||
try{
|
try{
|
||||||
exportConfigurationDTO = await ApiService.exportConfiguration(appContext.clientAPI, configuration.id!, isAllLanguages ? null : visitAppContext.language!);
|
exportConfigurationDTO = await ApiService.exportConfiguration(visitAppContext.clientAPI, configuration.id!, isAllLanguages ? null : visitAppContext.language!);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
print("Erreur lors du téléchargement de la visite");
|
print("Erreur lors du téléchargement de la visite");
|
||||||
print(e);
|
print(e);
|
||||||
@ -144,6 +456,56 @@ class DownloadConfiguration {
|
|||||||
return audiosNotWorking;
|
return audiosNotWorking;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
Future<String?> downloadResource(VisitAppContext visitAppContext, ConfigurationDTO configurationDTO, 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/${configurationDTO.id}/${resourceDTO.id}.$extension');
|
||||||
|
|
||||||
|
// Écriture du contenu téléchargé dans le fichier local
|
||||||
|
await file.writeAsBytes(response.bodyBytes);
|
||||||
|
|
||||||
|
return file.path;
|
||||||
|
} else {
|
||||||
|
print("Échec du téléchargement de la ressource - ${response.statusCode}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Erreur lors du téléchargement de la ressource !");
|
||||||
|
print(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<ResourceModel>> importAudio(VisitAppContext visitAppContext, ExportConfigurationDTO exportConfigurationDTO, String audioId, List<ResourceModel> audiosNotWorking) async {
|
Future<List<ResourceModel>> importAudio(VisitAppContext visitAppContext, ExportConfigurationDTO exportConfigurationDTO, String audioId, List<ResourceModel> audiosNotWorking) async {
|
||||||
var audioData = exportConfigurationDTO.resources!.where((element) => element.id == audioId);
|
var audioData = exportConfigurationDTO.resources!.where((element) => element.id == audioId);
|
||||||
@ -192,3 +554,6 @@ void cleanLocalResources(List<String> usedImageIds, ConfigurationDTO configurati
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,8 +5,7 @@ import 'Models/visitContext.dart';
|
|||||||
|
|
||||||
|
|
||||||
class AppContext with ChangeNotifier {
|
class AppContext with ChangeNotifier {
|
||||||
VisitAppContext _visitContext;
|
VisitAppContext? _visitContext;
|
||||||
Client clientAPI = Client("https://api.myinfomate.be"); // Replace by https://api.mymuseum.be //http://192.168.31.140:8089
|
|
||||||
|
|
||||||
AppContext(this._visitContext);
|
AppContext(this._visitContext);
|
||||||
|
|
||||||
|
|||||||
@ -15,12 +15,16 @@ import 'app_context.dart';
|
|||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
String initialRoute;
|
String initialRoute;
|
||||||
VisitAppContext? localContext = await DatabaseHelper.instance.getData(DatabaseTableType.main);
|
VisitAppContext? localContext = await DatabaseHelper.instance.getData(DatabaseTableType.main);
|
||||||
|
|
||||||
|
Directory? appDocumentsDirectory = Platform.isIOS ? await getApplicationDocumentsDirectory() : await getDownloadsDirectory();
|
||||||
|
String localPath = appDocumentsDirectory!.path;
|
||||||
|
|
||||||
if(localContext != null) {
|
if(localContext != null) {
|
||||||
print("we've got an local db !");
|
print("we've got an local db !");
|
||||||
print(localContext);
|
print(localContext);
|
||||||
@ -38,6 +42,9 @@ void main() async {
|
|||||||
print("NO LOCAL DB !");
|
print("NO LOCAL DB !");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localContext.localPath = localPath;
|
||||||
|
print("Local path $localPath");
|
||||||
|
|
||||||
initialRoute = '/home';
|
initialRoute = '/home';
|
||||||
|
|
||||||
final MyApp myApp = MyApp(
|
final MyApp myApp = MyApp(
|
||||||
@ -104,6 +111,9 @@ class _MyAppState extends State<MyApp> {
|
|||||||
//fontFamily: "Vollkorn",
|
//fontFamily: "Vollkorn",
|
||||||
textTheme: TextTheme(bodyLarge: TextStyle(color: widget.visitAppContext.configuration != null ? widget.visitAppContext.configuration!.primaryColor != null ? Color(int.parse(widget.visitAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)): kMainColor1 : kMainColor1)),
|
textTheme: TextTheme(bodyLarge: TextStyle(color: widget.visitAppContext.configuration != null ? widget.visitAppContext.configuration!.primaryColor != null ? Color(int.parse(widget.visitAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)): kMainColor1 : kMainColor1)),
|
||||||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||||
|
appBarTheme: const AppBarTheme(
|
||||||
|
iconTheme: IconThemeData(color: Colors.white), // Change the color here
|
||||||
|
),
|
||||||
),
|
),
|
||||||
routes: {
|
routes: {
|
||||||
'/home': (context) => const HomePage(),
|
'/home': (context) => const HomePage(),
|
||||||
|
|||||||
@ -22,7 +22,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "Sélectionner la langue de la visite",
|
"downloadLanguage": "Sélectionner la langue de la visite",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"responses": "Réponses",
|
"responses": "Réponses",
|
||||||
"restart": "Recommencer"
|
"restart": "Recommencer",
|
||||||
|
"downloadInProgress": "Téléchargement en cours",
|
||||||
|
"downloadFinish": "Téléchargement terminé",
|
||||||
|
"upToDate": "Tout est à jour"
|
||||||
}),
|
}),
|
||||||
Translation(language: "EN", data: {
|
Translation(language: "EN", data: {
|
||||||
"visitTitle": "List of tours",
|
"visitTitle": "List of tours",
|
||||||
@ -45,7 +48,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "Select the tour language",
|
"downloadLanguage": "Select the tour language",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"responses": "Answers",
|
"responses": "Answers",
|
||||||
"restart": "Restart"
|
"restart": "Restart",
|
||||||
|
"downloadInProgress": "Download in progress",
|
||||||
|
"downloadFinish": "Download complete",
|
||||||
|
"upToDate": "Up to date"
|
||||||
}),
|
}),
|
||||||
Translation(language: "DE", data: {
|
Translation(language: "DE", data: {
|
||||||
"visitTitle": "Liste der Touren",
|
"visitTitle": "Liste der Touren",
|
||||||
@ -68,7 +74,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "Wählen Sie die Sprache des Besuchs aus",
|
"downloadLanguage": "Wählen Sie die Sprache des Besuchs aus",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"responses": "Antworten",
|
"responses": "Antworten",
|
||||||
"restart": "Neu starten"
|
"restart": "Neu starten",
|
||||||
|
"downloadInProgress": "Download läuft",
|
||||||
|
"downloadFinish": "Download abgeschlossen",
|
||||||
|
"upToDate": "Alles ist auf dem neuesten Stand"
|
||||||
}),
|
}),
|
||||||
Translation(language: "NL", data: {
|
Translation(language: "NL", data: {
|
||||||
"visitTitle": "Lijst met rondleidingen",
|
"visitTitle": "Lijst met rondleidingen",
|
||||||
@ -91,7 +100,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "Selecteer de taal van de tour",
|
"downloadLanguage": "Selecteer de taal van de tour",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"responses": "Antwoorden",
|
"responses": "Antwoorden",
|
||||||
"restart": "Herstarten"
|
"restart": "Herstarten",
|
||||||
|
"downloadInProgress": "Download bezig",
|
||||||
|
"downloadFinish": "Download voltooid",
|
||||||
|
"upToDate": "Alles is up-to-date"
|
||||||
}),
|
}),
|
||||||
Translation(language: "IT", data: {
|
Translation(language: "IT", data: {
|
||||||
"visitTitle": "Elenco dei tour",
|
"visitTitle": "Elenco dei tour",
|
||||||
@ -114,7 +126,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "Seleziona la lingua del tour",
|
"downloadLanguage": "Seleziona la lingua del tour",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"responses": "Risposte",
|
"responses": "Risposte",
|
||||||
"restart": "Ricomincia"
|
"restart": "Ricomincia",
|
||||||
|
"downloadInProgress": "Download in corso",
|
||||||
|
"downloadFinish": "Download completato",
|
||||||
|
"upToDate": "Tutto è aggiornato"
|
||||||
}),
|
}),
|
||||||
Translation(language: "ES", data: {
|
Translation(language: "ES", data: {
|
||||||
"visitTitle": "Lista de recorridos",
|
"visitTitle": "Lista de recorridos",
|
||||||
@ -137,7 +152,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "Selecciona el idioma del tour",
|
"downloadLanguage": "Selecciona el idioma del tour",
|
||||||
"ok": "Ok",
|
"ok": "Ok",
|
||||||
"responses": "Respuestas",
|
"responses": "Respuestas",
|
||||||
"restart": "Reanudar"
|
"restart": "Reanudar",
|
||||||
|
"downloadInProgress": "Descarga en curso",
|
||||||
|
"downloadFinish": "Descarga completada",
|
||||||
|
"upToDate": "Todo está al día"
|
||||||
}),
|
}),
|
||||||
Translation(language: "PL", data: {
|
Translation(language: "PL", data: {
|
||||||
"visitTitle": "Lista wycieczek",
|
"visitTitle": "Lista wycieczek",
|
||||||
@ -160,7 +178,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "Wybierz język wycieczki",
|
"downloadLanguage": "Wybierz język wycieczki",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"responses": "Odpowiedzi",
|
"responses": "Odpowiedzi",
|
||||||
"restart": "Uruchom ponownie"
|
"restart": "Uruchom ponownie",
|
||||||
|
"downloadInProgress": "Pobieranie w toku",
|
||||||
|
"downloadFinish": "Pobieranie zakończone",
|
||||||
|
"upToDate": "Wszystko jest aktualne"
|
||||||
}),
|
}),
|
||||||
Translation(language: "CN", data: {
|
Translation(language: "CN", data: {
|
||||||
"visitTitle": "旅游清单",
|
"visitTitle": "旅游清单",
|
||||||
@ -183,7 +204,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "选择游览语言",
|
"downloadLanguage": "选择游览语言",
|
||||||
"ok": "好的",
|
"ok": "好的",
|
||||||
"responses": "答案",
|
"responses": "答案",
|
||||||
"restart": "重新开始"
|
"restart": "重新开始",
|
||||||
|
"downloadInProgress": "下载中",
|
||||||
|
"downloadFinish": "下载完成",
|
||||||
|
"upToDate": "已是最新"
|
||||||
}),
|
}),
|
||||||
Translation(language: "UK", data: {
|
Translation(language: "UK", data: {
|
||||||
"visitTitle": "Список турів",
|
"visitTitle": "Список турів",
|
||||||
@ -206,7 +230,10 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "Виберіть мову туру",
|
"downloadLanguage": "Виберіть мову туру",
|
||||||
"ok": "В порядку",
|
"ok": "В порядку",
|
||||||
"responses": "Відповіді",
|
"responses": "Відповіді",
|
||||||
"restart": "Перезапустіть"
|
"restart": "Перезапустіть",
|
||||||
|
"downloadInProgress": "Завантаження триває",
|
||||||
|
"downloadFinish": "Завантаження завершено",
|
||||||
|
"upToDate": "Все актуально"
|
||||||
}),
|
}),
|
||||||
Translation(language: "AR", data: {
|
Translation(language: "AR", data: {
|
||||||
"visitTitle": "قائمة الجولات",
|
"visitTitle": "قائمة الجولات",
|
||||||
@ -229,6 +256,9 @@ List<Translation> translations = [
|
|||||||
"downloadLanguage": "حدد لغة الجولة",
|
"downloadLanguage": "حدد لغة الجولة",
|
||||||
"ok": "نعم",
|
"ok": "نعم",
|
||||||
"responses": "الإجابات",
|
"responses": "الإجابات",
|
||||||
"restart": "إعادة تشغيل"
|
"restart": "إعادة تشغيل",
|
||||||
|
"downloadInProgress": "جارٍ التنزيل",
|
||||||
|
"downloadFinish": "اكتمل التنزيل",
|
||||||
|
"upToDate": "كل شيء محدث"
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@ -378,6 +378,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.1"
|
version: "0.15.1"
|
||||||
|
fluttertoast:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fluttertoast
|
||||||
|
sha256: "7eae679e596a44fdf761853a706f74979f8dd3cd92cf4e23cae161fda091b847"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.2.6"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -38,6 +38,7 @@ dependencies:
|
|||||||
openapi_generator_annotations: ^5.0.2
|
openapi_generator_annotations: ^5.0.2
|
||||||
sqflite:
|
sqflite:
|
||||||
provider: ^6.1.2
|
provider: ^6.1.2
|
||||||
|
fluttertoast:
|
||||||
#carousel_slider: ^4.2.1
|
#carousel_slider: ^4.2.1
|
||||||
#flutter_svg_provider: ^1.0.3
|
#flutter_svg_provider: ^1.0.3
|
||||||
photo_view: ^0.15.0
|
photo_view: ^0.15.0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user