Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
1 change: 1 addition & 0 deletions ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
81 changes: 74 additions & 7 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,94 @@ import 'package:flutter/material.dart';
import 'package:flutter_weather/src/screens/weather_screen.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_weather/src/themes.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
BlocSupervisor().delegate = SimpleBlocDelegate();
runApp(MyApp());
runApp(AppStateContainer(child: WeatherApp()));
}

class MyApp extends StatelessWidget {
class SimpleBlocDelegate extends BlocDelegate {
@override
onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
print(transition);
}
}

class WeatherApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Weather App',
theme: Themes.dark,
theme: AppStateContainer.of(context).theme,
home: WeatherScreen(),
);
}
}

class SimpleBlocDelegate extends BlocDelegate {
/// top level widget to hold application state
/// state is passed down with an inherited widget
class AppStateContainer extends StatefulWidget {
final Widget child;

AppStateContainer({@required this.child});

@override
onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
print(transition);
_AppStateContainerState createState() => _AppStateContainerState();

static _AppStateContainerState of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(_InheritedStateContainer)
as _InheritedStateContainer)
.data;
}
}

class _AppStateContainerState extends State<AppStateContainer> {
ThemeData _theme = Themes.getTheme(Themes.DARK_THEME_CODE);

@override
initState() {
super.initState();
SharedPreferences.getInstance().then((sharedPref) {
int themeCode =
sharedPref.getInt(Themes.SHARED_PREF_KEY) ?? Themes.DARK_THEME_CODE;
setState(() {
this._theme = Themes.getTheme(themeCode);
});
});
}

@override
Widget build(BuildContext context) {
print(theme.accentColor);
return _InheritedStateContainer(
data: this,
child: widget.child,
);
}

ThemeData get theme => _theme;

updateTheme(int themeCode) {
setState(() {
_theme = Themes.getTheme(themeCode);
});
SharedPreferences.getInstance().then((sharedPref) {
sharedPref.setInt(Themes.SHARED_PREF_KEY, themeCode);
});
}
}

class _InheritedStateContainer extends InheritedWidget {
final _AppStateContainerState data;

const _InheritedStateContainer({
Key key,
@required this.data,
@required Widget child,
}) : super(key: key, child: child);

@override
bool updateShouldNotify(_InheritedStateContainer oldWidget) => true;
}
99 changes: 69 additions & 30 deletions lib/src/screens/weather_screen.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter_weather/main.dart';
import 'package:flutter_weather/src/api/weather_api_client.dart';
import 'package:flutter_weather/src/bloc/weather_bloc.dart';
import 'package:flutter_weather/src/bloc/weather_event.dart';
import 'package:flutter_weather/src/bloc/weather_state.dart';
import 'package:flutter_weather/src/repository/weather_repository.dart';
import 'package:flutter_weather/src/api/api_keys.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_weather/src/themes.dart';
import 'package:flutter_weather/src/widgets/weather_widget.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';

enum OptionsMenu { changeCity, nightMode, lightMode }

class WeatherScreen extends StatefulWidget {
final WeatherRepository weatherRepository = WeatherRepository(
weatherApiClient: WeatherApiClient(
Expand All @@ -18,62 +22,73 @@ class WeatherScreen extends StatefulWidget {
_WeatherScreenState createState() => _WeatherScreenState();
}

class _WeatherScreenState extends State<WeatherScreen> with TickerProviderStateMixin {
class _WeatherScreenState extends State<WeatherScreen>
with TickerProviderStateMixin {
WeatherBloc _weatherBloc;
String _cityName = 'bengaluru';
AnimationController _fadeController;
Animation<double> _fadeAnimation;


@override
void initState() {
super.initState();
_weatherBloc = WeatherBloc(weatherRepository: widget.weatherRepository);
_weatherBloc.dispatch(FetchWeather(cityName: _cityName));
_fadeController = AnimationController(
duration: const Duration(milliseconds: 1000), vsync: this);
_fadeAnimation = CurvedAnimation(parent: _fadeController, curve: Curves.easeIn);
_fadeAnimation =
CurvedAnimation(parent: _fadeController, curve: Curves.easeIn);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColor,
backgroundColor: AppStateContainer.of(context).theme.primaryColor,
elevation: 0,
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
DateFormat('EEEE, MMMM yyyy').format(DateTime.now()),
style: TextStyle(
color: Theme.of(context).accentColor.withAlpha(80),
color: AppStateContainer.of(context)
.theme
.accentColor
.withAlpha(80),
fontSize: 14),
)
],
),
actions: <Widget>[
GestureDetector(

child: Padding(
padding: EdgeInsets.all(20),
PopupMenuButton<OptionsMenu>(
child: Icon(
Icons.public,
color: Theme.of(context).accentColor,
Icons.more_vert,
color: AppStateContainer.of(context).theme.accentColor,
),
),
onTap: () {
this.showCityChangeDialog();
},
)
onSelected: this._onOptionMenuItemSelected,
itemBuilder: (context) => <PopupMenuEntry<OptionsMenu>>[
PopupMenuItem<OptionsMenu>(
value: OptionsMenu.changeCity,
child: Text("change city"),
),
PopupMenuItem<OptionsMenu>(
value: OptionsMenu.nightMode,
child: Text("night mode"),
),
PopupMenuItem<OptionsMenu>(
value: OptionsMenu.lightMode,
child: Text("light mode"),
),
])
],
),
backgroundColor: Colors.white,
body: Material(
color: Theme.of(context).accentColor,
child: Container(
constraints: BoxConstraints.expand(),
decoration: BoxDecoration(color: Theme.of(context).primaryColor),
decoration: BoxDecoration(
color: AppStateContainer.of(context).theme.primaryColor),
child: FadeTransition(
opacity: _fadeAnimation,
child: BlocBuilder(
Expand All @@ -87,10 +102,12 @@ class _WeatherScreenState extends State<WeatherScreen> with TickerProviderStateM
);
} else if (weatherState is WeatherError ||
weatherState is WeatherEmpty) {
String errorText = 'There was an error fetching weather data';
if(weatherState is WeatherError){
if(weatherState.errorCode == 404){
errorText = 'We have trouble fetching weather for $_cityName';
String errorText =
'There was an error fetching weather data';
if (weatherState is WeatherError) {
if (weatherState.errorCode == 404) {
errorText =
'We have trouble fetching weather for $_cityName';
}
}
return Column(
Expand All @@ -106,14 +123,18 @@ class _WeatherScreenState extends State<WeatherScreen> with TickerProviderStateM
),
Text(
errorText,
style:
TextStyle(color: Theme.of(context).accentColor),
style: TextStyle(
color: AppStateContainer.of(context)
.theme
.accentColor),
),
FlatButton(
child: Text(
"Try Again",
style:
TextStyle(color: Theme.of(context).accentColor),
style: TextStyle(
color: AppStateContainer.of(context)
.theme
.accentColor),
),
onPressed: _fetchWeather,
)
Expand All @@ -122,7 +143,8 @@ class _WeatherScreenState extends State<WeatherScreen> with TickerProviderStateM
} else if (weatherState is WeatherLoading) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Theme.of(context).primaryColor,
backgroundColor:
AppStateContainer.of(context).theme.primaryColor,
),
);
}
Expand All @@ -132,18 +154,19 @@ class _WeatherScreenState extends State<WeatherScreen> with TickerProviderStateM
));
}

void showCityChangeDialog() {
void _showCityChangeDialog() {
showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Change city'),
backgroundColor: Colors.white,
title: Text('Change city', style: TextStyle(color: Colors.black)),
actions: <Widget>[
FlatButton(
child: Text(
'ok',
style: TextStyle(color: Theme.of(context).primaryColor),
style: TextStyle(color: Colors.black),
),
onPressed: () {
_fetchWeather();
Expand All @@ -158,12 +181,28 @@ class _WeatherScreenState extends State<WeatherScreen> with TickerProviderStateM
},
decoration: InputDecoration(
hintText: 'Enter the name of your city',
hintStyle: TextStyle(color: Colors.black),
),
style: TextStyle(color: Colors.black),
),
);
});
}

_onOptionMenuItemSelected(OptionsMenu item) {
switch (item) {
case OptionsMenu.changeCity:
this._showCityChangeDialog();
break;
case OptionsMenu.nightMode:
AppStateContainer.of(context).updateTheme(Themes.DARK_THEME_CODE);
break;
case OptionsMenu.lightMode:
AppStateContainer.of(context).updateTheme(Themes.LIGHT_THEME_CODE);
break;
}
}

_fetchWeather() {
_weatherBloc.dispatch(FetchWeather(cityName: _cityName));
}
Expand Down
17 changes: 15 additions & 2 deletions lib/src/themes.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import 'package:flutter/material.dart';

class Themes {
static final dark = ThemeData(
static const SHARED_PREF_KEY = "theme_code";
static const DARK_THEME_CODE = 0;
static const LIGHT_THEME_CODE = 1;

static final _dark = ThemeData(
primarySwatch: MaterialColor(
Colors.black.value,
const <int, Color>{
Expand All @@ -19,7 +23,8 @@ class Themes {
),
accentColor: Colors.white,
);
static final light = ThemeData(

static final _light = ThemeData(
primarySwatch: MaterialColor(
Colors.white.value,
const <int, Color>{
Expand All @@ -37,4 +42,12 @@ class Themes {
),
accentColor: Colors.black,
);

static ThemeData getTheme(int code) {
if(code == LIGHT_THEME_CODE){
return _light;
}
return _dark;
}

}
2 changes: 1 addition & 1 deletion lib/src/widgets/forecast_horizontal_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ForecastHorizontal extends StatelessWidget {
padding: const EdgeInsets.only(left: 10, right: 10),
child: Center(
child: ValueTile(
DateFormat('h aa').format(
DateFormat('E, ha').format(
DateTime.fromMillisecondsSinceEpoch(item.time * 1000)),
'${item.temperature.celsius.round()}°',
iconData: item.getIconData(),
Expand Down
Loading