Leveraging Flutter Starter to build a Weather App

Hi there! Welcome to the third tutorial for building production-level apps with Flutter Starter. Flutter has been extremely popular with the dev community since its launch but you might have some trouble building production-level apps.

Flutter gives you a simple counter app upon installation which works if you are just starting out. However, in order to build a production-level app, you need State Management, API calls, Styleguide and common widgets. This code is frequently repeated in every project. Our idea was to write all the code and create the necessary files for all your projects. No more rewrites!

Check out our solution- Flutter Starter:

Flutter_Starter.gif

To learn more about this example, visit the Weather App page.

You can find the API URL in api-constants.dart:

Map<String, String> apiConstants = {
  "openweather": "https://api.openweathermap.org/data/2.5",
  "auth": "https://reqres.in/api"
};

We will use an open source Weather API.

In main.dart, we need a function getWeatherforCity. This will take the city name and fetch the weather details for that city.

This is a get method so we will call get from restapihandler as shown below:

static getWeatherforCity(String city) async {
    final response = await RestApiHandlerData.getData(
        '${apiConstants["openweather"]}/weather?q=$city&appid=$appId');
    return response;
  }

The API SDK is now a black box from which we will just call the method getWeatherforCity and it will return a JSON response.

Now that we have the data, it needs to be called, parsed and stored. Proceed to the shared folder which contains blocs, models and resources.

Resources:

The following code snippet in weather_ shows how API SDK functions will be called:

class WeatherApiRepository {
  Future fetchWeather(String city) async {
    final response = await ApiSdk.getWeatherforCity(city);
    return response;
  }
}

The weather_model.dart file in the models folder will store the data from the response:

class WeatherModel {
  dynamic lon;
  dynamic lat;
  String mainWeather;
  String description;
  String temp;
  String minTemp;
  String maxTemp;
  dynamic windSpeed;
  String countryCode;
  String cityName;
  String icon;

  WeatherModel.fromJson(Map<String, dynamic> parsedJson)
      : lon = parsedJson['coord']['lon'],
        lat = parsedJson['coord']['lat'],
        mainWeather = parsedJson['weather'][0]['main'],
        description = parsedJson['weather'][0]['description'],
                // Converted temperature to celcius, you can do this in **a*pp*** also.
        temp = (parsedJson['main']['temp'] - 273.15).toStringAsFixed(2),
        minTemp = (parsedJson['main']['temp_min'] - 273.15).toStringAsFixed(2),
        maxTemp = (parsedJson['main']['temp_max'] - 273.15).toStringAsFixed(2),
        windSpeed = parsedJson['wind']['speed'],
        countryCode = parsedJson['sys']['country'],
        cityName = parsedJson['name'],
        icon = parsedJson["weather"][0]["icon"];
}

In weather_bloc.dart file, we have used the resources to access the data and catch any errors:

final response = await weatherApiRepository.fetchWeather(event.city);
        if (response["cod"] != 200) {
          yield FailureState(
            message: response['message'],
            cod: response['cod'],
          );
        } else {
          WeatherModel weatherModel = WeatherModel.fromJson(response);
          yield SearchSuccessState(weatherModel: weatherModel);
        }
      } catch (e) {
        FailureState(message: e);
      }

In the main app, the WeatherPage widget needs to be wrapped with the Blocprovider widget:

body: BlocProvider(
    create: (context) => WeatherBloc(), 
    child: WeatherPage(),
),

Finally, use BlocBuilder in weather_page.dart to build the required widget according to the states:

BlocBuilder<WeatherBloc, WeatherStates>(builder: (context, state) {
            if (state is SearchSuccessState)
              return BuildWeather(
                weatherModel: state.weatherModel,
              );
            else if (state is InitialSuccessState)
              return Container();
            else if (state is LoadingState)
              return _buildLoadingScreen();
            else if (state is FailureState)
              return _buildErrorPage(state.message, state.cod);
            else
              return Container();
          }),

Your app should look like this:

Weather_app (2).gif

Congrats! You just successfully built a production-ready Weather App. Interested in more? Take a look at our guide to building a Hacker News app. If you would like to learn more about Flutter Starter, please visit our official documentation.

This article was written by Sumant Raj and Madhav B. Edited by Kavya V.

Flutter-Starter-Banner1.png

No Comments Yet