Flutter Wallpaper App (Pexels API) Published by on

Creating an app is kind of easy but managing it is harder than its deployment.in this blog we will focus on the creation of a wallpaper app using pexels wallpaper API.for more information about pexels API visite (https://www.pexels.com/api/).

Herein, covers modules like rxdart, setting an image as wallpaper using the platform dependent downloading image and giving specific permissions in android.

Install the following dependencies in pubspec.yaml before getting started!

dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 http: carousel_slider: ^1.4.1 transparent_image: ^1.0.0 esys_flutter_share: ^1.0.2 image_picker_saver: ^0.3.0 rxdart: ^0.23.1 permission_handler: '^4.4.0+hotfix.2' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 dependencies : flutter : sdk : flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons : ^ 0.1.2 http : carousel_slider : ^ 1.4.1 transparent_image : ^ 1.0.0 esys_flutter_share : ^ 1.0.2 image_picker_saver : ^ 0.3.0 rxdart : ^ 0.23.1 permission_handler : '^4.4.0+hotfix.2'

Pexels have strict guidelines as we can only make a limited number of request to the server (200 requests in hours and 20000 in a month).which is seriously low to full fill user needs, to optimize this we will use state management using rxdart. read a full guide on pexel API visite(https://www.pexels.com/api/documentation/)

Create new service.dart to render a rest request of Pexels API and assign return JSON String in the stream.

import 'package:http/http.dart' as http; import 'package:rxdart/rxdart.dart'; import 'package:permission_handler/permission_handler.dart'; class Service{ String initialUrl = ''; BehaviorSubject WallpaperUrl; BehaviorSubject Wallpapertourism; BehaviorSubject Wallpaper4k; BehaviorSubject Wallpaperhd; BehaviorSubject Wallpapernature; BehaviorSubject Wallpaperpeople; BehaviorSubject Wallpaperlove; BehaviorSubject Search; Random random; Service({this.initialUrl}){ Search = new BehaviorSubject.seeded(this.initialUrl); WallpaperUrl = new BehaviorSubject.seeded(this.initialUrl); Wallpapertourism = new BehaviorSubject.seeded(this.initialUrl); Wallpaper4k = new BehaviorSubject.seeded(this.initialUrl); Wallpaperhd = new BehaviorSubject.seeded(this.initialUrl); Wallpapernature = new BehaviorSubject.seeded(this.initialUrl); Wallpaperpeople = new BehaviorSubject.seeded(this.initialUrl); Wallpaperlove= new BehaviorSubject.seeded(this.initialUrl); } Stream get wallpaperJson => WallpaperUrl.stream; Stream get wallpapertourismJson => Wallpapertourism.stream; Stream get wallpaper4kJson => Wallpaper4k.stream; Stream get wallpaperhdJson => Wallpaperhd.stream; Stream get wallpapernatureJson => Wallpapernature.stream; Stream get wallpaperpeopleJson => Wallpaperpeople.stream; Stream get wallpaperlovejson=> Wallpaperlove.stream; Stream get searchJson=> Search.stream; //Make HTTP get Request Future httpRequest(qury) async{ var YOUR_API_KEY=''; var URL= 'https://api.pexels.com/v1/search? query='+qury+'&per_page=80&page=2'; var response = await http.get(URL,headers: {HttpHeaders.authorizationHeader: YOUR_API_KEY},); var response = await http.get(URL); if (response.statusCode == 200){ return response.body; } else { print('Request failed status: ${response.statusCode}.'); } } void fetch() async { httpReuest("tourism").then((value) { Wallpapertourism.sink.add(value); }); httpReuest("4k").then((value){ Wallpaper4k.sink.add(value); }); httpReuest("HD").then((value){ Wallpaperhd.sink.add(value); }); httpReuest("nature").then((value) { Wallpapernature.sink.add(value); }); httpReuest("people").then((value) { Wallpaperpeople.sink.add(value); }); httpReuest("love").then((value) { Wallpaperlove.sink.add(value); }); } void httpRequestSearch(qury) async{ var YOUR_API_KEY=''; var URL= "https://api.pexels.com/v1/search?query=${query}"; var response = await http.get(URL,headers: {HttpHeaders.authorizationHeader: YOUR_API_KEY},); var response = await http.get(URL); if (response.statusCode == 200){ return response.body; } else { print('Request failed status: ${response.statusCode}.'); } } Future checkAndGetPermission() async{ final PermissionStatus permission = await PermissionHandler().checkPermissionStatus(PermissionGroup.storage); if (permission != PermissionStatus.granted) { final Map permissions = await PermissionHandler().requestPermissions([PermissionGroup.storage]); if(permissions[PermissionGroup.storage] != PermissionStatus.granted){ return null; } } return true; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 import 'package:http/http.dart' as http ; import 'package:rxdart/rxdart.dart' ; import 'package:permission_handler/permission_handler.dart' ; class Service { String initialUrl = '' ; BehaviorSubject WallpaperUrl ; BehaviorSubject Wallpapertourism ; BehaviorSubject Wallpaper4k ; BehaviorSubject Wallpaperhd ; BehaviorSubject Wallpapernature ; BehaviorSubject Wallpaperpeople ; BehaviorSubject Wallpaperlove ; BehaviorSubject Search ; Random random ; Service ( { this . initialUrl } ) { Search = new BehaviorSubject . seeded ( this . initialUrl ) ; WallpaperUrl = new BehaviorSubject . seeded ( this . initialUrl ) ; Wallpapertourism = new BehaviorSubject . seeded ( this . initialUrl ) ; Wallpaper4k = new BehaviorSubject . seeded ( this . initialUrl ) ; Wallpaperhd = new BehaviorSubject . seeded ( this . initialUrl ) ; Wallpapernature = new BehaviorSubject . seeded ( this . initialUrl ) ; Wallpaperpeople = new BehaviorSubject . seeded ( this . initialUrl ) ; Wallpaperlove = new BehaviorSubject . seeded ( this . initialUrl ) ; } Stream get wallpaperJson = > WallpaperUrl . stream ; Stream get wallpapertourismJson = > Wallpapertourism . stream ; Stream get wallpaper4kJson = > Wallpaper4k . stream ; Stream get wallpaperhdJson = > Wallpaperhd . stream ; Stream get wallpapernatureJson = > Wallpapernature . stream ; Stream get wallpaperpeopleJson = > Wallpaperpeople . stream ; Stream get wallpaperlovejson = > Wallpaperlove . stream ; Stream get searchJson = > Search . stream ; //Make HTTP get Request Future httpRequest ( qury ) async { var YOUR_API_KEY = '' ; var URL = 'https://api.pexels.com/v1/search? query=' + qury + '&per_page=80&page=2' ; var response = await http . get ( URL , headers : { HttpHeaders . authorizationHeader : YOUR_API_KEY } , ) ; var response = await http . get ( URL ) ; if ( response . statusCode == 200 ) { return response . body ; } else { print ( 'Request failed status: ${response.statusCode}.' ) ; } } void fetch ( ) async { httpReuest ( "tourism" ) . then ( ( value ) { Wallpapertourism . sink . add ( value ) ; } ) ; httpReuest ( "4k" ) . then ( ( value ) { Wallpaper4k . sink . add ( value ) ; } ) ; httpReuest ( "HD" ) . then ( ( value ) { Wallpaperhd . sink . add ( value ) ; } ) ; httpReuest ( "nature" ) . then ( ( value ) { Wallpapernature . sink . add ( value ) ; } ) ; httpReuest ( "people" ) . then ( ( value ) { Wallpaperpeople . sink . add ( value ) ; } ) ; httpReuest ( "love" ) . then ( ( value ) { Wallpaperlove . sink . add ( value ) ; } ) ; } void httpRequestSearch ( qury ) async { var YOUR_API_KEY = '' ; var URL = "https://api.pexels.com/v1/search?query=${query}" ; var response = await http . get ( URL , headers : { HttpHeaders . authorizationHeader : YOUR_API_KEY } , ) ; var response = await http . get ( URL ) ; if ( response . statusCode == 200 ) { return response . body ; } else { print ( 'Request failed status: ${response.statusCode}.' ) ; } } Future checkAndGetPermission ( ) async { final PermissionStatus permission = await PermissionHandler ( ) . checkPermissionStatus ( PermissionGroup . storage ) ; if ( permission != PermissionStatus . granted ) { final Map permissions = await PermissionHandler ( ) . requestPermissions ( & #91;PermissionGroup.storage]); if ( permissions & #91;PermissionGroup.storage] != PermissionStatus.granted){ return null ; } } return true ; } }

In main.dart import service.dart to get the stream JSON and convert it into JSON.

import 'package:flutter/material.dart'; import 'service.dart'; import 'dart:math'; import 'detail.dart'; import 'search.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'dart:convert' as convert; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Wallpaper Search', theme: ThemeData.dark(), home: MyHomePage(title: 'Wallpaper Search'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { TabController _tabController; Service _service = new Service(); @override void initState() { _service.checkAndGetPermission(); _service.fetch(); _tabController = new TabController(vsync: this, initialIndex: 0, length: 6); // TODO: implement initState super.initState(); } @override Widget build(BuildContext context) { var x = MediaQuery.of(context).size.height; var y = MediaQuery.of(context).size.width; return Scaffold( backgroundColor: Colors.black26, appBar: AppBar( title: Text("Wallpaper Search"), bottom: new TabBar( isScrollable: true, controller: _tabController, tabs: <Widget>[ new Tab(icon: Icon(Icons.dashboard)), new Tab(text: "4K Wallpaper"), new Tab(text: "HD Wallpaper",), new Tab(text: "Nature Wallpaper",), new Tab(text: "People Wallpaper",), new Tab(text: "Love Wallpaper"), ], ), ), body: new TabBarView( controller: _tabController, children: <Widget>[ WallpaperList(_service.wallpapertourismJson), WallpaperList(_service.wallpaper4kJson), WallpaperList(_service.wallpaperhdJson), WallpaperList(_service.wallpapernatureJson), WallpaperList(_service.wallpaperpeopleJson), WallpaperList(_service.wallpaperlovejson), ], ), floatingActionButton: FloatingActionButton( onPressed: (){ Navigator.push( context, new MaterialPageRoute( builder: (context) => new Search())); }, child: Icon( Icons.search, size: x/16, ), ), ); } Widget WallpaperList(var _jsnStream) { return StreamBuilder(stream: _jsnStream, builder: (context, AsyncSnapshot<String> snapshot) { if (snapshot.hasData) { Map<String, dynamic> wallpaper = convert.jsonDecode(snapshot.data); var jsonResponse = wallpaper; return CustomScrollView( slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate([ CarouselSlider.builder( height: MediaQuery .of(context) .size .height / 2, aspectRatio: 16 / 9, viewportFraction: 0.8, initialPage: 50, enableInfiniteScroll: true, reverse: true, autoPlay: true, autoPlayInterval: Duration(seconds: 3), autoPlayAnimationDuration: Duration(seconds: 1), autoPlayCurve: Curves.fastOutSlowIn, pauseAutoPlayOnTouch: Duration(seconds: 10), enlargeCenterPage: true, itemCount: jsonResponse['photos'].length as int, itemBuilder: (BuildContext context, int index) => GestureDetector( onTap: () { Navigator.push( context, new MaterialPageRoute( builder: (context) => new Detail( originalPic: jsonResponse['photos'][index]['src']['original'], pic: jsonResponse['photos'][index]['src']['large']))); }, child: Card( child: Image.network( jsonResponse['photos'][index]['src']['large'], width: double.infinity, fit: BoxFit.cover, ), ), ), ]), ), SliverGrid( gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 200.0, mainAxisSpacing: 0.0, crossAxisSpacing: 0.0, childAspectRatio: 0.75, ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return GestureDetector( onTap: () { Navigator.push( context, new MaterialPageRoute( builder: (context) => new Detail( originalPic: jsonResponse['photos'][index]['src']['original'], pic: jsonResponse['photos'][index]['src']['large']))); }, child: Container( alignment: Alignment.center, child: Card( child: Image.network( jsonResponse['photos'][index]['src']['large'], fit: BoxFit.cover, width: double.infinity, height: double.infinity, ), ), ), ); }, childCount: jsonResponse['photos'].length as int, ), ) ], scrollDirection: Axis.vertical, ); }else{ print('no'); return Container( child: Center( child: CircularProgressIndicator( strokeWidth:10 , ), ), ); } } ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 import 'package:flutter/material.dart' ; import 'service.dart' ; import 'dart:math' ; import 'detail.dart' ; import 'search.dart' ; import 'package:carousel_slider/carousel_slider.dart' ; import 'dart:convert' as convert ; void main ( ) = > runApp ( MyApp ( ) ) ; class MyApp extends StatelessWidget { // This widget is the root of your application. @ override Widget build ( BuildContext context ) { return MaterialApp ( debugShowCheckedModeBanner : false , title : 'Wallpaper Search' , theme : ThemeData . dark ( ) , home : MyHomePage ( title : 'Wallpaper Search' ) , ) ; } } class MyHomePage extends StatefulWidget { MyHomePage ( { Key key , this . title } ) : super ( key : key ) ; final String title ; @ override _MyHomePageState createState ( ) = > _MyHomePageState ( ) ; } class _MyHomePageState extends State & lt ; MyHomePage > with SingleTickerProviderStateMixin { TabController _tabController ; Service _service = new Service ( ) ; @ override void initState ( ) { _service . checkAndGetPermission ( ) ; _service . fetch ( ) ; _tabController = new TabController ( vsync : this , initialIndex : 0 , length : 6 ) ; // TODO: implement initState super . initState ( ) ; } @ override Widget build ( BuildContext context ) { var x = MediaQuery . of ( context ) . size . height ; var y = MediaQuery . of ( context ) . size . width ; return Scaffold ( backgroundColor : Colors . black26 , appBar : AppBar ( title : Text ( "Wallpaper Search" ) , bottom : new TabBar ( isScrollable : true , controller : _tabController , tabs : < Widget > [ new Tab ( icon : Icon ( Icons . dashboard ) ) , new Tab ( text : "4K Wallpaper" ) , new Tab ( text : "HD Wallpaper" , ) , new Tab ( text : "Nature Wallpaper" , ) , new Tab ( text : "People Wallpaper" , ) , new Tab ( text : "Love Wallpaper" ) , ] , ) , ) , body : new TabBarView ( controller : _tabController , children : & lt ; Widget > [ WallpaperList ( _service . wallpapertourismJson ) , WallpaperList ( _service . wallpaper4kJson ) , WallpaperList ( _service . wallpaperhdJson ) , WallpaperList ( _service . wallpapernatureJson ) , WallpaperList ( _service . wallpaperpeopleJson ) , WallpaperList ( _service . wallpaperlovejson ) , ] , ) , floatingActionButton : FloatingActionButton ( onPressed : ( ) { Navigator . push ( context , new MaterialPageRoute ( builder : ( context ) = > new Search ( ) ) ) ; } , child : Icon ( Icons . search , size : x / 16 , ) , ) , ) ; } Widget WallpaperList ( var _jsnStream ) { return StreamBuilder ( stream : _jsnStream , builder : ( context , AsyncSnapshot < String > snapshot ) { if ( snapshot . hasData ) { Map < String , dynamic > wallpaper = convert . jsonDecode ( snapshot . data ) ; var jsonResponse = wallpaper ; return CustomScrollView ( slivers : < Widget > [ SliverList ( delegate : SliverChildListDelegate ( [ CarouselSlider . builder ( height : MediaQuery . of ( context ) . size . height / 2 , aspectRatio : 16 / 9 , viewportFraction : 0.8 , initialPage : 50 , enableInfiniteScroll : true , reverse : true , autoPlay : true , autoPlayInterval : Duration ( seconds : 3 ) , autoPlayAnimationDuration : Duration ( seconds : 1 ) , autoPlayCurve : Curves . fastOutSlowIn , pauseAutoPlayOnTouch : Duration ( seconds : 10 ) , enlargeCenterPage : true , itemCount : jsonResponse [ 'photos' ] . length as int , itemBuilder : ( BuildContext context , int index ) = > GestureDetector ( onTap : ( ) { Navigator . push ( context , new MaterialPageRoute ( builder : ( context ) = > new Detail ( originalPic : jsonResponse [ 'photos' ] [ index ] [ 'src' ] [ 'original' ] , pic : jsonResponse [ 'photos' ] [ index ] [ 'src' ] [ 'large' ] ) ) ) ; } , child : Card ( child : Image . network ( jsonResponse [ 'photos' ] [ index ] [ 'src' ] [ 'large' ] , width : double . infinity , fit : BoxFit . cover , ) , ) , ) , ] ) , ) , SliverGrid ( gridDelegate : SliverGridDelegateWithMaxCrossAxisExtent ( maxCrossAxisExtent : 200.0 , mainAxisSpacing : 0.0 , crossAxisSpacing : 0.0 , childAspectRatio : 0.75 , ) , delegate : SliverChildBuilderDelegate ( ( BuildContext context , int index ) { return GestureDetector ( onTap : ( ) { Navigator . push ( context , new MaterialPageRoute ( builder : ( context ) = > new Detail ( originalPic : jsonResponse [ 'photos' ] [ index ] [ 'src' ] [ 'original' ] , pic : jsonResponse [ 'photos' ] [ index ] [ 'src' ] [ 'large' ] ) ) ) ; } , child : Container ( alignment : Alignment . center , child : Card ( child : Image . network ( jsonResponse [ 'photos' ] [ index ] [ 'src' ] [ 'large' ] , fit : BoxFit . cover , width : double . infinity , height : double . infinity , ) , ) , ) , ) ; } , childCount : jsonResponse [ 'photos' ] . length as int , ) , ) ] , scrollDirection : Axis . vertical , ) ; } else { print ( 'no' ) ; return Container ( child : Center ( child : CircularProgressIndicator ( strokeWidth : 10 , ) , ) , ) ; } } ) ; } }

Create a search.dart for performing an image search