
Комментарии 1
Зацените код
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(
ChangeNotifierProvider(
create: (context) => GalleryProvider(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Geo Album',
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: Colors.grey[900],
appBarTheme: AppBarTheme(
backgroundColor: Colors.grey[900],
elevation: 2,
centerTitle: true,
iconTheme: IconThemeData(color: Colors.white),
),
cardTheme: CardTheme(
color: Colors.grey[850],
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/settings': (context) => SettingsScreen(),
},
);
}
}
class SettingsScreen extends StatefulWidget {
@override
State createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State {
// Состояние хранится прямо здесь, без провайдеров
String selectedMapType = 'OpenStreetMap';
bool isLoading = false;
String getMapUrl(String type) {
switch (type) {
case 'Satellite':
return 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}';
case 'Terrain':
return 'https://tile.opentopomap.org/{z}/{x}/{y}.png';
default:
return 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
}
}
@override
Widget build(BuildContext context) {
final galleryProvider = Provider.of(context);
final screenWidth = MediaQuery.of(context).size.width;
final isTablet = screenWidth > 600;
final padding = isTablet ? 24.0 : 16.0;
final fontSize = isTablet ? 20.0 : 18.0;
final buttonHeight = isTablet ? 56.0 : 48.0;
return Scaffold(
appBar: AppBar(
title: Text('Настройки'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
actions: [
IconButton(
icon: Icon(Icons.info_outline),
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('О приложении'),
content: Text(
'Geo Album v1.0.0\n\n'
'Приложение для просмотра фотографий с геометками\n\n'
'Всего фото: ${galleryProvider.images.length}'
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text('OK'),
),
],
),
);
},
),
],
),
body: Container(
child: ListView(
padding: EdgeInsets.all(padding),
children: [
// КАРТОЧКА: Выбор типа карты
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Тип карты',
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
RadioListTile(
title: Text('OpenStreetMap'),
subtitle: Text('Стандартная карта'),
value: 'OpenStreetMap',
groupValue: selectedMapType,
onChanged: (value) {
setState(() {
selectedMapType = value!;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Карта изменена на $value'),
duration: Duration(seconds: 2),
),
);
},
),
RadioListTile(
title: Text('Satellite'),
subtitle: Text('Спутниковый вид'),
value: 'Satellite',
groupValue: selectedMapType,
onChanged: (value) {
setState(() {
selectedMapType = value!;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Карта изменена на $value'),
duration: Duration(seconds: 2),
),
);
},
),
RadioListTile(
title: Text('Terrain'),
subtitle: Text('Рельеф местности'),
value: 'Terrain',
groupValue: selectedMapType,
onChanged: (value) {
setState(() {
selectedMapType = value!;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Карта изменена на $value'),
duration: Duration(seconds: 2),
),
);
},
),
SizedBox(height: 8),
Container( // ОШИБКА 3: ещё один лишний Container
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey[800],
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Текущий URL:',
style: TextStyle(
fontSize: 12,
color: Colors.grey[400],
),
),
SizedBox(height: 4),
Text(
getMapUrl(selectedMapType),
style: TextStyle(
fontSize: 11,
fontFamily: 'monospace',
color: Colors.orange,
),
),
],
),
),
],
),
),
),
SizedBox(height: 24),
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Управление кэшем',
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
ElevatedButton.icon(
icon: Icon(Icons.map_outlined),
label: Text('Очистить кэш карты'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
minimumSize: Size(double.infinity, buttonHeight),
),
onPressed: isLoading ? null : () async {
setState(() {
isLoading = true;
});
await Future.delayed(Duration(seconds: 1));
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Кэш карты очищен')),
);
},
),
SizedBox(height: 12),
ElevatedButton.icon(
icon: Icon(Icons.image_outlined),
label: Text('Очистить миниатюры'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
minimumSize: Size(double.infinity, buttonHeight),
),
onPressed: isLoading ? null : () async {
setState(() {
isLoading = true;
});
await Future.delayed(Duration(seconds: 1));
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Миниатюры очищены')),
);
},
),
if (isLoading == true)
Padding(
padding: EdgeInsets.only(top: 16),
child: Center(
child: CircularProgressIndicator(),
),
),
],
),
),
),
SizedBox(height: 24),
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Статистика',
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Всего фото',
style: TextStyle(color: Colors.grey[400]),
),
Text(
'${galleryProvider.images.length}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'С геометками',
style: TextStyle(color: Colors.grey[400]),
),
Text(
'${galleryProvider.images.where((img) => img.latitude != null).length}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Без геометок',
style: TextStyle(color: Colors.grey[400]),
),
Text(
'${galleryProvider.images.length - galleryProvider.images.where((img) => img.latitude != null).length}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
SizedBox(height: 16),
Divider(),
SizedBox(height: 8),
Text(
'Адаптивность',
style: TextStyle(color: Colors.grey[400]),
),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Тип устройства'),
Text(
isTablet ? 'Планшет' : 'Телефон',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Ширина экрана'),
Text(
'${screenWidth.toInt()} px',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
],
),
),
),
SizedBox(height: isTablet ? 48 : 24),
],
),
),
);
}
}
Flutter 3.38 — Что нового во Flutter?