Skip to content

Commit 5fb7354

Browse files
author
Ananthu P Kanive
authored
Merge pull request #11 from LonelyCpp/dev
Dev
2 parents 0acdf5f + 57eb70f commit 5fb7354

File tree

13 files changed

+165
-21
lines changed

13 files changed

+165
-21
lines changed

android/app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
22
package="com.ananthu.flutter_weather">
33

4+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
5+
46
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
57
calls FlutterMain.startInitialization(this); in its onCreate method.
68
In most cases you can leave this as-is, but you if you want to provide

android/gradle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
org.gradle.jvmargs=-Xmx1536M
2+
android.useAndroidX=true
3+
android.enableJetifier=true

ios/Podfile.lock

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
11
PODS:
22
- Flutter (1.0.0)
3+
- geolocator (5.0.1):
4+
- Flutter
5+
- google_api_availability (2.0.1):
6+
- Flutter
7+
- location_permissions (2.0.2):
8+
- Flutter
9+
- permission_handler (3.1.0):
10+
- Flutter
311
- shared_preferences (0.0.1):
412
- Flutter
513

614
DEPENDENCIES:
715
- Flutter (from `.symlinks/flutter/ios`)
16+
- geolocator (from `.symlinks/plugins/geolocator/ios`)
17+
- google_api_availability (from `.symlinks/plugins/google_api_availability/ios`)
18+
- location_permissions (from `.symlinks/plugins/location_permissions/ios`)
19+
- permission_handler (from `.symlinks/plugins/permission_handler/ios`)
820
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
921

1022
EXTERNAL SOURCES:
1123
Flutter:
1224
:path: ".symlinks/flutter/ios"
25+
geolocator:
26+
:path: ".symlinks/plugins/geolocator/ios"
27+
google_api_availability:
28+
:path: ".symlinks/plugins/google_api_availability/ios"
29+
location_permissions:
30+
:path: ".symlinks/plugins/location_permissions/ios"
31+
permission_handler:
32+
:path: ".symlinks/plugins/permission_handler/ios"
1333
shared_preferences:
1434
:path: ".symlinks/plugins/shared_preferences/ios"
1535

1636
SPEC CHECKSUMS:
1737
Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296
38+
geolocator: ac98a5fcdddd7fcbae404b136ab9c33bf08739c7
39+
google_api_availability: cd29400b9c6eb73b0978f609f0ad66f41dfa90b4
40+
location_permissions: 974d8fbc3ec5fed16908492a5e03bcb3372fcfd9
41+
permission_handler: a1b8c0f8c83b4e7201f9c04b9aef09979cc97f60
1842
shared_preferences: 5a1d487c427ee18fcd3ea1f2a131569481834b53
1943

2044
PODFILE CHECKSUM: aff02bfeed411c636180d6812254b2daeea14d09

ios/Runner/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
44
<dict>
5+
<key>NSLocationWhenInUseUsageDescription</key>
6+
<string>Your location will be used to determine the current weather</string>
57
<key>CFBundleDevelopmentRegion</key>
68
<string>en</string>
79
<key>CFBundleExecutable</key>

lib/main.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class _AppStateContainerState extends State<AppStateContainer> {
5454
int themeCode = Themes.DARK_THEME_CODE;
5555
TemperatureUnit temperatureUnit = TemperatureUnit.celsius;
5656

57+
5758
@override
5859
initState() {
5960
super.initState();
@@ -63,7 +64,7 @@ class _AppStateContainerState extends State<AppStateContainer> {
6364
Themes.DARK_THEME_CODE;
6465
temperatureUnit = TemperatureUnit.values[
6566
sharedPref.getInt(CONSTANTS.SHARED_PREF_KEY_TEMPERATURE_UNIT) ??
66-
TemperatureUnit.kelvin];
67+
TemperatureUnit.celsius.index];
6768
this._theme = Themes.getTheme(themeCode);
6869
});
6970
});
@@ -95,7 +96,7 @@ class _AppStateContainerState extends State<AppStateContainer> {
9596
this.temperatureUnit = unit;
9697
});
9798
SharedPreferences.getInstance().then((sharedPref) {
98-
sharedPref.setInt(CONSTANTS.SHARED_PREF_KEY_THEME, unit.index);
99+
sharedPref.setInt(CONSTANTS.SHARED_PREF_KEY_TEMPERATURE_UNIT, unit.index);
99100
});
100101
}
101102
}

lib/src/api/weather_api_client.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ class WeatherApiClient {
1313
: assert(httpClient != null),
1414
assert(apiKey != null);
1515

16+
Future<String> getCityNameFromLocation(
17+
{double latitude, double longitude}) async {
18+
final url =
19+
'$baseUrl/data/2.5/weather?lat=$latitude&lon=$longitude&appid=$apiKey';
20+
print('fetching $url');
21+
final res = await this.httpClient.get(url);
22+
if (res.statusCode != 200) {
23+
throw HTTPException(res.statusCode, "unable to fetch weather data");
24+
}
25+
final weatherJson = json.decode(res.body);
26+
return weatherJson['name'];
27+
}
28+
1629
Future<Weather> getWeatherData(String cityName) async {
1730
final url = '$baseUrl/data/2.5/weather?q=$cityName&appid=$apiKey';
1831
print('fetching $url');

lib/src/bloc/weather_bloc.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class WeatherBloc extends Bloc<WeatherEvent, WeatherState> {
2424
yield WeatherLoading();
2525
try {
2626
final Weather weather =
27-
await weatherRepository.getWeather(event.cityName);
27+
await weatherRepository.getWeather(event.cityName, latitude: event.latitude, longitude: event.longitude);
2828
yield WeatherLoaded(weather: weather);
2929
} catch (exception) {
3030
print(exception);

lib/src/bloc/weather_event.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import 'package:equatable/equatable.dart';
2-
import 'package:meta/meta.dart';
32

43
abstract class WeatherEvent extends Equatable {
54
WeatherEvent([List props = const []]) : super(props);
65
}
76

87
class FetchWeather extends WeatherEvent {
98
final String cityName;
9+
final double longitude;
10+
final double latitude;
1011

11-
FetchWeather({@required this.cityName})
12-
: assert(cityName != null),
13-
super([cityName]);
12+
FetchWeather({this.cityName, this.longitude, this.latitude})
13+
: assert(cityName != null || longitude != null || latitude != null),
14+
super([cityName, longitude, latitude]);
1415
}
16+

lib/src/repository/weather_repository.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ class WeatherRepository {
77
WeatherRepository({@required this.weatherApiClient})
88
: assert(weatherApiClient != null);
99

10-
Future<Weather> getWeather(String cityName) async {
10+
Future<Weather> getWeather(String cityName, {double latitude, double longitude}) async {
11+
if(cityName == null){
12+
cityName = await weatherApiClient.getCityNameFromLocation(latitude: latitude, longitude: longitude);
13+
}
1114
var weather = await weatherApiClient.getWeatherData(cityName);
1215
var weathers = await weatherApiClient.getForecast(cityName);
1316
weather.forecast = weathers;

lib/src/screens/weather_screen.dart

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
1010
import 'package:flutter_weather/src/widgets/weather_widget.dart';
1111
import 'package:http/http.dart' as http;
1212
import 'package:intl/intl.dart';
13+
import 'package:geolocator/geolocator.dart';
14+
import 'package:permission_handler/permission_handler.dart';
1315

1416
enum OptionsMenu { changeCity, settings }
1517

@@ -32,7 +34,9 @@ class _WeatherScreenState extends State<WeatherScreen>
3234
void initState() {
3335
super.initState();
3436
_weatherBloc = WeatherBloc(weatherRepository: widget.weatherRepository);
35-
_weatherBloc.dispatch(FetchWeather(cityName: _cityName));
37+
_fetchWeatherWithLocation().catchError((error) {
38+
_fetchWeatherWithCity();
39+
});
3640
_fadeController = AnimationController(
3741
duration: const Duration(milliseconds: 1000), vsync: this);
3842
_fadeAnimation =
@@ -49,7 +53,7 @@ class _WeatherScreenState extends State<WeatherScreen>
4953
mainAxisAlignment: MainAxisAlignment.center,
5054
children: <Widget>[
5155
Text(
52-
DateFormat('EEEE, MMMM yyyy').format(DateTime.now()),
56+
DateFormat('EEEE, d MMMM yyyy').format(DateTime.now()),
5357
style: TextStyle(
5458
color: AppStateContainer.of(context)
5559
.theme
@@ -90,6 +94,7 @@ class _WeatherScreenState extends State<WeatherScreen>
9094
bloc: _weatherBloc,
9195
builder: (_, WeatherState weatherState) {
9296
if (weatherState is WeatherLoaded) {
97+
this._cityName = weatherState.weather.cityName;
9398
_fadeController.reset();
9499
_fadeController.forward();
95100
return WeatherWidget(
@@ -131,7 +136,7 @@ class _WeatherScreenState extends State<WeatherScreen>
131136
.theme
132137
.accentColor),
133138
),
134-
onPressed: _fetchWeather,
139+
onPressed: _fetchWeatherWithCity,
135140
)
136141
],
137142
);
@@ -161,24 +166,37 @@ class _WeatherScreenState extends State<WeatherScreen>
161166
FlatButton(
162167
child: Text(
163168
'ok',
164-
style: TextStyle(color: Colors.black),
169+
style: TextStyle(color: Colors.black, fontSize: 16),
165170
),
166171
onPressed: () {
167-
_fetchWeather();
172+
_fetchWeatherWithCity();
168173
Navigator.of(context).pop();
169174
},
170-
)
175+
),
171176
],
172177
content: TextField(
173178
autofocus: true,
174179
onChanged: (text) {
175180
_cityName = text;
176181
},
177182
decoration: InputDecoration(
178-
hintText: 'Enter the name of your city',
179-
hintStyle: TextStyle(color: Colors.black),
180-
),
183+
hintText: 'Name of your city',
184+
hintStyle: TextStyle(color: Colors.black),
185+
suffixIcon: GestureDetector(
186+
onTap: () {
187+
_fetchWeatherWithLocation().catchError((error) {
188+
_fetchWeatherWithCity();
189+
});
190+
Navigator.of(context).pop();
191+
},
192+
child: Icon(
193+
Icons.my_location,
194+
color: Colors.black,
195+
size: 16,
196+
),
197+
)),
181198
style: TextStyle(color: Colors.black),
199+
cursorColor: Colors.black,
182200
),
183201
);
184202
});
@@ -195,7 +213,52 @@ class _WeatherScreenState extends State<WeatherScreen>
195213
}
196214
}
197215

198-
_fetchWeather() {
216+
_fetchWeatherWithCity() {
199217
_weatherBloc.dispatch(FetchWeather(cityName: _cityName));
200218
}
219+
220+
_fetchWeatherWithLocation() async {
221+
var permissionHandler = PermissionHandler();
222+
var permissionResult = await permissionHandler
223+
.requestPermissions([PermissionGroup.locationWhenInUse]);
224+
225+
switch (permissionResult[PermissionGroup.locationWhenInUse]) {
226+
case PermissionStatus.denied:
227+
case PermissionStatus.unknown:
228+
print('location permission denied');
229+
_showLocationDeniedDialog(permissionHandler);
230+
throw Error();
231+
}
232+
233+
Position position = await Geolocator()
234+
.getCurrentPosition(desiredAccuracy: LocationAccuracy.low);
235+
print(position);
236+
_weatherBloc.dispatch(FetchWeather(
237+
longitude: position.longitude, latitude: position.latitude));
238+
}
239+
240+
void _showLocationDeniedDialog(PermissionHandler permissionHandler) {
241+
showDialog(
242+
context: context,
243+
barrierDismissible: true,
244+
builder: (BuildContext context) {
245+
return AlertDialog(
246+
backgroundColor: Colors.white,
247+
title: Text('Location is disabled :(',
248+
style: TextStyle(color: Colors.black)),
249+
actions: <Widget>[
250+
FlatButton(
251+
child: Text(
252+
'Enable!',
253+
style: TextStyle(color: Colors.green, fontSize: 16),
254+
),
255+
onPressed: () {
256+
permissionHandler.openAppSettings().then((val) => print(val));
257+
Navigator.of(context).pop();
258+
},
259+
),
260+
],
261+
);
262+
});
263+
}
201264
}

0 commit comments

Comments
 (0)