How to Build Wallpaper App Using Flutter

Feri Lukmansyah
15 min readJun 18, 2021

--

image from pexels

hello and welcome, in this discussion I will share how to Build Wallpaper Apps using Flutter, in this part I will show the process how to build it

this is the table of Content What will we be the topic this time

Table of Content

  • Creating Your Flutter Project
  • Creating Base Applications
  • Creating Views
  • Creating Widget
  • Creating Class to Fetching API and Handling Category
  • Creating Model

let’s go straight to the topic of the first discussion

Creating Your Flutter Project

lets creating a flutter project to start building wallpaper apps

  1. Open the IDE and select Create New Flutter Project.
  2. Select Flutter Application as the project type. Then click Next.
  3. Verify the Flutter SDK path specifies the SDK’s location (select Install SDK… if the text field is blank).
  4. Enter a project name (for example, wallpaperapps). Then click Next.
  5. Click Finish.
  6. Wait for Android Studio to install the SDK and create the project.

from the official documentation

Creating Base Applications

the second step is to create a base Application Structure, add this to main.dart

import 'package:flutter/material.dart';
import 'package:wallpaperapps/views/home.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Wallpaper Apps',
theme: ThemeData(

primaryColor: Colors.white,
),
home: Home(),
);
}
}

in this code, we call Home() class from View but Error because not Already created, in next step let's create a views

Creating Views

let’s creating views for our applications, first create Home() class for Home View like this

Handling Home View

create views directory inside lib directory and create home.dart inside views directory and create StatefulWidget for home view

class Home extends StatefulWidget {

@override
_HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {

// fetch data

// fetching curated photo from API
getCuratedPhotos() async {
var url = Uri.parse("https://api.pexels.com/v1/curated?per_page=20");
var response = await http.get(url,
headers: {
"Authorization":apiKey
});
// print(response.body.toString());

// parsing data from API (Json)
Map<String, dynamic> jsonData = jsonDecode(response.body);

// parsing data
jsonData["photos"].forEach((element){
// print(element); // dev mode

// getting data
WallpaperModel wallpaperModel = new WallpaperModel();
wallpaperModel = WallpaperModel.fromMap(element);
wallpapers.add(wallpaperModel);
// print(wallpapers.length); // dev mode
});

// set state
setState(() {});

}

inside Home() class, there is a function to retrieve data from the API to determine photos in the category column

// fetching curated photo from API
getCuratedPhotos() async {
var url = Uri.parse("https://api.pexels.com/v1/curated?per_page=20");
var response = await http.get(url,
headers: {
"Authorization":apiKey
});
// print(response.body.toString());

// parsing data from API (Json)
Map<String, dynamic> jsonData = jsonDecode(response.body);

// parsing data
jsonData["photos"].forEach((element){

// getting data
WallpaperModel wallpaperModel = new WallpaperModel();
wallpaperModel = WallpaperModel.fromMap(element);
wallpapers.add(wallpaperModel);
});

// set state
setState(() {});

}

Building Navbar Widget and List Wallpaper

now building Navbar Widget let’s call the widget brandName() create this inside widgets directory create file widget.dart

// widget.dart// brandNameWidget brandName(){
return RichText(
text: TextSpan(
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
children: const <TextSpan>[
TextSpan(text: 'Wallpaper', style: TextStyle(color: Colors.black87)),
TextSpan(text: 'Apps', style: TextStyle(color: Colors.blue)),
],
),
);
}
navbar brand name

and here is a widget for wallpaper List

// list wallpaper
Widget wallpaperList({required List <WallpaperModel> wallpapers, context }){
return Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: GridView.count(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
crossAxisCount: 2,
childAspectRatio: 0.6,
mainAxisSpacing: 6.0,
crossAxisSpacing: 6.0,
children: wallpapers.map((wallpaper){
return GridTile(
child: GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => ImageView(imgUrl: wallpaper.src!.portrait)
));
},
child: Hero(
tag: wallpaper.src!.portrait,
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.network(wallpaper.src!.portrait, fit: BoxFit.cover,)),
),
),
));
}).toList(),
),
);
}

Building Home User Interface

The next step is to Build Home User Interface, now let’s see the design

home UI Design

let’s back to our views/home.dart and add this code inside Home() class

List <CategoriesModel> categories = [];
List <WallpaperModel> wallpapers = [];

// text controller
TextEditingController searchController = new TextEditingController();

// initState
@override
void initState() {
getCuratedPhotos();
categories = getCategories();
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white ,//Colors.white, custom: 0xFF2B4772
appBar: AppBar(
title: brandName(),
elevation: 0.0
),
body: SingleChildScrollView(
child: Container(child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xfff5f8fd), // default colors: 0xfff5f8fd, custom: 0xFF2B4772
borderRadius: BorderRadius.circular(30)
),
padding: EdgeInsets.symmetric(horizontal: 24),
margin: EdgeInsets.symmetric(horizontal: 24),
child: Row(children: [
Expanded(
child: TextField(
controller: searchController,
decoration: InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
),
),
GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => Search(
searchQuery: searchController.text,
)
));
},
child: Container(
child: Icon(Icons.search)),
)
],)
,),
SizedBox(height: 16,),
Container(
height: 80,
child: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 24),
itemCount: categories.length,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: ((context, index){
return CategoryTitle(
title: categories[index].categoriesName,
imgUrl: categories[index].imgUrl,
);
}),
),
),
SizedBox(height: 16,),
wallpaperList(wallpapers: wallpapers, context: context),

],),),
),
);
}
}

Search Bar

we just created a function for handling search and a grid for displaying images, which can be seen in

// search BarContainer(
decoration: BoxDecoration(
color: Color(0xfff5f8fd), // default colors: 0xfff5f8fd, custom: 0xFF2B4772
borderRadius: BorderRadius.circular(30)
),
padding: EdgeInsets.symmetric(horizontal: 24),
margin: EdgeInsets.symmetric(horizontal: 24),
child: Row(children: [
Expanded(
child: TextField(
controller: searchController,
decoration: InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
),
),
GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => Search(
searchQuery: searchController.text,
)
));
},
child: Container(
child: Icon(Icons.search)),
)
],)
,),
SizedBox(height: 16,),
searchbar

Build Category Grid

next is Build Category Grid now inside SingleChildScrollView add this to Creating Grid Category

Container(
height: 80,
child: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 24),
itemCount: categories.length,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: ((context, index){
return CategoryTitle(
title: categories[index].categoriesName,
imgUrl: categories[index].imgUrl,
);
}),
),
),
SizedBox(height: 16,),
wallpaperList(wallpapers: wallpapers, context: context),

Create Category Title

to requests Image and Handling title in the category grid, we Need to Request From API now create a class named CategoryTitle extend with StatelessWidget

class CategoryTitle extends StatelessWidget {

// image url
final String? title, imgUrl;


// initialize using constructor
CategoryTitle({@required this.imgUrl, @required this.title});

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => Categories(categoryName: title!.toLowerCase()),
));
},
child: Container(
margin: EdgeInsets.only(right: 4),
child: Stack(children: [
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(imgUrl!, height: 50, width: 100, fit: BoxFit.cover,)),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
// color: Colors.black26,
),
height: 50,
width: 100,
alignment: Alignment.center,
child: Text(
title!,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 16,
),),)
],),
),
);
}
}

now the Home() the view is Complete but has many errors because we not already create other views and fetch category image for this,

Design Model

to initialize category and wallpaper on home views we need to define a model first create category_modeland wallpaper_model

Initialize Category Model

initialize Category Model in different file create directory call model and create categories_model.dart and initialize the model

// model/category_model.dart
class CategoriesModel {
String? categoriesName;
String? imgUrl;
}

Initialize Wallpaper Model

after define CategoryModel , define WallpaperModel

// model/wallpaper_model.dart
// wallpaper identity model

class WallpaperModel {

String? photographer;
String? photographerUrl;
int? photographerId;

// access keys map
SrcModel? src;

// create name parameter
WallpaperModel({
this.src,
this.photographerUrl,
this.photographerId,
this.photographer,

});

// passing json value from API
factory WallpaperModel.fromMap(Map<String, dynamic> jsonData){
return WallpaperModel(
src: SrcModel.fromMap(jsonData['src']),
photographerUrl: jsonData["photographer_url"],
photographerId: jsonData["photographer_id"],
photographer: jsonData["photographer"],
);
}

}

// wallpaper Source Map Model
class SrcModel {

String original;
String small;
String portrait;

// create name parameter
SrcModel({
required this.original,
required this.small,
required this.portrait,
});

// passing json value from API
factory SrcModel.fromMap(Map<String, dynamic> jsonData){
return SrcModel(
portrait: jsonData["portrait"],
original: jsonData["original"],
small: jsonData["small"],
);
}

}

In this Model we Parsing Data From API using a factory constructor

let’s look at JSON Format in an API Response

{"page": 1,"per_page": 1,"photos": [{"id": 7362829,"width": 4000,"height": 6000,"url": "https://www.pexels.com/photo/wood-light-dawn-landscape-7362829/","photographer": "Bayu Samudro","photographer_url": "https://www.pexels.com/@bayusamudro","photographer_id": 35776645,"avg_color": "#323434","src": {"original": "https://images.pexels.com/photos/7362829/pexels-photo-7362829.jpeg","large2x": "https://images.pexels.com/photos/7362829/pexels-photo-7362829.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940","large": "https://images.pexels.com/photos/7362829/pexels-photo-7362829.jpeg?auto=compress&cs=tinysrgb&h=650&w=940","medium": "https://images.pexels.com/photos/7362829/pexels-photo-7362829.jpeg?auto=compress&cs=tinysrgb&h=350","small": "https://images.pexels.com/photos/7362829/pexels-photo-7362829.jpeg?auto=compress&cs=tinysrgb&h=130","portrait": "https://images.pexels.com/photos/7362829/pexels-photo-7362829.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=1200&w=800","landscape": "https://images.pexels.com/photos/7362829/pexels-photo-7362829.jpeg?auto=compress&cs=tinysrgb&fit=crop&h=627&w=1200","tiny": "https://images.pexels.com/photos/7362829/pexels-photo-7362829.jpeg?auto=compress&cs=tinysrgb&dpr=1&fit=crop&h=200&w=280"},"liked": false}],"total_results": 8000,"next_page": "https://api.pexels.com/v1/curated/?page=2&per_page=1"}

after look the sample response from API now we will create a factory function to parse photosvalue from API

// passing json value from API
factory WallpaperModel.fromMap(Map<String, dynamic> jsonData){
return WallpaperModel(
src: SrcModel.fromMap(jsonData['src']),
photographerUrl: jsonData["photographer_url"],
photographerId: jsonData["photographer_id"],
photographer: jsonData["photographer"],
);
}

}

after we Parse From photos we need access tosrc and access these keys

  • portrait
  • small
  • original
// passing json value from API
factory SrcModel.fromMap(Map<String, dynamic> jsonData){
return SrcModel(
portrait: jsonData["portrait"],
original: jsonData["original"],
small: jsonData["small"],
);
}

now wallpaper_model will be like this

// wallpaper identity model

class WallpaperModel {

String? photographer;
String? photographerUrl;
int? photographerId;

// access keys map
SrcModel? src;

// create name parameter
WallpaperModel({
this.src,
this.photographerUrl,
this.photographerId,
this.photographer,

});

// passing json value from API
factory WallpaperModel.fromMap(Map<String, dynamic> jsonData){
return WallpaperModel(
src: SrcModel.fromMap(jsonData['src']),
photographerUrl: jsonData["photographer_url"],
photographerId: jsonData["photographer_id"],
photographer: jsonData["photographer"],
);
}

}

// wallpaper Source Map Model
class SrcModel {

String original;
String small;
String portrait;

// create name parameter
SrcModel({
required this.original,
required this.small,
required this.portrait,
});

// passing json value from API
factory SrcModel.fromMap(Map<String, dynamic> jsonData){
return SrcModel(
portrait: jsonData["portrait"],
original: jsonData["original"],
small: jsonData["small"],
);
}

}

and after define the model create a function to get category Model

Get Category Image Model

to get an image in the category grid we need to request that from API, to handle this problem we need to Create a Function to Handle the Category Model, create a new directory call data and create data.dart and handling the problem

// data/data.dart
import 'package:wallpaperapps/model/categories_model.dart';

// api keys
String apiKey = "563492ad6f9170000100000174dda4707e934bc58524e21b8e440b15";

List <CategoriesModel> getCategories(){

List <CategoriesModel> categories = [];

CategoriesModel categoryModel = new CategoriesModel();

// define Category

// Street Art
categoryModel.imgUrl = "https://images.pexels.com/photos/908713/pexels-photo-908713.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500";
categoryModel.categoriesName = "Street Art";
categories.add(categoryModel);
categoryModel = new CategoriesModel();

// Wild Live
categoryModel.imgUrl = "https://images.pexels.com/photos/704320/pexels-photo-704320.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500";
categoryModel.categoriesName = "Wild Live";
categories.add(categoryModel);
categoryModel = new CategoriesModel();

// Nature
categoryModel.imgUrl = "https://images.pexels.com/photos/34950/pexels-photo.jpg?auto=compress&cs=tinysrgb&dpr=2&w=500";
categoryModel.categoriesName = "Nature";
categories.add(categoryModel);
categoryModel = new CategoriesModel();

// city
categoryModel.imgUrl = "https://images.pexels.com/photos/466685/pexels-photo-466685.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500";
categoryModel.categoriesName = "City";
categories.add(categoryModel);
categoryModel = new CategoriesModel();

// motivation
categoryModel.imgUrl = "https://images.pexels.com/photos/3806690/pexels-photo-3806690.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500";
categoryModel.categoriesName = "Motivation";
categories.add(categoryModel);
categoryModel = new CategoriesModel();

// bikes
categoryModel.imgUrl = "https://images.pexels.com/photos/289869/pexels-photo-289869.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500";
categoryModel.categoriesName = "Bikes";
categories.add(categoryModel);
categoryModel = new CategoriesModel();

// cars
categoryModel.imgUrl = "https://images.pexels.com/photos/289869/pexels-photo-289869.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500";
categoryModel.categoriesName = "Cars";
categories.add(categoryModel);
categoryModel = new CategoriesModel();

// return value
return categories;

}

and after complete creating categories_model creating the widget for category

Build Category Widget Views

to fix errors on the home view we need to create a categories widget view after that import the widget to home.dart let’s create categories.dart inside views directory.

mport 'dart:convert';

import 'package:flutter/material.dart';
import 'package:wallpaperapps/data/data.dart';
import 'package:wallpaperapps/model/wallpaper_model.dart';
import 'package:http/http.dart' as http;
import 'package:wallpaperapps/widgets/widget.dart';

class Categories extends StatefulWidget {

// passing category name
final String categoryName;
Categories({required this.categoryName});

@override
_CategoriesState createState() => _CategoriesState();
}

class _CategoriesState extends State<Categories> {

// list wallpaper
List <WallpaperModel> wallpapers = [];


// fetch data

// fetching Search Photo from API
searchPhotos(String query) async {
var url = Uri.parse("https://api.pexels.com/v1/search?query=$query&per_page=20");
var response = await http.get(url,
headers: {
"Authorization":apiKey
});
// print(response.body.toString());

// parsing data from API (Json)
Map<String, dynamic> jsonData = jsonDecode(response.body);

// parsing data
jsonData["photos"].forEach((element){
// print(element); // dev mode

// getting data
WallpaperModel wallpaperModel = new WallpaperModel();
wallpaperModel = WallpaperModel.fromMap(element);
wallpapers.add(wallpaperModel);
});

// set state
setState(() {});
}

@override
void initState() {
// TODO: implement initState
searchPhotos(widget.categoryName);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: brandName(),
elevation: 0.0,
),
body: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget> [
SizedBox(height: 16,),
wallpaperList(wallpapers: wallpapers, context: context),
],),
),
),
);
}
}

install http to handling HTTP requests using pub, then fetching category image from pexels API

Build Search Widget Views

and if we looking again search function in home.dart have many errors because we, not already creating Search Widget, create search.dart inside views directory

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:wallpaperapps/data/data.dart';
import 'package:wallpaperapps/model/wallpaper_model.dart';
import 'package:wallpaperapps/widgets/widget.dart';
import 'package:http/http.dart' as http;


// Search Query

class Search extends StatefulWidget {
// Search Query Input
final String searchQuery;

Search({required this.searchQuery});


@override
_SearchState createState() => _SearchState();
}

class _SearchState extends State<Search> {
// text controller
TextEditingController searchController = new TextEditingController();

// list wallpaper
List <WallpaperModel> wallpapers = [];


// fetch data

// fetching Search Photo from API
searchPhotos(String query) async {
var url = Uri.parse("https://api.pexels.com/v1/search?query=$query&per_page=20");
var response = await http.get(url,
headers: {
"Authorization":apiKey
});
// print(response.body.toString());

// parsing data from API (Json)
Map<String, dynamic> jsonData = jsonDecode(response.body);

// parsing data
jsonData["photos"].forEach((element){
// print(element); // dev mode

// getting data
WallpaperModel wallpaperModel = new WallpaperModel();
wallpaperModel = WallpaperModel.fromMap(element);
wallpapers.add(wallpaperModel);
});

// set state
setState(() {});
}

@override
void initState() {
// TODO: implement initState
searchPhotos(widget.searchQuery);
super.initState();
searchController.text = widget.searchQuery;
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: brandName(),
elevation: 0.0,
),
body: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget> [
Container(
decoration: BoxDecoration(
color: Color(0xfff5f8fd),
borderRadius: BorderRadius.circular(30)
),
padding: EdgeInsets.symmetric(horizontal: 24),
margin: EdgeInsets.symmetric(horizontal: 24),
child: Row(children: [
Expanded(
child: TextField(
controller: searchController,
decoration: InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
),
),
GestureDetector(
onTap: (){
// passing query
searchPhotos(searchController.text);
},
child: Container(
child: Icon(Icons.search)),
)
],)
,),
wallpaperList(wallpapers: wallpapers, context: context),
],),
),
),

);
}
}

after create and handling search and category we need a class to handle wallpaper and image view on our apps, create a new View call image_view.dart inside views directory

// views/image_viewimport 'dart:io' as io;
import 'dart:typed_data';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:permission_handler/permission_handler.dart';

import 'wallpaper_manager.dart';
// import 'package:wallpaperapps/views/wallpaper_manager.dart';


class ImageView extends StatefulWidget {

// pass image url
final String imgUrl;
ImageView({required this.imgUrl});

@override
_ImageViewState createState() => _ImageViewState();
}

class _ImageViewState extends State<ImageView> {


@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: [
Hero(
tag: widget.imgUrl,
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Image.network(widget.imgUrl, fit: BoxFit.cover,)),
),

// set wallpaper button
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
alignment: Alignment.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
// save image to photos directory
_save();

},
child: Stack(
children: [
Container(
height: 50,
decoration: BoxDecoration(
color: Color(0xff1C1B1B).withOpacity(0.8),
borderRadius: BorderRadius.circular(30)
),
width: MediaQuery.of(context).size.width/2,
),
Container(
height: 50,
width: MediaQuery.of(context).size.width/2,
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
decoration: BoxDecoration(
border: Border.all(color: Colors.white54, width: 1),
borderRadius: BorderRadius.circular(30),
gradient: LinearGradient(
colors: [
Color(0x36FFFFFF),
Color(0x0FFFFFFF)
]
)
),
child: Column(children: <Widget> [
Text("Set As Wallpaper", style: TextStyle(fontSize: 16, color: Colors.white70),),
Text("Image Will be Save at Galery", style: TextStyle(
fontSize: 10,
color: Colors.white70,
),)
],),
)
],
),
),
SizedBox(height: 16,),
// cancel vutton handler
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Text("Cancel", style: TextStyle(color: Colors.white),)),
SizedBox(height: 50,)
],),
)

],),
);
}

}

in this view, if we click on an image it will appear in full screen

image view result

Set Image as Wallpaper and Save to Galery

to set images as wallpaper then saving to our gallery we need this packages

add to pubspect.yaml and update the dependencies

after install the required packages create function to asking permission

// asking permission
_askPermission() async {
if (io.Platform.isIOS) {
var photosStatus = await Permission.photos.status;
if (photosStatus.isDenied) {
await Permission.photos.request();
print("Photos Permission Status" + photosStatus.toString());
}
} else {
var photoStatus = await Permission.photos.status;
var storageStatus = await Permission.storage.status;
if (storageStatus.isDenied) {
await Permission.storage.request().then((value) {
if (!value.isGranted) _askPermission();
});
print("Android Storage Permission Status: " + storageStatus.toString());

} else if (photoStatus.isDenied) {
await Permission.photos.request().then((value) {
if (!value.isGranted) _askPermission();
});
print("Android Photos Permission Status: " + photoStatus.toString());
}
// Map<Permission, PermissionStatus> statuses = await [Permission.storage].request();
// print(statuses[Permission.storage]);

}
}

and create a class to manage Wallpaper and Set Wallpaper into lock screen and home screen inside views directory

// views/wallpaper_manager.dartimport 'dart:async';
import 'package:flutter/services.dart';

/// WallpaperManager plugin begins here
class WallpaperManager {
// Define channel
static const MethodChannel _channel = MethodChannel('wallpaper_manager');

/// Static code for Home Screen Wallpaper Choice
static const int HOME_SCREEN = 1;

/// Static code for Lock Screen Wallpaper Choice
static const int LOCK_SCREEN = 2;

/// Static code for both Home Screen and Lock Screen Wallpaper Choice
static const int BOTH_SCREENS = 3;

/// Function to check working/validity of method channels
static Future<String> get platformVersion async {
// String to store the version number before returning. This is just to test working/validity.
final version =
await _channel.invokeMethod<String>('getPlatformVersion') ?? '';

// Function returns version number
return version;
}

/// Function takes input file's path & location choice
static Future<String> setWallpaperFromFile(
String filePath, int wallpaperLocation) async {
// Variable to store operation result
final result = await _channel.invokeMethod<int>(
'setWallpaperFromFile',
{'filePath': filePath, 'wallpaperLocation': wallpaperLocation},
);

// Function returns the set String as result, use for debugging
return (result ?? 0) > 0 ? 'Wallpaper set' : 'There was an error.';
}

/// Function takes input file's path & location choice
static Future<String> setWallpaperFromFileWithCrop(String filePath,
int wallpaperLocation, int left, int top, int right, int bottom) async {
// Variable to store operation result
int? result;
if (left > right || top > bottom) {
result = 0;
} else {
result =
await _channel.invokeMethod<int>('setWallpaperFromFileWithCrop', {
'filePath': filePath,
'wallpaperLocation': wallpaperLocation,
'left': left,
'top': top,
'right': right,
'bottom': bottom
});
}

// Function returns the set String as result, use for debugging
return (result ?? 0) > 0 ? 'Wallpaper set' : 'There was an error.';
}

/// Function takes input file's asset (Dart/Flutter; pre-indexed in pubspec.yaml) & location choice
static Future<String> setWallpaperFromAsset(
String assetPath, int wallpaperLocation) async {
// Variable to store operation result
final result = await _channel.invokeMethod<int>(
'setWallpaperFromAsset',
{'assetPath': assetPath, 'wallpaperLocation': wallpaperLocation},
);

// Function returns the set String as result, use for debugging
return (result ?? 0) > 0 ? 'Wallpaper set' : 'There was an error.';
}

/// Function takes input file's asset (Dart/Flutter; pre-indexed in pubspec.yaml) & location choice
static Future<String> setWallpaperFromAssetWithCrop(String assetPath,
int wallpaperLocation, int left, int top, int right, int bottom) async {
// Variable to store operation result
int? result;
if (left > right || top > bottom || left < 0 || top < 0) {
result = 0;
} else {
result =
await _channel.invokeMethod<int>('setWallpaperFromAssetWithCrop', {
'assetPath': assetPath,
'wallpaperLocation': wallpaperLocation,
'left': left,
'top': top,
'right': right,
'bottom': bottom
});
}

// Function returns the set String as result, use for debugging
return (result ?? 0) > 0 ? 'Wallpaper set' : 'There was an error.';
}
}

and back to views/image_view.dart and add function to set Wallpaper Image and Save to gallery

// saving image to gallery function
_save() async {
if (io.Platform.isAndroid){
await _askPermission();
}

var response = await Dio().get(
widget.imgUrl,
options: Options(responseType: ResponseType.bytes)
);
final result = await ImageGallerySaver.saveImage(Uint8List.fromList(response.data));
print(result);
print('default path: '+ result['filePath'].toString());

// set wallpaper to home Screen and LockScreem
// int lockScreenLocation = WallpaperManager.LOCK_SCREEN;
// int homeScreenLocation = WallpaperManager.HOME_SCREEN;
int bothScreenLocation = WallpaperManager.BOTH_SCREENS;

// set path image
final imagePath = result['filePath'].toString().replaceAll(RegExp('file://'), '');

// setting wallpaper
String setBoth;
// String setLockScreen;
// String setHomeScreen;
try {
// setLockScreen = await WallpaperManager.setWallpaperFromFile(imagePath, lockScreenLocation);
// setHomeScreen = await WallpaperManager.setWallpaperFromFile(imagePath, homeScreenLocation);
setBoth = await WallpaperManager.setWallpaperFromFile(imagePath, bothScreenLocation);

// print status to console
print(setBoth);
// print(setHomeScreen);

} on PlatformException {
// setLockScreen = "Failed To Set Wallpaper in LockScreen";
// setHomeScreen = "Failed to Set Wallpaper in HomeScreen";
setBoth = "Failed To Set Wallpaper in Both";
}
if (!mounted) {
return;
}

Navigator.pop(context);
}

Updating Home Views

after creating the models, views, and data adding that to home.dart inside views directory

// update views/home.dartimport 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:wallpaperapps/data/data.dart';
import 'package:wallpaperapps/model/categories_model.dart';
import 'package:wallpaperapps/model/wallpaper_model.dart';
import 'package:wallpaperapps/views/categories.dart';
import 'package:wallpaperapps/views/search.dart';
import 'package:wallpaperapps/widgets/widget.dart';
import 'package:http/http.dart' as http;

class Home extends StatefulWidget {

@override
_HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {

// fetch data

// fetching curated photo from API
getCuratedPhotos() async {
var url = Uri.parse("https://api.pexels.com/v1/curated?per_page=20");
var response = await http.get(url,
headers: {
"Authorization":apiKey
});
// print(response.body.toString());

// parsing data from API (Json)
Map<String, dynamic> jsonData = jsonDecode(response.body);

// parsing data
jsonData["photos"].forEach((element){
// print(element); // dev mode

// getting data
WallpaperModel wallpaperModel = new WallpaperModel();
wallpaperModel = WallpaperModel.fromMap(element);
wallpapers.add(wallpaperModel);
// print(wallpapers.length); // dev mode
});

// set state
setState(() {});

}

List <CategoriesModel> categories = [];
List <WallpaperModel> wallpapers = [];

// text controller
TextEditingController searchController = new TextEditingController();

// initState
@override
void initState() {
getCuratedPhotos();
categories = getCategories();
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white ,//Colors.white, custom: 0xFF2B4772
appBar: AppBar(
title: brandName(),
elevation: 0.0
),
body: SingleChildScrollView(
child: Container(child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xfff5f8fd), // default colors: 0xfff5f8fd, custom: 0xFF2B4772
borderRadius: BorderRadius.circular(30)
),
padding: EdgeInsets.symmetric(horizontal: 24),
margin: EdgeInsets.symmetric(horizontal: 24),
child: Row(children: [
Expanded(
child: TextField(
controller: searchController,
decoration: InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
),
),
GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => Search(
searchQuery: searchController.text,
)
));
},
child: Container(
child: Icon(Icons.search)),
)
],)
,),
SizedBox(height: 16,),
Container(
height: 80,
child: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 24),
itemCount: categories.length,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: ((context, index){
return CategoryTitle(
title: categories[index].categoriesName,
imgUrl: categories[index].imgUrl,
);
}),
),
),
SizedBox(height: 16,),
wallpaperList(wallpapers: wallpapers, context: context),

],),),
),
);
}
}

class CategoryTitle extends StatelessWidget {

// image url
final String? title, imgUrl;


// initialize using constructor
CategoryTitle({@required this.imgUrl, @required this.title});

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => Categories(categoryName: title!.toLowerCase()),
));
},
child: Container(
margin: EdgeInsets.only(right: 4),
child: Stack(children: [
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(imgUrl!, height: 50, width: 100, fit: BoxFit.cover,)),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
// color: Colors.black26,
),
height: 50,
width: 100,
alignment: Alignment.center,
child: Text(
title!,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 16,
),),)
],),
),
);
}
}

Update Android Manifest to handling Permission for User Access

after completing the application updating the Android Manifest, The manifest file describes essential information about your app to the Android build tools, the Android operating system, and Google Play.

<!-- Manifest -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" />

<application
android:requestLegacyExternalStorage="true"
android manifest update

then run the applications press Shift + 10 for android studio

result wallpaper Apps

okay until here the discussion this time may be useful and good luck,

Useful Resource and Reference

--

--

Feri Lukmansyah
Feri Lukmansyah

Written by Feri Lukmansyah

A Software Engineer active on Upwork and Fiverr journal https://ferilukmansyah.dev

No responses yet