diff --git a/lib/db/box_photo.dart b/lib/db/box_visit_photo.dart similarity index 90% rename from lib/db/box_photo.dart rename to lib/db/box_visit_photo.dart index aa1f049..1db3e66 100644 --- a/lib/db/box_photo.dart +++ b/lib/db/box_visit_photo.dart @@ -19,19 +19,19 @@ class VisitPhoto { int photo_privee; int photo_principale; String tags; - int uploaded; + int id_concurrence_lien; VisitPhoto( {this.id = 0, required this.id_visite, required this.id_photo_typologie, required this.image_name, - this.id_photo_mp4 = 0, + this.id_photo_mp4 = -1, this.photo_privee = 0, this.photo_principale = 0, this.tags = '', DateTime? date_photo, - this.uploaded = 0}) + this.id_concurrence_lien = 0}) : date_photo = date_photo ?? DateTime.now(); static String? _photosDir = SharedPrefs().photosDir; @@ -56,7 +56,7 @@ class VisitPhoto { int? photo_privee, int? photo_principale, String? tags, - int? uploaded, + int? id_concurrence_lien, }) { return VisitPhoto( id: id ?? this.id, @@ -68,7 +68,7 @@ class VisitPhoto { photo_privee: photo_privee ?? this.photo_privee, photo_principale: photo_principale ?? this.photo_principale, tags: tags ?? this.tags, - uploaded: uploaded ?? this.uploaded, + id_concurrence_lien: id_concurrence_lien ?? this.id_concurrence_lien, ); } /* diff --git a/lib/main.dart b/lib/main.dart index 0e8b5c9..5988045 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,7 @@ // ignore_for_file: prefer_const_constructors import 'dart:ui'; -import 'dart:developer' as developer; +//import 'dart:developer' as developer; import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; @@ -43,6 +43,9 @@ Future main() async { objectbox = await ObjectBox.create(); + int objectboxAddress = identityHashCode(objectbox); + print(objectboxAddress); + /// Log objectbox.addLog('LOG', 'MOBDR', 'Ouverture application ', 0); diff --git a/lib/model/visite_model.dart b/lib/model/visit_model.dart similarity index 73% rename from lib/model/visite_model.dart rename to lib/model/visit_model.dart index dec3922..d1f567a 100644 --- a/lib/model/visite_model.dart +++ b/lib/model/visit_model.dart @@ -1,9 +1,10 @@ import 'package:intl/intl.dart'; import 'package:mobdr/main.dart'; -class VisiteModel { +class VisitModel { late int id; late int id_distrib; + late int id_etab; late int id_visite; late String name; late int photoCount; @@ -12,9 +13,10 @@ class VisiteModel { late String type_visite; late String langage; - VisiteModel( + VisitModel( {required this.id, required this.id_distrib, + required this.id_etab, required this.id_visite, required this.name, required this.photoCount, @@ -23,14 +25,15 @@ class VisiteModel { required this.type_visite, required this.langage}); - static Future> getTodayVisit() async { + static Future> getTodayVisit() async { // Retrieve all today visits from the database - final visites = await objectbox.getTodayVisit(); + final visits = await objectbox.getTodayVisit(); // Map each retrieved visit to VisiteModel - final visiteModels = visites - .map((visite) => VisiteModel( + final visitModelList = visits + .map((visite) => VisitModel( id_distrib: visite.id_distrib_visite, + id_etab: visite.id_etab, id: visite.id, id_visite: visite.id_visite, name: visite.id_etab.toString() + ' - ' + visite.title, @@ -43,17 +46,18 @@ class VisiteModel { .toList(); // Return the list of VisiteModel - return visiteModels; + return visitModelList; } - static Future> getPreviousVisit() async { + static Future> getPreviousVisit() async { // Retrieve all previsous visits from the database - final visites = await objectbox.getPreviousVisit(); + final visits = await objectbox.getPreviousVisit(); // Map each retrieved visit to VisiteModel - final visiteModels = visites - .map((visite) => VisiteModel( + final visitModelList = visits + .map((visite) => VisitModel( id_distrib: visite.id_distrib_visite, + id_etab: visite.id_etab, id: visite.id, id_visite: visite.id_visite, name: visite.id_etab.toString() + ' - ' + visite.title, @@ -66,17 +70,18 @@ class VisiteModel { .toList(); // Return the list of VisiteModel - return visiteModels; + return visitModelList; } - static Future> getAllVisit() async { + static Future> getAllVisit() async { // Retrieve all visits from the database - final visites = await objectbox.getAllVisit(); + final visits = await objectbox.getAllVisit(); // Map each retrieved visit to VisiteModel - final visiteModels = visites - .map((visite) => VisiteModel( + final visitModelList = visits + .map((visite) => VisitModel( id_distrib: visite.id_distrib_visite, + id_etab: visite.id_etab, id: visite.id, id_visite: visite.id_visite, name: visite.id_etab.toString() + ' - ' + visite.title, @@ -89,6 +94,6 @@ class VisiteModel { .toList(); // Return the list of VisiteModel - return visiteModels; + return visitModelList; } } diff --git a/lib/network/api_provider.dart b/lib/network/api_provider.dart index 323271e..604cfc6 100644 --- a/lib/network/api_provider.dart +++ b/lib/network/api_provider.dart @@ -3,12 +3,18 @@ This is api provider This page is used to get data from API */ -import 'package:mobdr/config/constant.dart'; -import 'package:mobdr/main.dart'; -import 'package:mobdr/service/shared_prefs.dart'; +import 'dart:io'; + import 'package:dio/dio.dart'; import 'dart:convert'; import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as path; +import 'package:http/http.dart' as http; +import 'package:http_parser/http_parser.dart'; + +import 'package:mobdr/config/constant.dart'; +import 'package:mobdr/main.dart'; +import 'package:mobdr/service/shared_prefs.dart'; class ApiProvider { Dio dio = Dio(); @@ -224,7 +230,7 @@ class ApiProvider { ApiConstants.externalEndpoint + ApiConstants.restEndpoint + '/mobDR/visite/calendrier', - {"id_utilisateur": 6, "start": 20230101, "end": 20230501}, + {"id_utilisateur": 6, "start": 20230101, "end": 20230531}, ), getCrud( ApiConstants.baseUrl + @@ -338,6 +344,137 @@ class ApiProvider { } } + Future uploadPhotoServlet(int id_visite, String photoPath) async { + try { + final url = Uri.parse(SERVLET_API); + final file = File(photoPath); + final bytes = await file.readAsBytes(); + + final multipartRequest = http.MultipartRequest('POST', url) + ..fields['id_visite'] = id_visite.toString() + ..files.add(http.MultipartFile.fromBytes( + 'photo', + bytes, + filename: path.basename(photoPath), + contentType: MediaType('image', 'jpeg'), + )); + + final headers = {'Cookie': "pguid=${SharedPrefs().guid};"}; + multipartRequest.headers.addAll(headers); + + final response = await multipartRequest.send(); + final responseString = await response.stream.bytesToString(); + + final jsonResponse = jsonDecode(responseString); + final idPhotoString = jsonResponse[0]['id_photo']; + final idPhoto = int.parse(idPhotoString); + + return idPhoto; + } catch (e) { + print('Error uploading photo: $e'); + return -1; + } + } + + Future updatePhotoTypology( + int id_visite, int id_photo_mp4, int id_photo_typologie) async { + final url = + '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/visite/$id_visite/photo/$id_photo_mp4/tri/typo'; + + final headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json', + 'Cookie': 'pguid=${SharedPrefs().guid};', + }; + + final params = { + 'id_typologie': id_photo_typologie.toString(), + }; + + final response = + await http.put(Uri.parse(url), headers: headers, body: params); + + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } + + Future updatePhotoVisibility(int id_visite, int id_photo_mp4, + int photo_principale, int photo_privee) async { + final url = + '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/visite/$id_visite/photo/$id_photo_mp4/tri/visibilite'; + + final headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json', + 'Cookie': 'pguid=${SharedPrefs().guid};', + }; + + final params = { + 'principale': photo_principale.toString(), + 'privee': photo_privee.toString(), + }; + + final response = + await http.put(Uri.parse(url), headers: headers, body: params); + + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } + + Future updatePhotoTags( + int id_visite, int id_photo_mp4, String tags) async { + final url = + '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/visite/$id_visite/photo/$id_photo_mp4/tri/tags'; + + final headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json', + 'Cookie': 'pguid=${SharedPrefs().guid};', + }; + + final params = {'tags': tags}; + + final response = + await http.put(Uri.parse(url), headers: headers, body: params); + + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } + + Future updatePhotoConpetitor( + int id_visite, int id_photo_mp4, int id_concurrence_lien) async { + final url = + '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/visite/$id_visite/photo/$id_photo_mp4/tri/concurrence'; + + final headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json', + 'Cookie': 'pguid=${SharedPrefs().guid};', + }; + + final params = { + 'id_concurrence_lien': id_concurrence_lien.toString(), + }; + + final response = + await http.put(Uri.parse(url), headers: headers, body: params); + + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } + Future getExample(apiToken) async { Response response; diff --git a/lib/objectbox-model.json b/lib/objectbox-model.json index 27c8f67..4086c7b 100644 --- a/lib/objectbox-model.json +++ b/lib/objectbox-model.json @@ -224,7 +224,7 @@ }, { "id": "13:6298506278273268036", - "lastPropertyId": "10:427077651567855068", + "lastPropertyId": "11:7594245284938827569", "name": "VisitPhoto", "properties": [ { @@ -274,8 +274,8 @@ "type": 9 }, { - "id": "10:427077651567855068", - "name": "uploaded", + "id": "11:7594245284938827569", + "name": "id_concurrence_lien", "type": 6 } ], @@ -462,7 +462,8 @@ 2059771745036116529, 102253757473665009, 1526411175344533047, - 1603887098520719919 + 1603887098520719919, + 427077651567855068 ], "retiredRelationUids": [], "version": 1 diff --git a/lib/objectbox.dart b/lib/objectbox.dart index 37e9c14..dc79fcb 100644 --- a/lib/objectbox.dart +++ b/lib/objectbox.dart @@ -4,7 +4,7 @@ import 'package:mobdr/db/box_etab.dart'; import 'package:mobdr/db/box_photo_competitor.dart'; import 'package:mobdr/db/box_visit.dart'; import 'package:mobdr/db/box_visit_tag.dart'; -import 'package:mobdr/db/box_photo.dart'; +import 'package:mobdr/db/box_visit_photo.dart'; import 'package:mobdr/db/box_photo_typology.dart'; import 'model.dart'; @@ -236,9 +236,9 @@ class ObjectBox { store.box().put(_Competitor); } - List getEtabCompetitorList() { + List getEtabCompetitorList(int _id_etab) { final query = etabCompetitorBox - .query(EtabCompetitor_.id_etab.equals(1417)) + .query(EtabCompetitor_.id_etab.equals(_id_etab)) .order(EtabCompetitor_.nom) .build(); final photoCompetitors = query.find(); @@ -493,6 +493,31 @@ class ObjectBox { return query.find(); } + // Retrieves a VisitPhoto object from the ObjectBox database with the specified visit ID. + /// + /// Parameters: + /// _id_visite: The ID of the visit the photo belongs to. + /// + /// Returns: + /// A VisitPhoto object, or null if no object is found. + List getAllVisitPhotosByVisit(int id_visite) { + final query = + visitPhotoBox.query(VisitPhoto_.id_visite.equals(id_visite)).build(); + return query.find(); + } + + /// Retrieves all VisitPhoto objects from the ObjectBox database. + /// + /// Parameters: + /// None. + /// + /// Returns: + /// A list of VisitPhoto objects, or an empty list if no objects are found. + List getAllVisitPhotos() { + final query = visitPhotoBox.query().build(); + return query.find(); + } + /// Retrieves a Photo object from the ObjectBox database with the specified ID. /// /// Parameters: @@ -500,8 +525,8 @@ class ObjectBox { /// /// Returns: /// A Photo object, or null if no object is found. - VisitPhoto? getPhotoById(int id_photo) { - final photo = visitPhotoBox.get(id_photo); + VisitPhoto? getPhotoById(int _id) { + final photo = visitPhotoBox.get(_id); return photo; } @@ -519,7 +544,28 @@ class ObjectBox { .map((query) => query.find()); } - void delPhoto(String _name) { + /// Removes a VisitPhoto object from the ObjectBox database with the specified ID. + /// + /// Parameters: + /// id: The ID of the VisitPhoto object to remove. + /// + /// Returns: + /// None. + void delPhotoById(int id) { + if (visitPhotoBox.remove(id)) { + print("Supression photo :${id}"); + } else + print("Supression photo :${id} KO"); + } + + /// Removes a VisitPhoto object from the ObjectBox database with the specified ID. + /// + /// Parameters: + /// id: The NAME of the VisitPhoto object to remove. + /// + /// Returns: + /// None. + void delPhotoByName(String _name) { final query = visitPhotoBox.query(VisitPhoto_.image_name.equals(_name)).build(); final results = query.find(); @@ -543,6 +589,15 @@ class ObjectBox { return builder.count(); } + void putPhotoIdMP4(int photoId, int id_photo_mp4) { + final photo = visitPhotoBox.get(photoId); + + if (photo != null) { + final updatedPhoto = photo.copyWith(id_photo_mp4: id_photo_mp4); + visitPhotoBox.put(updatedPhoto); + } + } + Future putPhotoTypologie(int photoId, int typologieId) async { final photo = visitPhotoBox.get(photoId); @@ -573,6 +628,15 @@ class ObjectBox { } } + Future putPhotoCompetitor(int photoId, int competitorId) async { + final photo = visitPhotoBox.get(photoId); + + if (photo != null) { + final updatedPhoto = photo.copyWith(id_concurrence_lien: competitorId); + await visitPhotoBox.putAsync(updatedPhoto); + } + } + /* remettre les principal à zero final queryBuilder = box.query(VisitPhoto_.Visit_id.equals(idVisite) & VisitPhoto_.photo_principale.equals(1)); final updatedPhotos = queryBuilder.build().find(); diff --git a/lib/objectbox.g.dart b/lib/objectbox.g.dart index e6cd06f..19c1604 100644 --- a/lib/objectbox.g.dart +++ b/lib/objectbox.g.dart @@ -16,11 +16,11 @@ import 'package:objectbox_flutter_libs/objectbox_flutter_libs.dart'; import 'db/box_etab.dart'; import 'db/box_log.dart'; -import 'db/box_photo.dart'; import 'db/box_photo_competitor.dart'; import 'db/box_photo_typology.dart'; import 'db/box_user.dart'; import 'db/box_visit.dart'; +import 'db/box_visit_photo.dart'; import 'db/box_visit_tag.dart'; import 'model.dart'; @@ -249,7 +249,7 @@ final _entities = [ ModelEntity( id: const IdUid(13, 6298506278273268036), name: 'VisitPhoto', - lastPropertyId: const IdUid(10, 427077651567855068), + lastPropertyId: const IdUid(11, 7594245284938827569), flags: 0, properties: [ ModelProperty( @@ -298,8 +298,8 @@ final _entities = [ type: 9, flags: 0), ModelProperty( - id: const IdUid(10, 427077651567855068), - name: 'uploaded', + id: const IdUid(11, 7594245284938827569), + name: 'id_concurrence_lien', type: 6, flags: 0) ], @@ -503,7 +503,8 @@ ModelDefinition getObjectBoxModel() { 2059771745036116529, 102253757473665009, 1526411175344533047, - 1603887098520719919 + 1603887098520719919, + 427077651567855068 ], retiredRelationUids: const [], modelVersion: 5, @@ -760,7 +761,7 @@ ModelDefinition getObjectBoxModel() { objectToFB: (VisitPhoto object, fb.Builder fbb) { final image_nameOffset = fbb.writeString(object.image_name); final tagsOffset = fbb.writeString(object.tags); - fbb.startTable(11); + fbb.startTable(12); fbb.addInt64(0, object.id); fbb.addInt64(1, object.id_visite); fbb.addInt64(2, object.id_photo_typologie); @@ -770,7 +771,7 @@ ModelDefinition getObjectBoxModel() { fbb.addInt64(6, object.photo_privee); fbb.addInt64(7, object.photo_principale); fbb.addOffset(8, tagsOffset); - fbb.addInt64(9, object.uploaded); + fbb.addInt64(10, object.id_concurrence_lien); fbb.finish(fbb.endTable()); return object.id; }, @@ -796,8 +797,8 @@ ModelDefinition getObjectBoxModel() { .vTableGet(buffer, rootOffset, 20, ''), date_photo: DateTime.fromMillisecondsSinceEpoch( const fb.Int64Reader().vTableGet(buffer, rootOffset, 12, 0)), - uploaded: - const fb.Int64Reader().vTableGet(buffer, rootOffset, 22, 0)); + id_concurrence_lien: + const fb.Int64Reader().vTableGet(buffer, rootOffset, 24, 0)); return object; }), @@ -1077,8 +1078,8 @@ class VisitPhoto_ { static final tags = QueryStringProperty(_entities[6].properties[8]); - /// see [VisitPhoto.uploaded] - static final uploaded = + /// see [VisitPhoto.id_concurrence_lien] + static final id_concurrence_lien = QueryIntegerProperty(_entities[6].properties[9]); } diff --git a/lib/service/shared_prefs.dart b/lib/service/shared_prefs.dart index 0686898..ba5e86a 100644 --- a/lib/service/shared_prefs.dart +++ b/lib/service/shared_prefs.dart @@ -130,4 +130,11 @@ class SharedPrefs { set urlMP4(String value) { _sharedPrefs.setString('urlMP4', value); } + + /// get/set onboarding visualizaton + int get onboarding => _sharedPrefs.getInt('key_onboarding') ?? 0; + + set onboarding(int value) { + _sharedPrefs.setInt('key_onboarding', value); + } } diff --git a/lib/ui/home.dart b/lib/ui/home.dart index 15a87f2..7d1704f 100644 --- a/lib/ui/home.dart +++ b/lib/ui/home.dart @@ -50,7 +50,11 @@ class _HomePageState extends State } void _handleTabSelection() { - setState(() {}); + // TODO a voir si on laisse setState ?? + /* + setState(() { + }); + */ } @override diff --git a/lib/ui/home/tab_home.dart b/lib/ui/home/tab_home.dart index ab49690..ac3356a 100644 --- a/lib/ui/home/tab_home.dart +++ b/lib/ui/home/tab_home.dart @@ -18,7 +18,7 @@ import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/events.dart'; import 'package:mobdr/ui/sync/sync_calendar.dart'; -import 'package:mobdr/model/visite_model.dart'; +import 'package:mobdr/model/visit_model.dart'; import 'package:mobdr/ui/visit/visit_photo_typology.dart'; import 'package:mobdr/ui/general/chat_us.dart'; import 'package:mobdr/ui/general/notification.dart'; @@ -48,8 +48,8 @@ class _TabHomePageState extends State bool _isLoading = true; String _errorMessage = ''; - late List todayVisitData = []; - late List previousVisitData = []; + late List todayVisitData = []; + late List previousVisitData = []; @override void initState() { @@ -251,12 +251,7 @@ class _TabHomePageState extends State behavior: HitTestBehavior.translucent, onTap: () { Route route = MaterialPageRoute( - builder: (context) => VisitPhotoTypologyPage( - pp_id_distrib: data.id_distrib, - pp_langage: data.langage, - pp_id_visite: data.id_visite, - pp_name: data.name, - ), + builder: (context) => VisitPhotoTypologyPage(pp_visitModel: data), ); Navigator.push(context, route); }, @@ -336,8 +331,8 @@ class _TabHomePageState extends State Future loadData() async { try { // visite model initialisation - todayVisitData = await VisiteModel.getTodayVisit(); - previousVisitData = await VisiteModel.getPreviousVisit(); + todayVisitData = await VisitModel.getTodayVisit(); + previousVisitData = await VisitModel.getPreviousVisit(); } catch (e) { // set errorMessage for debug _errorMessage = 'Error loading visites : $e'; diff --git a/lib/ui/onboarding.dart b/lib/ui/onboarding.dart index b75a08b..43df155 100644 --- a/lib/ui/onboarding.dart +++ b/lib/ui/onboarding.dart @@ -1,5 +1,6 @@ -import 'package:mobdr/ui/authentication/signin.dart'; import 'package:flutter/material.dart'; + +import 'package:mobdr/ui/authentication/signin.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/library/flutter_overboard/overboard.dart'; import 'package:mobdr/library/flutter_overboard/page_model.dart'; diff --git a/lib/ui/splash_screen.dart b/lib/ui/splash_screen.dart index 76191bd..5044274 100644 --- a/lib/ui/splash_screen.dart +++ b/lib/ui/splash_screen.dart @@ -1,10 +1,13 @@ import 'dart:async'; -import 'package:mobdr/config/constant.dart'; -import 'package:mobdr/ui/onboarding.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:mobdr/service/shared_prefs.dart'; +import 'package:mobdr/config/constant.dart'; +import 'package:mobdr/ui/onboarding.dart'; +import 'package:mobdr/ui/authentication/signin.dart'; + class SplashScreenPage extends StatefulWidget { @override _SplashScreenPageState createState() => _SplashScreenPageState(); @@ -12,7 +15,7 @@ class SplashScreenPage extends StatefulWidget { class _SplashScreenPageState extends State { Timer? _timer; - int _second = 3; // set timer for 3 second and then direct to next page + int _second = 2; // set timer for 3 second and then direct to next page void _startTimer() { const period = const Duration(seconds: 1); @@ -22,10 +25,18 @@ class _SplashScreenPageState extends State { }); if (_second == 0) { _cancelFlashsaleTimer(); - // for this example we will use pushReplacement because we want to go back to the list - Navigator.pushReplacement( - context, MaterialPageRoute(builder: (context) => OnBoardingPage())); + if (SharedPrefs().onboarding == 0) { + SharedPrefs().onboarding = 1; + + // for this example we will use pushReplacement because we want to go back to the list + Navigator.pushReplacement(context, + MaterialPageRoute(builder: (context) => OnBoardingPage())); + } else { + // for this example we will use pushReplacement because we want to go back to the list + Navigator.pushReplacement( + context, MaterialPageRoute(builder: (context) => SigninPage())); + } // if you use this splash screen on the very first time when you open the page, use below code //Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) => OnBoardingPage()), (Route route) => false); } diff --git a/lib/ui/sync/upload_photos.dart b/lib/ui/sync/upload_photos.dart index 3983ea8..b84ef8d 100644 --- a/lib/ui/sync/upload_photos.dart +++ b/lib/ui/sync/upload_photos.dart @@ -1,19 +1,16 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:path/path.dart' as path; -import 'package:http/http.dart' as http; -import 'package:http_parser/http_parser.dart'; -import 'package:mobdr/service/shared_prefs.dart'; -import 'package:mobdr/config/constant.dart'; +import 'package:mobdr/main.dart'; +import 'package:mobdr/events.dart'; +import 'package:mobdr/db/box_visit_photo.dart'; +import 'package:mobdr/network/api_provider.dart'; class UploadPhotosPage extends StatefulWidget { - final int id_visite; - final List photoPaths; + final int pp_id_visite; - UploadPhotosPage({required this.id_visite, required this.photoPaths}); + UploadPhotosPage({required this.pp_id_visite}); @override _UploadPhotosPageState createState() => _UploadPhotosPageState(); @@ -25,29 +22,110 @@ class _UploadPhotosPageState extends State { int _totalUploaded = 0; int _totalPhotos = 0; + late List _photosList; + + ApiProvider _apiProvider = ApiProvider(); + @override void initState() { super.initState(); - _totalPhotos = widget.photoPaths.length; + // "visit" mode + if (widget.pp_id_visite > 0) { + _photosList = objectbox.getAllVisitPhotosByVisit(widget.pp_id_visite); + _totalPhotos = _photosList.length; + // "all" mode + } else { + _photosList = objectbox.getAllVisitPhotos(); + _totalPhotos = _photosList.length; + } } - Future _uploadPhotos() async { + void _uploadPhotos() async { setState(() { _isUploading = true; _isFinished = false; }); - for (int i = 0; i < widget.photoPaths.length; i++) { - String photoPath = SharedPrefs().photosDir + "/" + widget.photoPaths[i]; - //String filename = path.basename(photoPath); + // parse all photos + for (var photo in _photosList) { + int id_photo_mp4 = -1; + bool isUpdatePhotoTypologie = true; + bool isUpdatePhotoVisibility = true; + bool isUpdatePhotoCompetitor = true; + bool isUpdatePhotoTags = true; - // Upload the photo - int photoId = await uploadPhoto(photoPath); + // if photo not already uploaded + if (photo.id_photo_mp4 <= 0) { + // try upload the photo + id_photo_mp4 = await _apiProvider.uploadPhotoServlet( + photo.id_visite, photo.getImage()); + } else + id_photo_mp4 = photo.id_photo_mp4; - if (photoId != -1) { - _totalUploaded++; + // the photo is saved in MP4 + if (id_photo_mp4 > 0) { + // update photo typology + isUpdatePhotoTypologie = await _apiProvider.updatePhotoTypology( + photo.id_visite, id_photo_mp4, photo.id_photo_typologie); + + // update photo visibility + if (photo.photo_principale == 1 || photo.photo_privee == 1) { + isUpdatePhotoVisibility = await _apiProvider.updatePhotoVisibility( + photo.id_visite, + id_photo_mp4, + photo.photo_principale, + photo.photo_privee); + } + + // update photo tags + if (photo.tags.isNotEmpty) { + isUpdatePhotoTags = await _apiProvider.updatePhotoTags( + photo.id_visite, id_photo_mp4, photo.tags); + } + + // update photo competitor + if (photo.id_concurrence_lien > 0) { + isUpdatePhotoCompetitor = await _apiProvider.updatePhotoConpetitor( + photo.id_visite, id_photo_mp4, photo.id_concurrence_lien); + } } + + if (id_photo_mp4 > 0 && + isUpdatePhotoTypologie == true && + isUpdatePhotoVisibility == true && + isUpdatePhotoTags == true && + isUpdatePhotoCompetitor == true) { + // delete photo in database + objectbox.delPhotoById(photo.id); + + // delete the file + File file = File(photo.getImage()); + if (await file.exists()) { + await file.delete(); + } + + _totalUploaded++; + } else { + // if successful upload + if (id_photo_mp4 != -1) { + photo.id_photo_mp4 = id_photo_mp4; + + // save MP4 id in database + objectbox.putPhotoIdMP4(photo.id, id_photo_mp4); + } + } + + //await Future.delayed(Duration(seconds: 5)); + } + + // Get unique id_visite values from _photosList + Set uniqueIds = _photosList.map((photo) => photo.id_visite).toSet(); + + // Send VisitPhotoCountEvent for each unique id_visite + for (int id_visite in uniqueIds) { + eventBus.fire(VisitPhotoCountEvent( + id_visite, objectbox.getVisitPhotoCount(id_visite))); } setState(() { @@ -56,38 +134,6 @@ class _UploadPhotosPageState extends State { }); } - Future uploadPhoto(String photoPath) async { - try { - final url = Uri.parse(SERVLET_API); - final file = File(photoPath); - final bytes = await file.readAsBytes(); - - final multipartRequest = http.MultipartRequest('POST', url) - ..fields['id_visite'] = widget.id_visite.toString() - ..files.add(http.MultipartFile.fromBytes( - 'photo', - bytes, - filename: path.basename(photoPath), - contentType: MediaType('image', 'jpeg'), - )); - - final headers = {'Cookie': "pguid=${SharedPrefs().guid};"}; - multipartRequest.headers.addAll(headers); - - final response = await multipartRequest.send(); - final responseString = await response.stream.bytesToString(); - - final jsonResponse = jsonDecode(responseString); - final idPhotoString = jsonResponse[0]['id_photo']; - final idPhoto = int.parse(idPhotoString); - - return idPhoto; - } catch (e) { - print('Error uploading photo: $e'); - return -1; - } - } - @override Widget build(BuildContext context) { return Scaffold( @@ -175,9 +221,15 @@ class _UploadPhotosPageState extends State { Visibility( visible: !_isUploading, child: ElevatedButton( - child: Text('Upload Photos ($_totalUploaded / $_totalPhotos)'), - onPressed: _isFinished ? null : _uploadPhotos, - ), + child: + Text('Upload Photos ($_totalUploaded / $_totalPhotos)'), + onPressed: _isFinished + ? null + : () { + _uploadPhotos(); + } + //, + ), ), ], ), diff --git a/lib/ui/visit/tab_visit.dart b/lib/ui/visit/tab_visit.dart index 4e40d54..b96c029 100644 --- a/lib/ui/visit/tab_visit.dart +++ b/lib/ui/visit/tab_visit.dart @@ -5,7 +5,7 @@ import 'package:mobdr/main.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/events.dart'; -import 'package:mobdr/model/visite_model.dart'; +import 'package:mobdr/model/visit_model.dart'; import 'package:mobdr/ui/visit/visit_photo_typology.dart'; import 'package:mobdr/ui/reusable/cache_image_network.dart'; import 'package:mobdr/ui/sync/upload_photos.dart'; @@ -27,7 +27,7 @@ class _TabVisitListPageState extends State bool _isLoading = true; String _errorMessage = ''; - late List modelData = []; + late List modelData = []; late StreamSubscription subVisitPhotoCountEvent; @@ -134,7 +134,12 @@ class _TabVisitListPageState extends State ), Expanded( child: GestureDetector( - onTap: () {}, + onTap: () { + Route route = MaterialPageRoute( + builder: (context) => UploadPhotosPage(pp_id_visite: 0), + ); + Navigator.push(context, route); + }, child: Container( alignment: Alignment.center, padding: EdgeInsets.fromLTRB(12, 8, 12, 8), @@ -157,18 +162,14 @@ class _TabVisitListPageState extends State ])); } - Widget _buildVisitelistCard( - VisiteModel visiteData, boxImageSize, animation, index) { + Widget _buildVisitelistCard(VisitModel data, boxImageSize, animation, index) { return SizeTransition( sizeFactor: animation, child: GestureDetector( onTap: () { Route route = MaterialPageRoute( - builder: (context) => VisitPhotoTypologyPage( - pp_id_distrib: visiteData.id_distrib, - pp_langage: visiteData.langage, - pp_id_visite: visiteData.id_visite, - pp_name: visiteData.name)); + builder: (context) => + VisitPhotoTypologyPage(pp_visitModel: data)); Navigator.push(context, route); }, child: Container( @@ -192,7 +193,7 @@ class _TabVisitListPageState extends State child: buildCacheNetworkImage( width: boxImageSize, height: boxImageSize, - url: visiteData.image, + url: data.image, ), ), SizedBox( @@ -206,20 +207,20 @@ class _TabVisitListPageState extends State margin: EdgeInsets.only(top: 5), child: Row( children: [ - Text(visiteData.name, + Text(data.name, style: GlobalStyle.productPrice) ], ), ), Container(height: 8), Text( - visiteData.date, + data.date, style: GlobalStyle.productSale, ), Container( margin: EdgeInsets.only(top: 5), child: Text( - '${visiteData.photoCount} Photo(s)', + '${data.photoCount} Photo(s)', style: GlobalStyle.productPrice, ), ), @@ -234,7 +235,7 @@ class _TabVisitListPageState extends State size: 20, ), Text( - ' ' + visiteData.type_visite, + ' ' + data.type_visite, style: GlobalStyle.productName.copyWith( fontSize: 13, ), @@ -254,7 +255,7 @@ class _TabVisitListPageState extends State child: Row( children: [ Expanded( - child: (visiteData.photoCount == 0) + child: (data.photoCount == 0) ? TextButton( style: ButtonStyle( minimumSize: @@ -284,11 +285,7 @@ class _TabVisitListPageState extends State onPressed: () { Route route = MaterialPageRoute( builder: (context) => UploadPhotosPage( - id_visite: visiteData.id_visite, - photoPaths: [ - 'sim_1682957196322406.jpeg', - ], - ), + pp_id_visite: data.id_visite), ); Navigator.push(context, route); }, @@ -331,7 +328,7 @@ class _TabVisitListPageState extends State Future loadData() async { try { // data initialisation with today visits - modelData = await VisiteModel.getAllVisit(); + modelData = await VisitModel.getAllVisit(); } catch (e) { // set errorMessage for debug _errorMessage = 'Error loading visits : $e'; diff --git a/lib/ui/visit/visit_photo_typology.dart b/lib/ui/visit/visit_photo_typology.dart index b63aee2..aa127a2 100644 --- a/lib/ui/visit/visit_photo_typology.dart +++ b/lib/ui/visit/visit_photo_typology.dart @@ -6,21 +6,15 @@ import 'package:mobdr/main.dart'; import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/db/box_photo_typology.dart'; +import 'package:mobdr/model/visit_model.dart'; import 'package:mobdr/ui/visit/visit_photo_typology_list.dart'; class VisitPhotoTypologyPage extends StatefulWidget { - final int pp_id_distrib; - final String pp_langage; - final int pp_id_visite; - final String pp_name; + final VisitModel pp_visitModel; VisitPhotoTypologyPage({ - Key? key, - required this.pp_id_distrib, - required this.pp_langage, - required this.pp_id_visite, - required this.pp_name, - }) : super(key: key); + required this.pp_visitModel, + }); @override _VisitPhotoTypologyPageState createState() => _VisitPhotoTypologyPageState(); @@ -33,9 +27,7 @@ class _VisitPhotoTypologyPageState extends State { onTap: () { Route route = MaterialPageRoute( builder: (context) => VisitPhotoTypologyListPage( - pp_id_distrib: widget.pp_id_distrib, - pp_langage: widget.pp_langage, - pp_id_visite: widget.pp_id_visite, + pp_visitModel: widget.pp_visitModel, pp_id_typologie: PhotoTypology[index].id_photo_typologie, pp_libelle_typologie: PhotoTypology[index].libelle, @@ -58,7 +50,7 @@ class _VisitPhotoTypologyPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildBadge( - widget.pp_id_visite, + widget.pp_visitModel.id_visite, PhotoTypology[index].id_photo_typologie, PhotoTypology[index].libelle), Icon(Icons.chevron_right, size: 20, color: SOFT_GREY), @@ -135,7 +127,7 @@ class _VisitPhotoTypologyPageState extends State { ), elevation: GlobalStyle.appBarElevation, title: Text( - widget.pp_name, + widget.pp_visitModel.name, style: GlobalStyle.appBarTitle, ), backgroundColor: GlobalStyle.appBarBackgroundColor, diff --git a/lib/ui/visit/visit_photo_typology_detail.dart b/lib/ui/visit/visit_photo_typology_detail.dart index 29a83ec..0cb563e 100644 --- a/lib/ui/visit/visit_photo_typology_detail.dart +++ b/lib/ui/visit/visit_photo_typology_detail.dart @@ -5,33 +5,29 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:mobdr/config/constant.dart'; -import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/main.dart'; import 'package:mobdr/ui/general/chat_us.dart'; import 'package:mobdr/ui/visit/visit_photo_tag.dart'; -import 'package:mobdr/db/box_photo.dart'; +import 'package:mobdr/db/box_visit_photo.dart'; import 'package:mobdr/db/box_photo_typology.dart'; import 'package:mobdr/db/box_photo_competitor.dart'; +import 'package:mobdr/model/visit_model.dart'; class VisitPhotoTypologyDetailPage extends StatefulWidget { - // variables corresponding to the data parameters - final int pp_id; - final int pp_id_distrib; - final String pp_langage; + final VisitModel pp_visitModel; + final int pp_imageId; final String pp_image; final int pp_id_typologie; // Requiring data parameters VisitPhotoTypologyDetailPage({ - Key? key, - required this.pp_id, - required this.pp_id_distrib, - required this.pp_langage, + required this.pp_visitModel, + required this.pp_imageId, required this.pp_image, required this.pp_id_typologie, - }) : super(key: key); + }); @override _VisitPhotoTypologyDetailPageState createState() => @@ -60,7 +56,7 @@ class _VisitPhotoTypologyDetailPageState void initState() { super.initState(); - loadData(widget.pp_id).then((_) { + loadData(widget.pp_imageId).then((_) { setState(() { _isLoading = false; }); @@ -228,13 +224,13 @@ class _VisitPhotoTypologyDetailPageState Widget radioSize(String txt, int index) { return GestureDetector( onTap: () async { - // save photo typology in the database - objectbox.putPhotoTypologie( - widget.pp_id, _typologiesList[index].id_photo_typologie); - setState(() { _typologyIndex = index; }); + + // save photo typology in the database + objectbox.putPhotoTypologie( + widget.pp_imageId, _typologiesList[index].id_photo_typologie); }, child: Container( padding: EdgeInsets.fromLTRB(12, 8, 12, 8), @@ -267,7 +263,7 @@ class _VisitPhotoTypologyDetailPageState }); // save photo visibilities in the database - objectbox.putPhotoVisibilities(widget.pp_id, _visibilities); + objectbox.putPhotoVisibilities(widget.pp_imageId, _visibilities); }, child: Row( children: [ @@ -340,8 +336,8 @@ class _VisitPhotoTypologyDetailPageState context, MaterialPageRoute( builder: (context) => PhotoTagPage( - pp_langage: widget.pp_langage, - pp_id_distrib: widget.pp_id_distrib, + pp_langage: widget.pp_visitModel.langage, + pp_id_distrib: widget.pp_visitModel.id_distrib, pp_photoId: this._photo.id, pp_currentTags: tagList), ), @@ -486,6 +482,11 @@ class _VisitPhotoTypologyDetailPageState setState(() { _competitor = competitor.nom; }); + + // save photo competitor in the database + objectbox.putPhotoCompetitor(widget.pp_visitModel.id, + competitor.id_concurrence_lien); + Navigator.pop(context); }, child: Container( @@ -529,7 +530,8 @@ class _VisitPhotoTypologyDetailPageState tagList = tags.isEmpty ? [] : _photo.tags.split(","); // competitor initialization - _competitorsList = objectbox.getEtabCompetitorList(); + _competitorsList = + objectbox.getEtabCompetitorList(widget.pp_visitModel.id_etab); _competitor = ""; } catch (e) { // set errorMessage for debug diff --git a/lib/ui/visit/visit_photo_typology_list.dart b/lib/ui/visit/visit_photo_typology_list.dart index 3d4bbe2..00ad398 100644 --- a/lib/ui/visit/visit_photo_typology_list.dart +++ b/lib/ui/visit/visit_photo_typology_list.dart @@ -15,10 +15,11 @@ import 'package:path_provider/path_provider.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/main.dart'; +import 'package:mobdr/db/box_visit_photo.dart'; +import 'package:mobdr/model/visit_model.dart'; import 'package:mobdr/ui/reusable/global_widget.dart'; import 'package:mobdr/ui/home/photo_camera.dart'; import 'package:mobdr/ui/visit/visit_photo_typology_detail.dart'; -import 'package:mobdr/db/box_photo.dart'; import 'package:mobdr/events.dart'; // TODO Il faut supprimer les possibles photos du répertoire cache ! @@ -31,16 +32,12 @@ extension FileNameExtension on File { } class VisitPhotoTypologyListPage extends StatefulWidget { - final int pp_id_distrib; - final String pp_langage; - final int pp_id_visite; + final VisitModel pp_visitModel; final int pp_id_typologie; final String pp_libelle_typologie; VisitPhotoTypologyListPage( - {required this.pp_id_distrib, - required this.pp_langage, - required this.pp_id_visite, + {required this.pp_visitModel, required this.pp_id_typologie, required this.pp_libelle_typologie}); @@ -235,9 +232,8 @@ class _VisitPhotoTypologyListPageState onTap: () { Route route = MaterialPageRoute( builder: (context) => VisitPhotoTypologyDetailPage( - pp_id: _visitPhotoData[index].id, - pp_id_distrib: widget.pp_id_distrib, - pp_langage: widget.pp_langage, + pp_imageId: _visitPhotoData[index].id, + pp_visitModel: widget.pp_visitModel, pp_image: _visitPhotoData[index].getImage(), pp_id_typologie: widget.pp_id_typologie, )); @@ -450,10 +446,11 @@ class _VisitPhotoTypologyListPageState // TODO ƒuture void ? void loadData() { _visitPhotoData = objectbox.getAllVisitTypologyPhotos( - widget.pp_id_visite, widget.pp_id_typologie); + widget.pp_visitModel.id_visite, widget.pp_id_typologie); // number of photos of the visit - visitPhotoCount = objectbox.getVisitPhotoCount(widget.pp_id_visite); + visitPhotoCount = + objectbox.getVisitPhotoCount(widget.pp_visitModel.id_visite); } /// Removes the image at the specified [imageURL] from the cache of the [NetworkImage] provider. @@ -475,7 +472,7 @@ class _VisitPhotoTypologyListPageState /// to insert into database _listPhotos.add(VisitPhoto( - id_visite: widget.pp_id_visite, + id_visite: widget.pp_visitModel.id_visite, id_photo_typologie: widget.pp_id_typologie, image_name: myPhoto.path.split('/').last)); } @@ -490,8 +487,8 @@ class _VisitPhotoTypologyListPageState if (addedPhotos.length > 0) { visitPhotoCount += addedPhotos.length; // a global refresh event is sent - eventBus - .fire(VisitPhotoCountEvent(widget.pp_id_visite, visitPhotoCount)); + eventBus.fire(VisitPhotoCountEvent( + widget.pp_visitModel.id_visite, visitPhotoCount)); } /// refresh widget @@ -539,11 +536,11 @@ class _VisitPhotoTypologyListPageState // a global refresh event is sent visitPhotoCount -= 1; - eventBus - .fire(VisitPhotoCountEvent(widget.pp_id_visite, visitPhotoCount)); + eventBus.fire(VisitPhotoCountEvent( + widget.pp_visitModel.id_visite, visitPhotoCount)); // delete file on database - objectbox.delPhoto(removedItem.image_name); + objectbox.delPhotoByName(removedItem.image_name); // delete file on local storage deleteFile(new File(removedItem.getImage()));