mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-02-12 16:52:51 +00:00
cusstom providers settings
This commit is contained in:
@@ -11,10 +11,9 @@ import 'state/session_state.dart';
|
||||
import 'state/settings_state.dart';
|
||||
import 'state/upload_queue_state.dart';
|
||||
|
||||
// Re-export types for backward compatibility
|
||||
// Re-export types
|
||||
export 'state/settings_state.dart' show UploadMode;
|
||||
export 'state/session_state.dart' show AddCameraSession;
|
||||
export 'models/tile_provider.dart' show TileProviderType;
|
||||
|
||||
// ------------------ AppState ------------------
|
||||
class AppState extends ChangeNotifier {
|
||||
@@ -72,9 +71,7 @@ class AppState extends ChangeNotifier {
|
||||
TileType? get selectedTileType => _settingsState.selectedTileType;
|
||||
TileProvider? get selectedTileProvider => _settingsState.selectedTileProvider;
|
||||
|
||||
/// Legacy getter for backward compatibility
|
||||
@Deprecated('Use selectedTileType instead')
|
||||
TileProviderType get tileProvider => _settingsState.tileProvider;
|
||||
|
||||
|
||||
// Upload queue state
|
||||
int get pendingCount => _uploadQueueState.pendingCount;
|
||||
@@ -202,11 +199,7 @@ class AppState extends ChangeNotifier {
|
||||
await _settingsState.deleteTileProvider(providerId);
|
||||
}
|
||||
|
||||
/// Legacy setter for backward compatibility
|
||||
@Deprecated('Use setSelectedTileType instead')
|
||||
Future<void> setTileProvider(TileProviderType provider) async {
|
||||
await _settingsState.setTileProvider(provider);
|
||||
}
|
||||
|
||||
|
||||
// ---------- Queue Methods ----------
|
||||
void clearQueue() {
|
||||
|
||||
@@ -212,12 +212,3 @@ class DefaultTileProviders {
|
||||
}
|
||||
}
|
||||
|
||||
/// Legacy enum for backward compatibility during transition
|
||||
/// TODO: Remove once all references are updated
|
||||
@Deprecated('Use TileProvider and TileType instead')
|
||||
enum TileProviderType {
|
||||
osmStreet,
|
||||
googleHybrid,
|
||||
arcgisSatellite,
|
||||
mapboxSatellite,
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
|
||||
|
||||
import '../../app_state.dart';
|
||||
import '../../models/tile_provider.dart';
|
||||
import '../tile_provider_management_screen.dart';
|
||||
|
||||
class TileProviderSection extends StatelessWidget {
|
||||
const TileProviderSection({super.key});
|
||||
@@ -28,9 +29,10 @@ class TileProviderSection extends StatelessWidget {
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// TODO: Navigate to provider management screen
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Provider management coming soon!')),
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const TileProviderManagementScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('Manage Providers'),
|
||||
|
||||
390
lib/screens/tile_provider_editor_screen.dart
Normal file
390
lib/screens/tile_provider_editor_screen.dart
Normal file
@@ -0,0 +1,390 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../app_state.dart';
|
||||
import '../models/tile_provider.dart';
|
||||
|
||||
class TileProviderEditorScreen extends StatefulWidget {
|
||||
final TileProvider? provider; // null for adding new provider
|
||||
|
||||
const TileProviderEditorScreen({super.key, this.provider});
|
||||
|
||||
@override
|
||||
State<TileProviderEditorScreen> createState() => _TileProviderEditorScreenState();
|
||||
}
|
||||
|
||||
class _TileProviderEditorScreenState extends State<TileProviderEditorScreen> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late final TextEditingController _nameController;
|
||||
late final TextEditingController _apiKeyController;
|
||||
late List<TileType> _tileTypes;
|
||||
|
||||
bool get _isEditing => widget.provider != null;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final provider = widget.provider;
|
||||
_nameController = TextEditingController(text: provider?.name ?? '');
|
||||
_apiKeyController = TextEditingController(text: provider?.apiKey ?? '');
|
||||
_tileTypes = provider != null
|
||||
? List.from(provider.tileTypes)
|
||||
: <TileType>[];
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
_apiKeyController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_isEditing ? 'Edit Provider' : 'Add Provider'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: _saveProvider,
|
||||
child: const Text('Save'),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _nameController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Provider Name',
|
||||
hintText: 'e.g., Custom Maps Inc.',
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.trim().isEmpty) {
|
||||
return 'Provider name is required';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _apiKeyController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'API Key (Optional)',
|
||||
hintText: 'Enter API key if required by tile types',
|
||||
),
|
||||
obscureText: true,
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Tile Types',
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: _addTileType,
|
||||
icon: const Icon(Icons.add),
|
||||
label: const Text('Add Type'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (_tileTypes.isEmpty)
|
||||
const Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Text('No tile types configured'),
|
||||
),
|
||||
)
|
||||
else
|
||||
..._tileTypes.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
final tileType = entry.value;
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
child: ListTile(
|
||||
title: Text(tileType.name),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(tileType.urlTemplate),
|
||||
Text(
|
||||
tileType.attribution,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () => _editTileType(index),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: _tileTypes.length > 1
|
||||
? () => _deleteTileType(index)
|
||||
: null, // Can't delete last tile type
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () => _editTileType(index),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _addTileType() {
|
||||
_showTileTypeDialog();
|
||||
}
|
||||
|
||||
void _editTileType(int index) {
|
||||
_showTileTypeDialog(tileType: _tileTypes[index], index: index);
|
||||
}
|
||||
|
||||
void _deleteTileType(int index) {
|
||||
if (_tileTypes.length <= 1) return;
|
||||
|
||||
setState(() {
|
||||
_tileTypes.removeAt(index);
|
||||
});
|
||||
}
|
||||
|
||||
void _showTileTypeDialog({TileType? tileType, int? index}) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => _TileTypeDialog(
|
||||
tileType: tileType,
|
||||
onSave: (newTileType) {
|
||||
setState(() {
|
||||
if (index != null) {
|
||||
_tileTypes[index] = newTileType;
|
||||
} else {
|
||||
_tileTypes.add(newTileType);
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _saveProvider() {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
if (_tileTypes.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('At least one tile type is required')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final providerId = widget.provider?.id ?? DateTime.now().millisecondsSinceEpoch.toString();
|
||||
final provider = TileProvider(
|
||||
id: providerId,
|
||||
name: _nameController.text.trim(),
|
||||
apiKey: _apiKeyController.text.trim().isEmpty ? null : _apiKeyController.text.trim(),
|
||||
tileTypes: _tileTypes,
|
||||
);
|
||||
|
||||
context.read<AppState>().addOrUpdateTileProvider(provider);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
|
||||
class _TileTypeDialog extends StatefulWidget {
|
||||
final TileType? tileType;
|
||||
final Function(TileType) onSave;
|
||||
|
||||
const _TileTypeDialog({
|
||||
required this.onSave,
|
||||
this.tileType,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_TileTypeDialog> createState() => _TileTypeDialogState();
|
||||
}
|
||||
|
||||
class _TileTypeDialogState extends State<_TileTypeDialog> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late final TextEditingController _nameController;
|
||||
late final TextEditingController _urlController;
|
||||
late final TextEditingController _attributionController;
|
||||
Uint8List? _previewTile;
|
||||
bool _isLoadingPreview = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final tileType = widget.tileType;
|
||||
_nameController = TextEditingController(text: tileType?.name ?? '');
|
||||
_urlController = TextEditingController(text: tileType?.urlTemplate ?? '');
|
||||
_attributionController = TextEditingController(text: tileType?.attribution ?? '');
|
||||
_previewTile = tileType?.previewTile;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
_urlController.dispose();
|
||||
_attributionController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(widget.tileType != null ? 'Edit Tile Type' : 'Add Tile Type'),
|
||||
content: SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _nameController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Name',
|
||||
hintText: 'e.g., Satellite',
|
||||
),
|
||||
validator: (value) => value?.trim().isEmpty == true ? 'Name is required' : null,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _urlController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'URL Template',
|
||||
hintText: 'https://example.com/{z}/{x}/{y}.png',
|
||||
),
|
||||
validator: (value) {
|
||||
if (value?.trim().isEmpty == true) return 'URL template is required';
|
||||
if (!value!.contains('{z}') || !value.contains('{x}') || !value.contains('{y}')) {
|
||||
return 'URL must contain {z}, {x}, and {y} placeholders';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _attributionController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Attribution',
|
||||
hintText: '© Map Provider',
|
||||
),
|
||||
validator: (value) => value?.trim().isEmpty == true ? 'Attribution is required' : null,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
TextButton.icon(
|
||||
onPressed: _isLoadingPreview ? null : _fetchPreviewTile,
|
||||
icon: _isLoadingPreview
|
||||
? const SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Icon(Icons.preview),
|
||||
label: const Text('Fetch Preview'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
if (_previewTile != null)
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey),
|
||||
),
|
||||
child: Image.memory(_previewTile!, fit: BoxFit.cover),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _saveTileType,
|
||||
child: const Text('Save'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _fetchPreviewTile() async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
setState(() {
|
||||
_isLoadingPreview = true;
|
||||
});
|
||||
|
||||
try {
|
||||
// Use a sample tile (zoom 10, somewhere in the world)
|
||||
final url = _urlController.text
|
||||
.replaceAll('{z}', '10')
|
||||
.replaceAll('{x}', '512')
|
||||
.replaceAll('{y}', '384');
|
||||
|
||||
final response = await http.get(Uri.parse(url));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
setState(() {
|
||||
_previewTile = response.bodyBytes;
|
||||
});
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Preview tile loaded successfully')),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw Exception('HTTP ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Failed to fetch preview: $e')),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoadingPreview = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _saveTileType() {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
|
||||
final tileTypeId = widget.tileType?.id ??
|
||||
'${_nameController.text.toLowerCase().replaceAll(' ', '_')}_${DateTime.now().millisecondsSinceEpoch}';
|
||||
|
||||
final tileType = TileType(
|
||||
id: tileTypeId,
|
||||
name: _nameController.text.trim(),
|
||||
urlTemplate: _urlController.text.trim(),
|
||||
attribution: _attributionController.text.trim(),
|
||||
previewTile: _previewTile,
|
||||
);
|
||||
|
||||
widget.onSave(tileType);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
160
lib/screens/tile_provider_management_screen.dart
Normal file
160
lib/screens/tile_provider_management_screen.dart
Normal file
@@ -0,0 +1,160 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../app_state.dart';
|
||||
import '../models/tile_provider.dart';
|
||||
import 'tile_provider_editor_screen.dart';
|
||||
|
||||
class TileProviderManagementScreen extends StatelessWidget {
|
||||
const TileProviderManagementScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final appState = context.watch<AppState>();
|
||||
final providers = appState.tileProviders;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Tile Providers'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () => _addProvider(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: providers.isEmpty
|
||||
? const Center(
|
||||
child: Text('No tile providers configured'),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: providers.length,
|
||||
itemBuilder: (context, index) {
|
||||
final provider = providers[index];
|
||||
final isSelected = appState.selectedTileProvider?.id == provider.id;
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
provider.name,
|
||||
style: TextStyle(
|
||||
fontWeight: isSelected ? FontWeight.bold : null,
|
||||
),
|
||||
),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('${provider.tileTypes.length} tile types'),
|
||||
if (provider.apiKey?.isNotEmpty == true)
|
||||
const Text(
|
||||
'API Key configured',
|
||||
style: TextStyle(
|
||||
fontStyle: FontStyle.italic,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
if (!provider.isUsable)
|
||||
Text(
|
||||
'Needs API key',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: isSelected
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.surfaceVariant,
|
||||
child: Icon(
|
||||
Icons.map,
|
||||
color: isSelected
|
||||
? Theme.of(context).colorScheme.onPrimary
|
||||
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
trailing: providers.length > 1
|
||||
? PopupMenuButton<String>(
|
||||
onSelected: (action) {
|
||||
switch (action) {
|
||||
case 'edit':
|
||||
_editProvider(context, provider);
|
||||
break;
|
||||
case 'delete':
|
||||
_deleteProvider(context, provider);
|
||||
break;
|
||||
}
|
||||
},
|
||||
itemBuilder: (context) => [
|
||||
const PopupMenuItem(
|
||||
value: 'edit',
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.edit),
|
||||
SizedBox(width: 8),
|
||||
Text('Edit'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const PopupMenuItem(
|
||||
value: 'delete',
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.delete),
|
||||
SizedBox(width: 8),
|
||||
Text('Delete'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const Icon(Icons.lock, size: 16), // Can't delete last provider
|
||||
onTap: () => _editProvider(context, provider),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _addProvider(BuildContext context) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const TileProviderEditorScreen(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _editProvider(BuildContext context, TileProvider provider) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => TileProviderEditorScreen(provider: provider),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _deleteProvider(BuildContext context, TileProvider provider) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Delete Provider'),
|
||||
content: Text('Are you sure you want to delete "${provider.name}"?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.read<AppState>().deleteTileProvider(provider.id);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Delete'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -60,26 +60,7 @@ class SettingsState extends ChangeNotifier {
|
||||
return types;
|
||||
}
|
||||
|
||||
/// Legacy getter for backward compatibility
|
||||
@Deprecated('Use selectedTileType instead')
|
||||
TileProviderType get tileProvider {
|
||||
// Map current selection to legacy enum for compatibility
|
||||
final selected = selectedTileType;
|
||||
if (selected == null) return TileProviderType.osmStreet;
|
||||
|
||||
switch (selected.id) {
|
||||
case 'osm_street':
|
||||
return TileProviderType.osmStreet;
|
||||
case 'google_hybrid':
|
||||
return TileProviderType.googleHybrid;
|
||||
case 'esri_satellite':
|
||||
return TileProviderType.arcgisSatellite;
|
||||
case 'mapbox_satellite':
|
||||
return TileProviderType.mapboxSatellite;
|
||||
default:
|
||||
return TileProviderType.osmStreet;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Initialize settings from preferences
|
||||
Future<void> init() async {
|
||||
@@ -230,26 +211,5 @@ class SettingsState extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Legacy setter for backward compatibility
|
||||
@Deprecated('Use setSelectedTileType instead')
|
||||
Future<void> setTileProvider(TileProviderType provider) async {
|
||||
// Map legacy enum to new tile type ID
|
||||
String tileTypeId;
|
||||
switch (provider) {
|
||||
case TileProviderType.osmStreet:
|
||||
tileTypeId = 'osm_street';
|
||||
break;
|
||||
case TileProviderType.googleHybrid:
|
||||
tileTypeId = 'google_hybrid';
|
||||
break;
|
||||
case TileProviderType.arcgisSatellite:
|
||||
tileTypeId = 'esri_satellite';
|
||||
break;
|
||||
case TileProviderType.mapboxSatellite:
|
||||
tileTypeId = 'mapbox_satellite';
|
||||
break;
|
||||
}
|
||||
|
||||
await setSelectedTileType(tileTypeId);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user