parent
f238c1cf0f
commit
ddda7ab779
@ -0,0 +1,45 @@
|
||||
import 'package:flutter/Material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:justmusic/values/constants.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
class CityListComponent extends StatelessWidget {
|
||||
final Tuple2<String, String> location;
|
||||
const CityListComponent({Key? key, required this.location}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: RichText(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
text: TextSpan(children: [
|
||||
TextSpan(
|
||||
text: location.item2 + ", ",
|
||||
style: GoogleFonts.plusJakartaSans(
|
||||
color: grayText,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 17),
|
||||
),
|
||||
TextSpan(
|
||||
text: location.item1,
|
||||
style: GoogleFonts.plusJakartaSans(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 17),
|
||||
),
|
||||
])),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/Material.dart';
|
||||
|
||||
import '../components/city_list_component.dart';
|
||||
import '../services/GeoApi.dart';
|
||||
import '../values/constants.dart';
|
||||
|
||||
class SearchCityScreen extends StatefulWidget {
|
||||
final Function callback;
|
||||
const SearchCityScreen({Key? key, required this.callback}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SearchCityScreen> createState() => _SearchCityScreenState();
|
||||
}
|
||||
|
||||
class _SearchCityScreenState extends State<SearchCityScreen> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
final GeoApi api = GeoApi();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double screenHeight = MediaQuery.of(context).size.height;
|
||||
return BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: 60.0,
|
||||
sigmaY: 60.0,
|
||||
),
|
||||
child: Container(
|
||||
color: bgAppBar.withOpacity(0.5),
|
||||
height: screenHeight - 50,
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Align(
|
||||
child: Container(
|
||||
width: 60,
|
||||
height: 5,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFF3A3A3A).withOpacity(0.6),
|
||||
borderRadius: BorderRadius.circular(20))),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Flexible(
|
||||
child: ScrollConfiguration(
|
||||
behavior: ScrollBehavior().copyWith(scrollbars: true),
|
||||
child: FutureBuilder(
|
||||
future: api.getNearbyCities(),
|
||||
builder:
|
||||
(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return ListView.builder(
|
||||
physics: const BouncingScrollPhysics(
|
||||
decelerationRate: ScrollDecelerationRate.fast),
|
||||
controller: _scrollController,
|
||||
itemCount: snapshot.data.length,
|
||||
itemBuilder: (context, index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
widget.callback(snapshot.data[index]);
|
||||
},
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: CityListComponent(
|
||||
location: snapshot.data[index],
|
||||
),
|
||||
));
|
||||
});
|
||||
} else {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: grayColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
class GeoApi {
|
||||
final String apiKey = "85a2724ad38b3994c2b7ebe1d239bbff";
|
||||
Future<List<Tuple2<String, String>>?> getNearbyCities() async {
|
||||
try {
|
||||
LocationPermission permission = await Geolocator.checkPermission();
|
||||
bool serviceEnabled;
|
||||
|
||||
// Test if location services are enabled.
|
||||
serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!serviceEnabled) {
|
||||
// Location services are not enabled don't continue
|
||||
// accessing the position and request users of the
|
||||
// App to enable the location services.
|
||||
return Future.error('Location services are disabled.');
|
||||
}
|
||||
|
||||
permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
return Future.error('Location permissions are denied');
|
||||
}
|
||||
}
|
||||
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
return Future.error(
|
||||
'Location permissions are permanently denied, we cannot request permissions.');
|
||||
}
|
||||
|
||||
Position position = await Geolocator.getCurrentPosition(
|
||||
desiredAccuracy: LocationAccuracy.high);
|
||||
String apiUrl =
|
||||
'http://api.openweathermap.org/data/2.5/find?lat=${position.latitude}&lon=${position.longitude}&cnt=10&appid=$apiKey';
|
||||
var response = await http.get(Uri.parse(apiUrl));
|
||||
if (response.statusCode == 200) {
|
||||
var data = json.decode(response.body);
|
||||
List<dynamic> cities = data['list'];
|
||||
List<Tuple2<String, String>> cityInfo = cities.map((city) {
|
||||
String cityName = city['name'] as String;
|
||||
String countryName = city['sys']['country'] as String;
|
||||
return Tuple2(cityName, countryName);
|
||||
}).toList();
|
||||
return cityInfo;
|
||||
} else {
|
||||
print('Failed to fetch data');
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error: $e');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class Tuple {}
|
Loading…
Reference in new issue