mirror of
https://github.com/darkmoonight/Rain.git
synced 2025-06-28 12:09:57 +00:00
Fix map
This commit is contained in:
parent
f174c0f336
commit
d5a34ea11b
4 changed files with 219 additions and 182 deletions
|
@ -80,7 +80,9 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
|||
|
||||
Widget _buildMapTileLayer() {
|
||||
return TileLayer(
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
urlTemplate: settings.language == 'ru_RU'
|
||||
? 'https://tile2.maps.2gis.com/tiles?x={x}&y={y}&z={z}'
|
||||
: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
userAgentPackageName: 'com.darkmoonight.rain',
|
||||
);
|
||||
}
|
||||
|
@ -171,10 +173,15 @@ class _SelectGeolocationState extends State<SelectGeolocation> {
|
|||
animationConfig: const ScaleRAWA(),
|
||||
attributions: [
|
||||
TextSourceAttribution(
|
||||
'OpenStreetMap contributors',
|
||||
settings.language == 'ru_RU'
|
||||
? '2GIS contributors'
|
||||
: 'OpenStreetMap contributors',
|
||||
onTap: () => weatherController
|
||||
.urlLauncher(
|
||||
'https://openstreetmap.org/copyright'),
|
||||
.urlLauncher(settings
|
||||
.language ==
|
||||
'ru_RU'
|
||||
? 'https://law.2gis.ru/copyright'
|
||||
: 'https://openstreetmap.org/copyright'),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:io';
|
|||
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
|
||||
import 'package:dio_cache_interceptor_file_store/dio_cache_interceptor_file_store.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map_animations/flutter_map_animations.dart';
|
||||
import 'package:flutter_map_cache/flutter_map_cache.dart';
|
||||
|
@ -177,7 +178,9 @@ class _MapWeatherState extends State<MapWeather> with TickerProviderStateMixin {
|
|||
|
||||
Widget _buildMapTileLayer(CacheStore cacheStore) {
|
||||
return TileLayer(
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
urlTemplate: settings.language == 'ru_RU'
|
||||
? 'https://tile2.maps.2gis.com/tiles?x={x}&y={y}&z={z}'
|
||||
: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
userAgentPackageName: 'com.darkmoonight.rain',
|
||||
tileProvider: CachedTileProvider(
|
||||
store: cacheStore,
|
||||
|
@ -219,192 +222,210 @@ class _MapWeatherState extends State<MapWeather> with TickerProviderStateMixin {
|
|||
final hourOfDay = weatherController.hourOfDay.value;
|
||||
final dayOfNow = weatherController.dayOfNow.value;
|
||||
|
||||
return FutureBuilder<CacheStore>(
|
||||
future: _cacheStoreFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return Scaffold(
|
||||
body: FutureBuilder<CacheStore>(
|
||||
future: _cacheStoreFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (snapshot.hasError) {
|
||||
return Center(child: Text(snapshot.error.toString()));
|
||||
}
|
||||
if (snapshot.hasError) {
|
||||
return Center(child: Text(snapshot.error.toString()));
|
||||
}
|
||||
|
||||
final cacheStore = snapshot.data!;
|
||||
final cacheStore = snapshot.data!;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
FlutterMap(
|
||||
mapController: _animatedMapController.mapController,
|
||||
options: MapOptions(
|
||||
backgroundColor: context.theme.colorScheme.surface,
|
||||
initialCenter: LatLng(mainLocation.lat!, mainLocation.lon!),
|
||||
initialZoom: 12,
|
||||
cameraConstraint: CameraConstraint.contain(
|
||||
bounds: LatLngBounds(
|
||||
const LatLng(-90, -180),
|
||||
const LatLng(90, 180),
|
||||
return Stack(
|
||||
children: [
|
||||
FlutterMap(
|
||||
mapController: _animatedMapController.mapController,
|
||||
options: MapOptions(
|
||||
backgroundColor: context.theme.colorScheme.surface,
|
||||
initialCenter: LatLng(mainLocation.lat!, mainLocation.lon!),
|
||||
initialZoom: 12,
|
||||
cameraConstraint: CameraConstraint.contain(
|
||||
bounds: LatLngBounds(
|
||||
const LatLng(-90, -180),
|
||||
const LatLng(90, 180),
|
||||
),
|
||||
),
|
||||
onTap: (_, __) => _hideCard(),
|
||||
onLongPress: (tapPosition, point) => showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
enableDrag: false,
|
||||
builder: (BuildContext context) => CreateWeatherCard(
|
||||
latitude: '${point.latitude}',
|
||||
longitude: '${point.longitude}',
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: (_, __) => _hideCard(),
|
||||
onLongPress: (tapPosition, point) => showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
enableDrag: false,
|
||||
builder: (BuildContext context) => CreateWeatherCard(
|
||||
latitude: '${point.latitude}',
|
||||
longitude: '${point.longitude}',
|
||||
children: [
|
||||
if (_isDarkMode)
|
||||
ColorFiltered(
|
||||
colorFilter: const ColorFilter.matrix(<double>[
|
||||
-0.2, -0.7, -0.08, 0, 255, // Red channel
|
||||
-0.2, -0.7, -0.08, 0, 255, // Green channel
|
||||
-0.2, -0.7, -0.08, 0, 255, // Blue channel
|
||||
0, 0, 0, 1, 0, // Alpha channel
|
||||
]),
|
||||
child: _buildMapTileLayer(cacheStore),
|
||||
)
|
||||
else
|
||||
_buildMapTileLayer(cacheStore),
|
||||
RichAttributionWidget(
|
||||
animationConfig: const ScaleRAWA(),
|
||||
alignment: AttributionAlignment.bottomLeft,
|
||||
attributions: [
|
||||
TextSourceAttribution(
|
||||
settings.language == 'ru_RU'
|
||||
? '2GIS contributors'
|
||||
: 'OpenStreetMap contributors',
|
||||
onTap: () => weatherController.urlLauncher(
|
||||
settings.language == 'ru_RU'
|
||||
? 'https://law.2gis.ru/copyright'
|
||||
: 'https://openstreetmap.org/copyright'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Obx(() {
|
||||
final mainMarker = _buildMainLocationMarker(
|
||||
WeatherCard.fromJson({
|
||||
...mainWeather.toJson(),
|
||||
...mainLocation.toJson(),
|
||||
}),
|
||||
hourOfDay,
|
||||
dayOfNow,
|
||||
);
|
||||
|
||||
final cardMarkers = weatherController.weatherCards
|
||||
.map((weatherCardList) =>
|
||||
_buildCardMarker(weatherCardList))
|
||||
.toList();
|
||||
|
||||
return MarkerLayer(
|
||||
markers: [mainMarker, ...cardMarkers],
|
||||
);
|
||||
}),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: _buildWeatherCard(),
|
||||
),
|
||||
],
|
||||
),
|
||||
RawAutocomplete<Result>(
|
||||
focusNode: _focusNode,
|
||||
textEditingController: _controllerSearch,
|
||||
fieldViewBuilder: (BuildContext context,
|
||||
TextEditingController fieldTextEditingController,
|
||||
FocusNode fieldFocusNode,
|
||||
VoidCallback onFieldSubmitted) {
|
||||
return MyTextForm(
|
||||
labelText: 'search'.tr,
|
||||
type: TextInputType.text,
|
||||
icon: const Icon(IconsaxPlusLinear.global_search),
|
||||
controller: _controllerSearch,
|
||||
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
|
||||
focusNode: _focusNode,
|
||||
onChanged: (value) => setState(() {}),
|
||||
iconButton: _controllerSearch.text.isNotEmpty
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
_controllerSearch.clear();
|
||||
},
|
||||
icon: const Icon(
|
||||
IconsaxPlusLinear.close_circle,
|
||||
color: Colors.grey,
|
||||
size: 20,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
},
|
||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||
if (textEditingValue.text.isEmpty) {
|
||||
return const Iterable<Result>.empty();
|
||||
}
|
||||
return WeatherAPI().getCity(textEditingValue.text, locale);
|
||||
},
|
||||
onSelected: (Result selection) {
|
||||
_animatedMapController.mapController.move(
|
||||
LatLng(selection.latitude, selection.longitude), 14);
|
||||
_controllerSearch.clear();
|
||||
_focusNode.unfocus();
|
||||
},
|
||||
displayStringForOption: (Result option) =>
|
||||
'${option.name}, ${option.admin1}',
|
||||
optionsViewBuilder: (BuildContext context,
|
||||
AutocompleteOnSelected<Result> onSelected,
|
||||
Iterable<Result> options) {
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
elevation: 4.0,
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: options.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final Result option = options.elementAt(index);
|
||||
return InkWell(
|
||||
onTap: () => onSelected(option),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
'${option.name}, ${option.admin1}',
|
||||
style: context.textTheme.labelLarge,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
floatingActionButtonLocation: ExpandableFab.location,
|
||||
floatingActionButton: _isCardVisible
|
||||
? null
|
||||
: ExpandableFab(
|
||||
pos: ExpandableFabPos.right,
|
||||
type: ExpandableFabType.up,
|
||||
distance: 70,
|
||||
openButtonBuilder: RotateFloatingActionButtonBuilder(
|
||||
child: const Icon(IconsaxPlusLinear.menu),
|
||||
fabSize: ExpandableFabSize.regular,
|
||||
),
|
||||
closeButtonBuilder: DefaultFloatingActionButtonBuilder(
|
||||
child: const Icon(Icons.close),
|
||||
fabSize: ExpandableFabSize.regular,
|
||||
),
|
||||
children: [
|
||||
if (_isDarkMode)
|
||||
ColorFiltered(
|
||||
colorFilter: const ColorFilter.matrix(<double>[
|
||||
-0.2, -0.7, -0.08, 0, 255, // Red channel
|
||||
-0.2, -0.7, -0.08, 0, 255, // Green channel
|
||||
-0.2, -0.7, -0.08, 0, 255, // Blue channel
|
||||
0, 0, 0, 1, 0, // Alpha channel
|
||||
]),
|
||||
child: _buildMapTileLayer(cacheStore),
|
||||
)
|
||||
else
|
||||
_buildMapTileLayer(cacheStore),
|
||||
RichAttributionWidget(
|
||||
animationConfig: const ScaleRAWA(),
|
||||
alignment: AttributionAlignment.bottomLeft,
|
||||
attributions: [
|
||||
TextSourceAttribution(
|
||||
'OpenStreetMap contributors',
|
||||
onTap: () => weatherController
|
||||
.urlLauncher('https://openstreetmap.org/copyright'),
|
||||
),
|
||||
],
|
||||
FloatingActionButton(
|
||||
heroTag: null,
|
||||
child: const Icon(IconsaxPlusLinear.gps),
|
||||
onPressed: () => _resetMapOrientation(
|
||||
center: LatLng(mainLocation.lat!, mainLocation.lon!),
|
||||
zoom: 12),
|
||||
),
|
||||
Obx(() {
|
||||
final mainMarker = _buildMainLocationMarker(
|
||||
WeatherCard.fromJson({
|
||||
...mainWeather.toJson(),
|
||||
...mainLocation.toJson(),
|
||||
}),
|
||||
hourOfDay,
|
||||
dayOfNow,
|
||||
);
|
||||
|
||||
final cardMarkers = weatherController.weatherCards
|
||||
.map((weatherCardList) =>
|
||||
_buildCardMarker(weatherCardList))
|
||||
.toList();
|
||||
|
||||
return MarkerLayer(
|
||||
markers: [mainMarker, ...cardMarkers],
|
||||
);
|
||||
}),
|
||||
Positioned(
|
||||
bottom: 15,
|
||||
right: 15,
|
||||
child: FloatingActionButton(
|
||||
child: const Icon(IconsaxPlusLinear.gps),
|
||||
onPressed: () => _resetMapOrientation(
|
||||
center: LatLng(mainLocation.lat!, mainLocation.lon!),
|
||||
zoom: 12),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 15,
|
||||
right: 85,
|
||||
child: FloatingActionButton(
|
||||
child: const Icon(IconsaxPlusLinear.refresh_square_2),
|
||||
onPressed: () => _resetMapOrientation(),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: _buildWeatherCard(),
|
||||
FloatingActionButton(
|
||||
heroTag: null,
|
||||
child: const Icon(IconsaxPlusLinear.refresh_2),
|
||||
onPressed: () => _resetMapOrientation(),
|
||||
),
|
||||
],
|
||||
),
|
||||
RawAutocomplete<Result>(
|
||||
focusNode: _focusNode,
|
||||
textEditingController: _controllerSearch,
|
||||
fieldViewBuilder: (BuildContext context,
|
||||
TextEditingController fieldTextEditingController,
|
||||
FocusNode fieldFocusNode,
|
||||
VoidCallback onFieldSubmitted) {
|
||||
return MyTextForm(
|
||||
labelText: 'search'.tr,
|
||||
type: TextInputType.text,
|
||||
icon: const Icon(IconsaxPlusLinear.global_search),
|
||||
controller: _controllerSearch,
|
||||
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
|
||||
focusNode: _focusNode,
|
||||
onChanged: (value) => setState(() {}),
|
||||
iconButton: _controllerSearch.text.isNotEmpty
|
||||
? IconButton(
|
||||
onPressed: () {
|
||||
_controllerSearch.clear();
|
||||
},
|
||||
icon: const Icon(
|
||||
IconsaxPlusLinear.close_circle,
|
||||
color: Colors.grey,
|
||||
size: 20,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
},
|
||||
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||
if (textEditingValue.text.isEmpty) {
|
||||
return const Iterable<Result>.empty();
|
||||
}
|
||||
return WeatherAPI().getCity(textEditingValue.text, locale);
|
||||
},
|
||||
onSelected: (Result selection) {
|
||||
_animatedMapController.mapController
|
||||
.move(LatLng(selection.latitude, selection.longitude), 14);
|
||||
_controllerSearch.clear();
|
||||
_focusNode.unfocus();
|
||||
},
|
||||
displayStringForOption: (Result option) =>
|
||||
'${option.name}, ${option.admin1}',
|
||||
optionsViewBuilder: (BuildContext context,
|
||||
AutocompleteOnSelected<Result> onSelected,
|
||||
Iterable<Result> options) {
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
elevation: 4.0,
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: options.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final Result option = options.elementAt(index);
|
||||
return InkWell(
|
||||
onTap: () => onSelected(option),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
'${option.name}, ${option.admin1}',
|
||||
style: context.textTheme.labelLarge,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
12
pubspec.lock
12
pubspec.lock
|
@ -347,6 +347,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
flutter_expandable_fab:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_expandable_fab
|
||||
sha256: f4692d1949cda81e10ca0c3e75aea1e14e29ecc12d9328996321b96e9747a955
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
flutter_hsvcolor_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -441,10 +449,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_timezone
|
||||
sha256: "0cb5498dedfaac615c779138194052f04524c31d958fab33d378f22b6cc14686"
|
||||
sha256: "06150cc6dde7a0309acc3f1c38380819ae774be4d942934c824c4fa64efadffa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "3.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
|
@ -33,7 +33,7 @@ dependencies:
|
|||
path_provider: ^2.1.4
|
||||
# quick_settings: ^1.0.1
|
||||
json_annotation: ^4.9.0
|
||||
flutter_timezone: ^2.1.0
|
||||
flutter_timezone: ^3.0.0
|
||||
device_info_plus: ^10.1.2
|
||||
package_info_plus: ^8.0.2
|
||||
connectivity_plus: ^6.0.5
|
||||
|
@ -44,6 +44,7 @@ dependencies:
|
|||
line_awesome_flutter: ^3.0.1
|
||||
dio_cache_interceptor: ^3.5.0
|
||||
flutter_map_animations: ^0.7.1
|
||||
flutter_expandable_fab: ^2.2.0
|
||||
flutter_hsvcolor_picker: ^1.5.1
|
||||
scrollable_positioned_list: ^0.3.8
|
||||
flutter_local_notifications: ^17.2.2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue