fix: solve the map state management problem when expanding/collapsed.
This commit is contained in:
@@ -156,8 +156,19 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
widget.onSelectionChanged();
|
widget.onSelectionChanged();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setState(
|
if (isExpanded) {
|
||||||
() => _expandedStates[mergedRecord.groupKey] = !isExpanded);
|
final mapId =
|
||||||
|
mergedRecord.records.map((r) => r.uniqueId).join('_');
|
||||||
|
setState(() {
|
||||||
|
_expandedStates[mergedRecord.groupKey] = false;
|
||||||
|
_mapOptimalZoom.remove(mapId);
|
||||||
|
_mapCalculating.remove(mapId);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_expandedStates[mergedRecord.groupKey] = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
@@ -261,8 +272,8 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double _calculateOptimalZoom(List<LatLng> positions, {double containerWidth = 400, double containerHeight = 220}) {
|
double _calculateOptimalZoom(List<LatLng> positions,
|
||||||
if (positions.isEmpty) return 15.0;
|
{double containerWidth = 400, double containerHeight = 220}) {
|
||||||
if (positions.length == 1) return 17.0;
|
if (positions.length == 1) return 17.0;
|
||||||
|
|
||||||
double minLat = positions[0].latitude;
|
double minLat = positions[0].latitude;
|
||||||
@@ -298,8 +309,12 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
|
|
||||||
const paddingRatio = 0.8;
|
const paddingRatio = 0.8;
|
||||||
|
|
||||||
final widthZoom = math.log((containerWidth * paddingRatio) / (widthWorld * 256.0)) / math.log(2.0);
|
final widthZoom =
|
||||||
final heightZoom = math.log((containerHeight * paddingRatio) / (heightWorld * 256.0)) / math.log(2.0);
|
math.log((containerWidth * paddingRatio) / (widthWorld * 256.0)) /
|
||||||
|
math.log(2.0);
|
||||||
|
final heightZoom =
|
||||||
|
math.log((containerHeight * paddingRatio) / (heightWorld * 256.0)) /
|
||||||
|
math.log(2.0);
|
||||||
|
|
||||||
final optimalZoom = math.min(widthZoom, heightZoom);
|
final optimalZoom = math.min(widthZoom, heightZoom);
|
||||||
|
|
||||||
@@ -314,8 +329,10 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
final deltaLng = (pos2.longitude - pos1.longitude) * math.pi / 180;
|
final deltaLng = (pos2.longitude - pos1.longitude) * math.pi / 180;
|
||||||
|
|
||||||
final a = math.sin(deltaLat / 2) * math.sin(deltaLat / 2) +
|
final a = math.sin(deltaLat / 2) * math.sin(deltaLat / 2) +
|
||||||
math.cos(lat1) * math.cos(lat2) *
|
math.cos(lat1) *
|
||||||
math.sin(deltaLng / 2) * math.sin(deltaLng / 2);
|
math.cos(lat2) *
|
||||||
|
math.sin(deltaLng / 2) *
|
||||||
|
math.sin(deltaLng / 2);
|
||||||
final c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
|
final c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
|
||||||
|
|
||||||
return earthRadius * c;
|
return earthRadius * c;
|
||||||
@@ -328,7 +345,9 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
if (record.direction != 0) parts.add(record.direction == 1 ? "下" : "上");
|
if (record.direction != 0) parts.add(record.direction == 1 ? "下" : "上");
|
||||||
if (record.position.isNotEmpty && record.position != "<NUL>") {
|
if (record.position.isNotEmpty && record.position != "<NUL>") {
|
||||||
final position = record.position;
|
final position = record.position;
|
||||||
final cleanPosition = position.endsWith('.') ? position.substring(0, position.length - 1) : position;
|
final cleanPosition = position.endsWith('.')
|
||||||
|
? position.substring(0, position.length - 1)
|
||||||
|
: position;
|
||||||
parts.add("${cleanPosition}K");
|
parts.add("${cleanPosition}K");
|
||||||
}
|
}
|
||||||
return parts.join(' ');
|
return parts.join(' ');
|
||||||
@@ -344,10 +363,13 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
final mapId = records.map((r) => r.uniqueId).join('_');
|
final mapId = records.map((r) => r.uniqueId).join('_');
|
||||||
final bounds = LatLngBounds.fromPoints(positions);
|
final bounds = LatLngBounds.fromPoints(positions);
|
||||||
|
|
||||||
if (!_mapOptimalZoom.containsKey(mapId) && !(_mapCalculating[mapId] ?? false)) {
|
if (!_mapOptimalZoom.containsKey(mapId) &&
|
||||||
|
!(_mapCalculating[mapId] ?? false)) {
|
||||||
_mapCalculating[mapId] = true;
|
_mapCalculating[mapId] = true;
|
||||||
|
|
||||||
_calculateOptimalZoomAsync(positions, containerWidth: 400, containerHeight: 220).then((optimalZoom) {
|
_calculateOptimalZoomAsync(positions,
|
||||||
|
containerWidth: 400, containerHeight: 220)
|
||||||
|
.then((optimalZoom) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_mapOptimalZoom[mapId] = optimalZoom;
|
_mapOptimalZoom[mapId] = optimalZoom;
|
||||||
@@ -357,7 +379,24 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final zoomLevel = _mapOptimalZoom[mapId] ?? _getDefaultZoom(positions);
|
if (!_mapOptimalZoom.containsKey(mapId)) {
|
||||||
|
return const Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 8),
|
||||||
|
SizedBox(
|
||||||
|
height: 228,
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: Colors.blue,
|
||||||
|
strokeWidth: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final zoomLevel = _mapOptimalZoom[mapId]!;
|
||||||
|
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
@@ -366,33 +405,12 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
margin: const EdgeInsets.symmetric(vertical: 4),
|
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(8), color: Colors.grey[900]),
|
borderRadius: BorderRadius.circular(8), color: Colors.grey[900]),
|
||||||
child: FlutterMap(
|
child: _DelayedMultiMarkerMap(
|
||||||
options: MapOptions(
|
key: ValueKey('multi_map_${mapId}_$zoomLevel'),
|
||||||
initialCenter: bounds.center,
|
positions: positions,
|
||||||
initialZoom: zoomLevel,
|
center: bounds.center,
|
||||||
minZoom: 5,
|
zoom: zoomLevel,
|
||||||
maxZoom: 18),
|
))
|
||||||
children: [
|
|
||||||
TileLayer(
|
|
||||||
urlTemplate:
|
|
||||||
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
|
||||||
userAgentPackageName: 'org.noxylva.lbjconsole'),
|
|
||||||
MarkerLayer(
|
|
||||||
markers: positions
|
|
||||||
.map((pos) => Marker(
|
|
||||||
point: pos,
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.red.withOpacity(0.8),
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
border: Border.all(
|
|
||||||
color: Colors.white, width: 2)),
|
|
||||||
child: const Icon(Icons.train,
|
|
||||||
color: Colors.white, size: 20))))
|
|
||||||
.toList())
|
|
||||||
]))
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,7 +450,17 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
widget.onSelectionChanged();
|
widget.onSelectionChanged();
|
||||||
});
|
});
|
||||||
} else if (!isSubCard) {
|
} else if (!isSubCard) {
|
||||||
setState(() => _expandedStates[record.uniqueId] = !isExpanded);
|
if (isExpanded) {
|
||||||
|
setState(() {
|
||||||
|
_expandedStates[record.uniqueId] = false;
|
||||||
|
_mapOptimalZoom.remove(record.uniqueId);
|
||||||
|
_mapCalculating.remove(record.uniqueId);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_expandedStates[record.uniqueId] = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
@@ -569,7 +597,8 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
if (isValidRoute && isValidPosition) const SizedBox(width: 4),
|
if (isValidRoute && isValidPosition) const SizedBox(width: 4),
|
||||||
if (isValidPosition)
|
if (isValidPosition)
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text("${position.trim().endsWith('.') ? position.trim().substring(0, position.trim().length - 1) : position.trim()}K",
|
child: Text(
|
||||||
|
"${position.trim().endsWith('.') ? position.trim().substring(0, position.trim().length - 1) : position.trim()}K",
|
||||||
style:
|
style:
|
||||||
const TextStyle(fontSize: 16, color: Colors.white),
|
const TextStyle(fontSize: 16, color: Colors.white),
|
||||||
overflow: TextOverflow.ellipsis))
|
overflow: TextOverflow.ellipsis))
|
||||||
@@ -583,52 +612,60 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
|
|
||||||
Widget _buildExpandedContent(TrainRecord record) {
|
Widget _buildExpandedContent(TrainRecord record) {
|
||||||
final position = _parsePosition(record.positionInfo);
|
final position = _parsePosition(record.positionInfo);
|
||||||
if (position == null) return const SizedBox.shrink();
|
final mapId = record.uniqueId;
|
||||||
|
|
||||||
return FutureBuilder<double>(
|
if (position == null) {
|
||||||
future: Future(() => _calculateOptimalZoom([position], containerWidth: 400, containerHeight: 220)),
|
|
||||||
builder: (context, zoomSnapshot) {
|
|
||||||
if (!zoomSnapshot.hasData) {
|
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
if (!_mapOptimalZoom.containsKey(mapId) &&
|
||||||
|
!(_mapCalculating[mapId] ?? false)) {
|
||||||
|
_mapCalculating[mapId] = true;
|
||||||
|
|
||||||
|
_calculateOptimalZoomAsync([position],
|
||||||
|
containerWidth: 400, containerHeight: 220)
|
||||||
|
.then((optimalZoom) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_mapOptimalZoom[mapId] = optimalZoom;
|
||||||
|
_mapCalculating[mapId] = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_mapOptimalZoom.containsKey(mapId)) {
|
||||||
|
return const Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 8),
|
||||||
|
SizedBox(
|
||||||
|
height: 228,
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: Colors.blue,
|
||||||
|
strokeWidth: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final zoomLevel = _mapOptimalZoom[mapId]!;
|
||||||
|
|
||||||
|
return Column(children: [
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Container(
|
Container(
|
||||||
height: 220,
|
height: 220,
|
||||||
width: double.infinity,
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 4),
|
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8), color: Colors.grey[900]),
|
||||||
color: Colors.grey[900]),
|
child: _DelayedMapWithMarker(
|
||||||
child: FlutterMap(
|
key: ValueKey('map_${mapId}_$zoomLevel'),
|
||||||
options: MapOptions(
|
position: position,
|
||||||
initialCenter: position,
|
zoom: zoomLevel,
|
||||||
initialZoom: zoomSnapshot.data!
|
))
|
||||||
),
|
|
||||||
children: [
|
|
||||||
TileLayer(
|
|
||||||
urlTemplate:
|
|
||||||
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
|
||||||
userAgentPackageName: 'org.noxylva.lbjconsole'),
|
|
||||||
MarkerLayer(markers: [
|
|
||||||
Marker(
|
|
||||||
point: position,
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.red,
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
border: Border.all(
|
|
||||||
color: Colors.white, width: 2)),
|
|
||||||
child: const Icon(Icons.train,
|
|
||||||
color: Colors.white, size: 20)))
|
|
||||||
])
|
|
||||||
]))
|
|
||||||
]);
|
]);
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LatLng? _parsePosition(String? positionInfo) {
|
LatLng? _parsePosition(String? positionInfo) {
|
||||||
@@ -666,11 +703,8 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<_BoundaryBox> _calculateBoundaryBoxParallel(List<LatLng> positions) async {
|
Future<_BoundaryBox> _calculateBoundaryBoxParallel(
|
||||||
if (positions.isEmpty) {
|
List<LatLng> positions) async {
|
||||||
return _BoundaryBox(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (positions.length < 100) {
|
if (positions.length < 100) {
|
||||||
return _calculateBoundaryBoxIsolate(positions);
|
return _calculateBoundaryBoxIsolate(positions);
|
||||||
}
|
}
|
||||||
@@ -683,9 +717,8 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
chunks.add(positions.sublist(i, end));
|
chunks.add(positions.sublist(i, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
final results = await Future.wait(
|
final results = await Future.wait(chunks.map(
|
||||||
chunks.map((chunk) => Isolate.run(() => _calculateBoundaryBoxIsolate(chunk)))
|
(chunk) => Isolate.run(() => _calculateBoundaryBoxIsolate(chunk))));
|
||||||
);
|
|
||||||
|
|
||||||
double minLat = results[0].minLat;
|
double minLat = results[0].minLat;
|
||||||
double maxLat = results[0].maxLat;
|
double maxLat = results[0].maxLat;
|
||||||
@@ -702,8 +735,8 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
return _BoundaryBox(minLat, maxLat, minLng, maxLng);
|
return _BoundaryBox(minLat, maxLat, minLng, maxLng);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<double> _calculateOptimalZoomAsync(List<LatLng> positions, {required double containerWidth, required double containerHeight}) async {
|
Future<double> _calculateOptimalZoomAsync(List<LatLng> positions,
|
||||||
if (positions.isEmpty) return 15.0;
|
{required double containerWidth, required double containerHeight}) async {
|
||||||
if (positions.length == 1) return 17.0;
|
if (positions.length == 1) return 17.0;
|
||||||
|
|
||||||
final boundaryBox = await _calculateBoundaryBoxParallel(positions);
|
final boundaryBox = await _calculateBoundaryBoxParallel(positions);
|
||||||
@@ -729,12 +762,16 @@ class HistoryScreenState extends State<HistoryScreen> {
|
|||||||
|
|
||||||
const paddingRatio = 0.8;
|
const paddingRatio = 0.8;
|
||||||
|
|
||||||
final widthZoom = math.log((containerWidth * paddingRatio) / (widthWorld * 256.0)) / math.log(2.0);
|
final widthZoom =
|
||||||
final heightZoom = math.log((containerHeight * paddingRatio) / (heightWorld * 256.0)) / math.log(2.0);
|
math.log((containerWidth * paddingRatio) / (widthWorld * 256.0)) /
|
||||||
|
math.log(2.0);
|
||||||
|
final heightZoom =
|
||||||
|
math.log((containerHeight * paddingRatio) / (heightWorld * 256.0)) /
|
||||||
|
math.log(2.0);
|
||||||
|
|
||||||
final optimalZoom = math.min(widthZoom, heightZoom);
|
final optimalZoom = math.min(widthZoom, heightZoom);
|
||||||
|
|
||||||
return math.max(1.0, math.min(20.0, optimalZoom));
|
return math.max(5.0, math.min(18.0, optimalZoom));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,10 +785,6 @@ class _BoundaryBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_BoundaryBox _calculateBoundaryBoxIsolate(List<LatLng> positions) {
|
_BoundaryBox _calculateBoundaryBoxIsolate(List<LatLng> positions) {
|
||||||
if (positions.isEmpty) {
|
|
||||||
return _BoundaryBox(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
double minLat = positions[0].latitude;
|
double minLat = positions[0].latitude;
|
||||||
double maxLat = positions[0].latitude;
|
double maxLat = positions[0].latitude;
|
||||||
double minLng = positions[0].longitude;
|
double minLng = positions[0].longitude;
|
||||||
@@ -766,3 +799,95 @@ _BoundaryBox _calculateBoundaryBoxIsolate(List<LatLng> positions) {
|
|||||||
|
|
||||||
return _BoundaryBox(minLat, maxLat, minLng, maxLng);
|
return _BoundaryBox(minLat, maxLat, minLng, maxLng);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _DelayedMapWithMarker extends StatefulWidget {
|
||||||
|
final LatLng position;
|
||||||
|
final double zoom;
|
||||||
|
|
||||||
|
const _DelayedMapWithMarker({
|
||||||
|
Key? key,
|
||||||
|
required this.position,
|
||||||
|
required this.zoom,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_DelayedMapWithMarker> createState() => _DelayedMapWithMarkerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DelayedMapWithMarkerState extends State<_DelayedMapWithMarker> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FlutterMap(
|
||||||
|
options:
|
||||||
|
MapOptions(initialCenter: widget.position, initialZoom: widget.zoom),
|
||||||
|
children: [
|
||||||
|
TileLayer(
|
||||||
|
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||||
|
userAgentPackageName: 'org.noxylva.lbjconsole'),
|
||||||
|
MarkerLayer(markers: [
|
||||||
|
Marker(
|
||||||
|
point: widget.position,
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.red,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: Border.all(color: Colors.white, width: 2)),
|
||||||
|
child:
|
||||||
|
const Icon(Icons.train, color: Colors.white, size: 20)))
|
||||||
|
])
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DelayedMultiMarkerMap extends StatefulWidget {
|
||||||
|
final List<LatLng> positions;
|
||||||
|
final LatLng center;
|
||||||
|
final double zoom;
|
||||||
|
|
||||||
|
const _DelayedMultiMarkerMap({
|
||||||
|
Key? key,
|
||||||
|
required this.positions,
|
||||||
|
required this.center,
|
||||||
|
required this.zoom,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_DelayedMultiMarkerMap> createState() => _DelayedMultiMarkerMapState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DelayedMultiMarkerMapState extends State<_DelayedMultiMarkerMap> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FlutterMap(
|
||||||
|
options: MapOptions(
|
||||||
|
initialCenter: widget.center,
|
||||||
|
initialZoom: widget.zoom,
|
||||||
|
minZoom: 5,
|
||||||
|
maxZoom: 18,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TileLayer(
|
||||||
|
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||||
|
userAgentPackageName: 'org.noxylva.lbjconsole',
|
||||||
|
),
|
||||||
|
MarkerLayer(
|
||||||
|
markers: widget.positions
|
||||||
|
.map((pos) => Marker(
|
||||||
|
point: pos,
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.red.withOpacity(0.8),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(color: Colors.white, width: 2)),
|
||||||
|
child: const Icon(Icons.train,
|
||||||
|
color: Colors.white, size: 20))))
|
||||||
|
.toList()),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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: 0.1.6-flutter
|
version: 0.1.7-flutter
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
|
|||||||
Reference in New Issue
Block a user