refactor: Remove generic try-catch blocks and add explicit API error handling in activity places service.
All checks were successful
Deploy Flutter to Firebase (Mac) / deploy-android (push) Successful in 3m41s
All checks were successful
Deploy Flutter to Firebase (Mac) / deploy-android (push) Successful in 3m41s
This commit is contained in:
@@ -174,7 +174,11 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
|||||||
'Erreur recherche activités: $e',
|
'Erreur recherche activités: $e',
|
||||||
stackTrace,
|
stackTrace,
|
||||||
);
|
);
|
||||||
emit(const ActivityError('Impossible de rechercher les activités'));
|
// Extraire le message d'erreur si disponible
|
||||||
|
final errorMessage = e.toString().replaceAll('Exception: ', '');
|
||||||
|
emit(
|
||||||
|
ActivityError('Impossible de rechercher les activités: $errorMessage'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,83 +37,75 @@ class ActivityPlacesService {
|
|||||||
int maxResults = 20,
|
int maxResults = 20,
|
||||||
int offset = 0,
|
int offset = 0,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
LoggerService.info(
|
||||||
LoggerService.info(
|
'ActivityPlacesService: Recherche d\'activités pour: $destination (max: $maxResults, offset: $offset)',
|
||||||
'ActivityPlacesService: Recherche d\'activités pour: $destination (max: $maxResults, offset: $offset)',
|
);
|
||||||
|
|
||||||
|
// 1. Géocoder la destination
|
||||||
|
final coordinates = await _geocodeDestination(destination);
|
||||||
|
|
||||||
|
// 2. Rechercher les activités par catégorie ou toutes les catégories
|
||||||
|
List<Activity> allActivities = [];
|
||||||
|
|
||||||
|
if (category != null) {
|
||||||
|
final activities = await _searchByCategory(
|
||||||
|
coordinates['lat']!,
|
||||||
|
coordinates['lng']!,
|
||||||
|
category,
|
||||||
|
tripId,
|
||||||
|
radius,
|
||||||
);
|
);
|
||||||
|
allActivities.addAll(activities);
|
||||||
|
} else {
|
||||||
|
// Rechercher dans toutes les catégories principales
|
||||||
|
final mainCategories = [
|
||||||
|
ActivityCategory.attraction,
|
||||||
|
ActivityCategory.museum,
|
||||||
|
ActivityCategory.restaurant,
|
||||||
|
ActivityCategory.culture,
|
||||||
|
ActivityCategory.nature,
|
||||||
|
];
|
||||||
|
|
||||||
// 1. Géocoder la destination
|
for (final cat in mainCategories) {
|
||||||
final coordinates = await _geocodeDestination(destination);
|
|
||||||
|
|
||||||
// 2. Rechercher les activités par catégorie ou toutes les catégories
|
|
||||||
List<Activity> allActivities = [];
|
|
||||||
|
|
||||||
if (category != null) {
|
|
||||||
final activities = await _searchByCategory(
|
final activities = await _searchByCategory(
|
||||||
coordinates['lat']!,
|
coordinates['lat']!,
|
||||||
coordinates['lng']!,
|
coordinates['lng']!,
|
||||||
category,
|
cat,
|
||||||
tripId,
|
tripId,
|
||||||
radius,
|
radius,
|
||||||
);
|
);
|
||||||
allActivities.addAll(activities);
|
allActivities.addAll(activities);
|
||||||
} else {
|
|
||||||
// Rechercher dans toutes les catégories principales
|
|
||||||
final mainCategories = [
|
|
||||||
ActivityCategory.attraction,
|
|
||||||
ActivityCategory.museum,
|
|
||||||
ActivityCategory.restaurant,
|
|
||||||
ActivityCategory.culture,
|
|
||||||
ActivityCategory.nature,
|
|
||||||
];
|
|
||||||
|
|
||||||
for (final cat in mainCategories) {
|
|
||||||
final activities = await _searchByCategory(
|
|
||||||
coordinates['lat']!,
|
|
||||||
coordinates['lng']!,
|
|
||||||
cat,
|
|
||||||
tripId,
|
|
||||||
radius,
|
|
||||||
);
|
|
||||||
allActivities.addAll(activities);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Supprimer les doublons et trier par note
|
// 3. Supprimer les doublons et trier par note
|
||||||
final uniqueActivities = _removeDuplicates(allActivities);
|
final uniqueActivities = _removeDuplicates(allActivities);
|
||||||
uniqueActivities.sort((a, b) => (b.rating ?? 0).compareTo(a.rating ?? 0));
|
uniqueActivities.sort((a, b) => (b.rating ?? 0).compareTo(a.rating ?? 0));
|
||||||
|
|
||||||
|
LoggerService.info(
|
||||||
|
'ActivityPlacesService: ${uniqueActivities.length} activités trouvées au total',
|
||||||
|
);
|
||||||
|
|
||||||
|
// 4. Appliquer la pagination
|
||||||
|
final startIndex = offset;
|
||||||
|
final endIndex = (startIndex + maxResults).clamp(
|
||||||
|
0,
|
||||||
|
uniqueActivities.length,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (startIndex >= uniqueActivities.length) {
|
||||||
LoggerService.info(
|
LoggerService.info(
|
||||||
'ActivityPlacesService: ${uniqueActivities.length} activités trouvées au total',
|
'ActivityPlacesService: Offset $startIndex dépasse le nombre total (${uniqueActivities.length})',
|
||||||
);
|
);
|
||||||
|
|
||||||
// 4. Appliquer la pagination
|
|
||||||
final startIndex = offset;
|
|
||||||
final endIndex = (startIndex + maxResults).clamp(
|
|
||||||
0,
|
|
||||||
uniqueActivities.length,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (startIndex >= uniqueActivities.length) {
|
|
||||||
LoggerService.info(
|
|
||||||
'ActivityPlacesService: Offset $startIndex dépasse le nombre total (${uniqueActivities.length})',
|
|
||||||
);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
final paginatedResults = uniqueActivities.sublist(startIndex, endIndex);
|
|
||||||
LoggerService.info(
|
|
||||||
'ActivityPlacesService: Retour de ${paginatedResults.length} activités (offset: $offset, max: $maxResults)',
|
|
||||||
);
|
|
||||||
|
|
||||||
return paginatedResults;
|
|
||||||
} catch (e) {
|
|
||||||
LoggerService.error(
|
|
||||||
'ActivityPlacesService: Erreur lors de la recherche: $e',
|
|
||||||
);
|
|
||||||
_errorService.logError('activity_places_service', e);
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final paginatedResults = uniqueActivities.sublist(startIndex, endIndex);
|
||||||
|
LoggerService.info(
|
||||||
|
'ActivityPlacesService: Retour de ${paginatedResults.length} activités (offset: $offset, max: $maxResults)',
|
||||||
|
);
|
||||||
|
|
||||||
|
return paginatedResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Géocode une destination pour obtenir les coordonnées
|
/// Géocode une destination pour obtenir les coordonnées
|
||||||
@@ -191,50 +183,52 @@ class ActivityPlacesService {
|
|||||||
String tripId,
|
String tripId,
|
||||||
int radius,
|
int radius,
|
||||||
) async {
|
) async {
|
||||||
try {
|
final url =
|
||||||
final url =
|
'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
|
||||||
'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
|
'?location=$lat,$lng'
|
||||||
'?location=$lat,$lng'
|
'&radius=$radius'
|
||||||
'&radius=$radius'
|
'&type=${category.googlePlaceType}'
|
||||||
'&type=${category.googlePlaceType}'
|
'&key=$_apiKey'
|
||||||
'&key=$_apiKey'
|
'&language=fr';
|
||||||
'&language=fr';
|
|
||||||
|
|
||||||
final response = await http.get(Uri.parse(url));
|
final response = await http.get(Uri.parse(url));
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = json.decode(response.body);
|
final data = json.decode(response.body);
|
||||||
|
|
||||||
if (data['status'] == 'OK') {
|
if (data['status'] == 'OK') {
|
||||||
final List<Activity> activities = [];
|
final List<Activity> activities = [];
|
||||||
|
|
||||||
for (final place in data['results']) {
|
for (final place in data['results']) {
|
||||||
try {
|
try {
|
||||||
final activity = await _convertPlaceToActivity(
|
final activity = await _convertPlaceToActivity(
|
||||||
place,
|
place,
|
||||||
tripId,
|
tripId,
|
||||||
category,
|
category,
|
||||||
);
|
);
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
activities.add(activity);
|
activities.add(activity);
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
LoggerService.error(
|
|
||||||
'ActivityPlacesService: Erreur conversion place: $e',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
LoggerService.error(
|
||||||
|
'ActivityPlacesService: Erreur conversion place: $e',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return activities;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
return activities;
|
||||||
} catch (e) {
|
} else if (data['status'] == 'ZERO_RESULTS') {
|
||||||
LoggerService.error(
|
return [];
|
||||||
'ActivityPlacesService: Erreur recherche par catégorie: $e',
|
} else {
|
||||||
);
|
LoggerService.error(
|
||||||
return [];
|
'ActivityPlacesService: Erreur API Places: ${data['status']} - ${data['error_message']}',
|
||||||
|
);
|
||||||
|
throw Exception(
|
||||||
|
'API Places Error: ${data['status']} - ${data['error_message']}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Erreur HTTP ${response.statusCode}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,62 +351,62 @@ class ActivityPlacesService {
|
|||||||
required String tripId,
|
required String tripId,
|
||||||
int radius = 5000,
|
int radius = 5000,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
LoggerService.info(
|
||||||
LoggerService.info(
|
'ActivityPlacesService: Recherche textuelle: $query à $destination',
|
||||||
'ActivityPlacesService: Recherche textuelle: $query à $destination',
|
);
|
||||||
);
|
|
||||||
|
|
||||||
// Géocoder la destination
|
// Géocoder la destination
|
||||||
final coordinates = await _geocodeDestination(destination);
|
final coordinates = await _geocodeDestination(destination);
|
||||||
|
|
||||||
final encodedQuery = Uri.encodeComponent(query);
|
final encodedQuery = Uri.encodeComponent(query);
|
||||||
final url =
|
final url =
|
||||||
'https://maps.googleapis.com/maps/api/place/textsearch/json'
|
'https://maps.googleapis.com/maps/api/place/textsearch/json'
|
||||||
'?query=$encodedQuery in $destination'
|
'?query=$encodedQuery in $destination'
|
||||||
'&location=${coordinates['lat']},${coordinates['lng']}'
|
'&location=${coordinates['lat']},${coordinates['lng']}'
|
||||||
'&radius=$radius'
|
'&radius=$radius'
|
||||||
'&key=$_apiKey'
|
'&key=$_apiKey'
|
||||||
'&language=fr';
|
'&language=fr';
|
||||||
|
|
||||||
final response = await http.get(Uri.parse(url));
|
final response = await http.get(Uri.parse(url));
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = json.decode(response.body);
|
final data = json.decode(response.body);
|
||||||
|
|
||||||
if (data['status'] == 'OK') {
|
if (data['status'] == 'OK') {
|
||||||
final List<Activity> activities = [];
|
final List<Activity> activities = [];
|
||||||
|
|
||||||
for (final place in data['results']) {
|
for (final place in data['results']) {
|
||||||
try {
|
try {
|
||||||
// Déterminer la catégorie basée sur les types du lieu
|
// Déterminer la catégorie basée sur les types du lieu
|
||||||
final types = List<String>.from(place['types'] ?? []);
|
final types = List<String>.from(place['types'] ?? []);
|
||||||
final category = _determineCategoryFromTypes(types);
|
final category = _determineCategoryFromTypes(types);
|
||||||
|
|
||||||
final activity = await _convertPlaceToActivity(
|
final activity = await _convertPlaceToActivity(
|
||||||
place,
|
place,
|
||||||
tripId,
|
tripId,
|
||||||
category,
|
category,
|
||||||
);
|
);
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
activities.add(activity);
|
activities.add(activity);
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
LoggerService.error(
|
|
||||||
'ActivityPlacesService: Erreur conversion place: $e',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
LoggerService.error(
|
||||||
|
'ActivityPlacesService: Erreur conversion place: $e',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return activities;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
return activities;
|
||||||
} catch (e) {
|
} else if (data['status'] == 'ZERO_RESULTS') {
|
||||||
LoggerService.error(
|
return [];
|
||||||
'ActivityPlacesService: Erreur recherche textuelle: $e',
|
} else {
|
||||||
);
|
LoggerService.error(
|
||||||
return [];
|
'ActivityPlacesService: Erreur API Places Text Search: ${data['status']}',
|
||||||
|
);
|
||||||
|
throw Exception('API Error: ${data['status']}');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Erreur HTTP ${response.statusCode}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,70 +517,63 @@ class ActivityPlacesService {
|
|||||||
int pageSize,
|
int pageSize,
|
||||||
String? nextPageToken,
|
String? nextPageToken,
|
||||||
) async {
|
) async {
|
||||||
try {
|
String url =
|
||||||
String url =
|
'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
|
||||||
'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
|
'?location=$lat,$lng'
|
||||||
'?location=$lat,$lng'
|
'&radius=$radius'
|
||||||
'&radius=$radius'
|
'&type=${category.googlePlaceType}'
|
||||||
'&type=${category.googlePlaceType}'
|
'&key=$_apiKey'
|
||||||
'&key=$_apiKey'
|
'&language=fr';
|
||||||
'&language=fr';
|
|
||||||
|
|
||||||
if (nextPageToken != null) {
|
if (nextPageToken != null) {
|
||||||
url += '&pagetoken=$nextPageToken';
|
url += '&pagetoken=$nextPageToken';
|
||||||
}
|
}
|
||||||
|
|
||||||
final response = await http.get(Uri.parse(url));
|
final response = await http.get(Uri.parse(url));
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = json.decode(response.body);
|
final data = json.decode(response.body);
|
||||||
|
|
||||||
if (data['status'] == 'OK') {
|
if (data['status'] == 'OK') {
|
||||||
final List<Activity> activities = [];
|
final List<Activity> activities = [];
|
||||||
final results = data['results'] as List? ?? [];
|
final results = data['results'] as List? ?? [];
|
||||||
|
|
||||||
// Limiter à pageSize résultats
|
// Limiter à pageSize résultats
|
||||||
final limitedResults = results.take(pageSize).toList();
|
final limitedResults = results.take(pageSize).toList();
|
||||||
|
|
||||||
for (final place in limitedResults) {
|
for (final place in limitedResults) {
|
||||||
try {
|
try {
|
||||||
final activity = await _convertPlaceToActivity(
|
final activity = await _convertPlaceToActivity(
|
||||||
place,
|
place,
|
||||||
tripId,
|
tripId,
|
||||||
category,
|
category,
|
||||||
);
|
);
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
activities.add(activity);
|
activities.add(activity);
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
LoggerService.error(
|
|
||||||
'ActivityPlacesService: Erreur conversion place: $e',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
LoggerService.error(
|
||||||
|
'ActivityPlacesService: Erreur conversion place: $e',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
'activities': activities,
|
|
||||||
'nextPageToken': data['next_page_token'],
|
|
||||||
'hasMoreData': data['next_page_token'] != null,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'activities': <Activity>[],
|
'activities': activities,
|
||||||
'nextPageToken': null,
|
'nextPageToken': data['next_page_token'],
|
||||||
'hasMoreData': false,
|
'hasMoreData': data['next_page_token'] != null,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} else if (data['status'] == 'ZERO_RESULTS') {
|
||||||
LoggerService.error(
|
return {
|
||||||
'ActivityPlacesService: Erreur recherche catégorie paginée: $e',
|
'activities': <Activity>[],
|
||||||
);
|
'nextPageToken': null,
|
||||||
return {
|
'hasMoreData': false,
|
||||||
'activities': <Activity>[],
|
};
|
||||||
'nextPageToken': null,
|
} else {
|
||||||
'hasMoreData': false,
|
throw Exception('API Error: ${data['status']}');
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Erreur HTTP ${response.statusCode}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,75 +586,68 @@ class ActivityPlacesService {
|
|||||||
int pageSize,
|
int pageSize,
|
||||||
String? nextPageToken,
|
String? nextPageToken,
|
||||||
) async {
|
) async {
|
||||||
try {
|
// Pour toutes les catégories, on utilise une recherche plus générale
|
||||||
// Pour toutes les catégories, on utilise une recherche plus générale
|
String url =
|
||||||
String url =
|
'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
|
||||||
'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
|
'?location=$lat,$lng'
|
||||||
'?location=$lat,$lng'
|
'&radius=$radius'
|
||||||
'&radius=$radius'
|
'&type=tourist_attraction'
|
||||||
'&type=tourist_attraction'
|
'&key=$_apiKey'
|
||||||
'&key=$_apiKey'
|
'&language=fr';
|
||||||
'&language=fr';
|
|
||||||
|
|
||||||
if (nextPageToken != null) {
|
if (nextPageToken != null) {
|
||||||
url += '&pagetoken=$nextPageToken';
|
url += '&pagetoken=$nextPageToken';
|
||||||
}
|
}
|
||||||
|
|
||||||
final response = await http.get(Uri.parse(url));
|
final response = await http.get(Uri.parse(url));
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = json.decode(response.body);
|
final data = json.decode(response.body);
|
||||||
|
|
||||||
if (data['status'] == 'OK') {
|
if (data['status'] == 'OK') {
|
||||||
final List<Activity> activities = [];
|
final List<Activity> activities = [];
|
||||||
final results = data['results'] as List? ?? [];
|
final results = data['results'] as List? ?? [];
|
||||||
|
|
||||||
// Limiter à pageSize résultats
|
// Limiter à pageSize résultats
|
||||||
final limitedResults = results.take(pageSize).toList();
|
final limitedResults = results.take(pageSize).toList();
|
||||||
|
|
||||||
for (final place in limitedResults) {
|
for (final place in limitedResults) {
|
||||||
try {
|
try {
|
||||||
// Déterminer la catégorie basée sur les types du lieu
|
// Déterminer la catégorie basée sur les types du lieu
|
||||||
final types = List<String>.from(place['types'] ?? []);
|
final types = List<String>.from(place['types'] ?? []);
|
||||||
final category = _determineCategoryFromTypes(types);
|
final category = _determineCategoryFromTypes(types);
|
||||||
|
|
||||||
final activity = await _convertPlaceToActivity(
|
final activity = await _convertPlaceToActivity(
|
||||||
place,
|
place,
|
||||||
tripId,
|
tripId,
|
||||||
category,
|
category,
|
||||||
);
|
);
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
activities.add(activity);
|
activities.add(activity);
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
LoggerService.error(
|
|
||||||
'ActivityPlacesService: Erreur conversion place: $e',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
LoggerService.error(
|
||||||
|
'ActivityPlacesService: Erreur conversion place: $e',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
'activities': activities,
|
|
||||||
'nextPageToken': data['next_page_token'],
|
|
||||||
'hasMoreData': data['next_page_token'] != null,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'activities': <Activity>[],
|
'activities': activities,
|
||||||
'nextPageToken': null,
|
'nextPageToken': data['next_page_token'],
|
||||||
'hasMoreData': false,
|
'hasMoreData': data['next_page_token'] != null,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} else if (data['status'] == 'ZERO_RESULTS') {
|
||||||
LoggerService.error(
|
return {
|
||||||
'ActivityPlacesService: Erreur recherche toutes catégories paginée: $e',
|
'activities': <Activity>[],
|
||||||
);
|
'nextPageToken': null,
|
||||||
return {
|
'hasMoreData': false,
|
||||||
'activities': <Activity>[],
|
};
|
||||||
'nextPageToken': null,
|
} else {
|
||||||
'hasMoreData': false,
|
throw Exception('API Error: ${data['status']}');
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Erreur HTTP ${response.statusCode}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.3+1
|
version: 2025.12.1+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.9.2
|
sdk: ^3.9.2
|
||||||
|
|||||||
Reference in New Issue
Block a user