Flutter Wallpaper App (Pexels API)

Published by Abhay Rastogi on

Flutter Wallpaper Web App Using pexels API

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'

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;
  }


}

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: [
            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 snapshot) {
          if (snapshot.hasData) {
            Map wallpaper = convert.jsonDecode(snapshot.data);
            var jsonResponse = wallpaper;
            return CustomScrollView(
              slivers: [

                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

import 'package:flutter/material.dart';
import 'service.dart';
import 'detail.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'dart:convert' as convert;
class Search extends StatefulWidget {
  @override
  _SearchState createState() => _SearchState();
}

class _SearchState extends State<Search> {

  final TextEditingController _searchQuery = new 
  TextEditingController();
  bool _IsSearching;
  String _searchText = "";
  Service _service = new Service();
  Widget appBarTitle = new Text("Search Sample", style: new TextStyle(color: Colors.white),);
  Icon actionIcon = new Icon(Icons.check_circle, color: Colors.white,);

 @override
  void initState() {
    _IsSearching = false;
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(

      appBar: AppBar(
        centerTitle: true,
        title: TextField(

                  controller: _searchQuery,
                  style: new TextStyle(


                  ),
                  decoration: new InputDecoration(
                      prefixIcon: new Icon(Icons.search),
                     border: OutlineInputBorder(),

                      hintText: "Search ...",

                  ),
                  onSubmitted: (value){

                    setState(() {
                      _IsSearching = !_IsSearching;
                     });
                       // search pass String in method
                      _service.httpRequestSearch(value);
                   
                    
                  },
                ),
        elevation: 20,
        leading: new IconButton(
          icon: new Icon(Icons.arrow_back),
          onPressed: () => Navigator.of(context).pop(),
        ),
       
      ),

      body:  WallpaperList(_service.searchJson) ,


    );
  }


  Widget WallpaperList(var _jsnStream) {
    return StreamBuilder(stream: _jsnStream,
        builder: (context, AsyncSnapshot<String> snapshot) {
          if (snapshot.hasData) {
            Map wallpaper = convert.jsonDecode(snapshot.data);
            var jsonResponse = wallpaper;
            
            return jsonResponse['photos'] != 0 ? 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,
            ):Card(

                child: Center(
                  child: Text("Not Found ...!"),
                )
            );
          }else{
            return _IsSearching == false?Card(

              child: Center(
                child: Icon(Icons.wallpaper,size: MediaQuery.of(context).size.height/4,),
              ),
            ):Card(

                child: Center(
                child: CircularProgressIndicator(),
          )
            );
          }
        }


    );
  }


}
Categories: flutter

1 Comment

wallyScoft · 18th November 2020 at 7:55 pm

i am so satisfacted. greetings wally

Leave a Reply

Your email address will not be published. Required fields are marked *