Creating a UI to interact with the smart contract
- Create a new file named display_population.dart in the lib/ directory.
- Add the following content to the file:
Dart
import 'package:country_pickers/utils/utils.dart' ; import 'package:flutter/material.dart' ; import 'package:population/set_population.dart' ; import 'package:provider/provider.dart' ; import 'package:population/contract_linking.dart' ; class DisplayPopulation extends StatelessWidget { @override Widget build(BuildContext context) { final contractLink = Provider.of<ContractLinking>(context); return Scaffold( appBar: AppBar( title: Text( "Population On Blockchain" ), centerTitle: true , ), floatingActionButton: FloatingActionButton( child: Icon(Icons.edit), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => SetPopulation(), fullscreenDialog: true )); }, ), body: Container( padding: EdgeInsets.symmetric(horizontal: 20), child: Center( child: contractLink.isLoading ? CircularProgressIndicator() : SingleChildScrollView( child: Column( children: [ contractLink.countryName == "Unknown" ? Icon( Icons.error, size: 100, ) : Container( child: CountryPickerUtils.getDefaultFlagImage( CountryPickerUtils.getCountryByIsoCode( contractLink.countryName)), width: 250, height: 150, ), Padding( padding: const EdgeInsets.all(8.0), child: Text( "Country - ${contractLink.countryName}" , style: TextStyle( fontSize: 30, fontWeight: FontWeight.bold, color: Theme.of(context).accentColor), ), ), Padding( padding: const EdgeInsets.all(8.0), child: Text( "Population - ${contractLink.currentPopulation}" , style: TextStyle( fontSize: 25, fontWeight: FontWeight.bold, color: Theme.of(context).primaryColor)), ), contractLink.countryName == "Unknown" ? Text( "" ) : Padding( padding: const EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton.icon( onPressed: () { dialog(context, "Increase" ); }, icon: Icon(Icons.person_add_alt_1, size: 18), label: Text( "Increase" ), ), SizedBox( width: 15, ), ElevatedButton.icon( onPressed: () { if (contractLink.currentPopulation != "0" ) { dialog(context, "Decrease" ); } }, icon: Icon(Icons.person_remove_alt_1, size: 18), label: Text( "Decrease" ), ) ], ), ) ], ), ), ), ), ); } dialog(context, method) { final contractLink = Provider.of<ContractLinking>(context, listen: false ); TextEditingController countController = TextEditingController(); showDialog( context: context, builder: (_) => AlertDialog( title: method == "Increase" ? Text( "Increase Population" ) : Text( "Decrease Population" ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Current Population is ${contractLink.currentPopulation}" ), Padding( padding: EdgeInsets.only(top: 20.0), child: TextField( controller: countController, keyboardType: TextInputType.number, decoration: InputDecoration( border: OutlineInputBorder(), hintText: method == "Increase" ? "Increase Population By ..." : "Decrease Population By ..." , ), ), ) ], ), actions: <Widget>[ Row( children: [ TextButton( child: Text( "Cancel" ), onPressed: () { Navigator.of(context).pop(); }, ), TextButton( child: method == "Increase" ? Text( "Increase" ) : Text( "Decrease" ), onPressed: () { method == "Increase" ? contractLink.increasePopulation( int .parse(countController.text)) : contractLink.decreasePopulation( int .parse(countController.text)); Navigator.of(context).pop(); }, ), ], ) ], )); } } |
- Create another new file named set_population.dart in the lib/ directory.
- Add the following content to the file:
Dart
import 'package:country_pickers/country.dart' ; import 'package:country_pickers/country_pickers.dart' ; import 'package:flutter/material.dart' ; import 'package:population/contract_linking.dart' ; import 'package:provider/provider.dart' ; class SetPopulation extends StatefulWidget { @override _SetPopulationState createState() => _SetPopulationState(); } class _SetPopulationState extends State<SetPopulation> { Country _selectedCountry = CountryPickerUtils.getCountryByIsoCode( 'AF' ); TextEditingController countryNameController = TextEditingController(text: "Unknown" ); TextEditingController populationController = TextEditingController(); @override Widget build(BuildContext context) { final contractLink = Provider.of<ContractLinking>(context); return Scaffold( appBar: AppBar( title: Text( "Set Population" ), actions: [ TextButton( onPressed: () { contractLink.addData(countryNameController.text, BigInt.from( int .parse(populationController.text))); Navigator.pop(context); }, child: Text( "SAVE" , style: TextStyle( color: Colors.brown, fontWeight: FontWeight.bold), )) ], ), body: Container( child: Center( child: SingleChildScrollView( child: Column( children: [ stackCard(countryFlagPicker(), countryFlag()), stackCard(populationTextfield(), countryFlag()), ], ), ), ), )); } Widget stackCard(Widget widget1, Widget widget2) { return Stack( children: [ Padding( padding: EdgeInsets.only(bottom: 8.0, left: 54), child: Container( height: 120, child: Card( color: Colors.cyan, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [widget1], ), ), ), ), widget2 ], ); } Widget countryFlag() { return Positioned( top: 15, child: Container( width: 100, height: 100, decoration: BoxDecoration( shape: BoxShape.circle, ), child: CircleAvatar( backgroundColor: Colors.blueGrey, child: Container( width: 80, height: 50, child: CountryPickerUtils.getDefaultFlagImage(_selectedCountry))), ), ); } Widget countryFlagPicker() { return CountryPickerDropdown( underline: Container( height: 2, color: Colors.black, ), onValuePicked: (Country country) { print( "${country.name}" ); setState(() { _selectedCountry = country; countryNameController.text = country.isoCode; }); }, itemBuilder: (Country country) { return Row( children: <Widget>[ SizedBox(width: 48.0), CountryPickerUtils.getDefaultFlagImage(country), SizedBox(width: 8.0), Expanded( child: Text( country.name, style: TextStyle( color: Colors.brown, fontSize: 25, fontWeight: FontWeight.bold), )), ], ); }, icon: Icon( Icons.arrow_downward, color: Colors.white, size: 50, ), itemHeight: null, isExpanded: true , ); } Widget populationTextfield() { return Padding( padding: EdgeInsets.only(left: 48.0, right: 5), child: TextField( decoration: InputDecoration( filled: true , fillColor: Colors.black, focusedBorder: OutlineInputBorder(), labelText: "Population" , labelStyle: TextStyle(color: Colors.white), hintText: "Enter Population" , prefixIcon: Icon(Icons.person_pin_outlined)), keyboardType: TextInputType.number, controller: populationController, ), ); } } |
- Update the main.dart as :
Dart
import 'package:flutter/cupertino.dart' ; import 'package:flutter/material.dart' ; import 'package:population/display_population.dart' ; import 'package:provider/provider.dart' ; import 'package:population/contract_linking.dart' ; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider<ContractLinking>( create: (_) => ContractLinking(), child: MaterialApp( title: 'Population On Blockchain' , theme: ThemeData( brightness: Brightness.dark, primaryColor: Colors.cyan[400], accentColor: Colors.deepOrange[200]), home: DisplayPopulation(), ), ); } } |
Flutter and Blockchain – Population Dapp
Before checking out this article, Do take a look at Flutter and Blockchain – Hello World Dapp. This tutorial will take you through the process of building your mobile dapp – Population on Blockchain!
This tutorial is meant for those with a basic knowledge of Ethereum and smart contracts, who have some knowledge of the Flutter framework but are new to mobile dapps.
In this tutorial we will be covering:
- Setting up the development environment
- Creating a Truffle Project
- Writing the Smart Contract
- Compiling and Migrating the Smart Contract
- Testing the Smart Contract
- Contract linking with Flutter
- Creating a UI to interact with the smart contract
- Interacting with the complete Dapp
Description
Population on blockchain is a simple decentralized application, which will allow you to store a specific country population on the blockchain, you can increment as well as decrement the population based on the current condition of the country.
Output: