This commit is contained in:
Yoshi 2024-08-22 22:49:37 +03:00
parent f174c0f336
commit d5a34ea11b
4 changed files with 219 additions and 182 deletions

View file

@ -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'),
),
],
),

View file

@ -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,
),
),
);
},
),
),
),
);
},
),
],
);
},
);
}
}

View file

@ -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

View file

@ -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