import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:flutter_fortune_wheel/flutter_fortune_wheel.dart';
import 'package:confetti/confetti.dart';
// Run the MyApp widget
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
// Disable debug banner
debugShowCheckedModeBanner: false,
// App title
title: 'Gfg Lunch Wheel',
// Set the home screen
home: ExamplePage(),
);
}
}
class ExamplePage extends StatefulWidget {
@override
_ExamplePageState createState() => _ExamplePageState();
}
// Lunch class to represent a meal
class Lunch {
// Name of the meal
final String meal;
// Image URL of the meal
var img;
Lunch({required this.meal, this.img});
// Factory constructor to create a Lunch object from JSON
factory Lunch.fromJson(Map<String, dynamic> json) {
return Lunch(
meal: json['strMeal'],
img: json['strMealThumb'],
);
}
}
class _ExamplePageState extends State<ExamplePage> {
// StreamController to manage the selected index of the wheel
StreamController<int> selected = StreamController<int>();
// ConfettiController to manage confetti animation
late ConfettiController _centerController;
// API URL to fetch Indian meals
String url = "https://www.themealdb.com/api/json/v1/1/filter.php?a=Indian";
// List to store meal ideas
List<Lunch> _ideas = [];
// Function to fetch meal ideas from the API
Future<void> _getLunchIdeas() async {
http.Response response;
Uri uri = Uri.parse(url);
response = await http.get(uri);
if (response.statusCode == 200) {
Map<String, dynamic> jsonData = json.decode(response.body);
if (jsonData['meals'] != null) {
List<dynamic> meals = jsonData['meals'];
print("Fetched meals: $meals");
setState(() {
_ideas = meals.map((json) => Lunch.fromJson(json)).toList();
});
}
}
}
@override
void initState() {
super.initState();
// Fetch meal ideas when the widget initializes
_getLunchIdeas();
// Initialize confetti controller
_centerController =
ConfettiController(duration: const Duration(seconds: 10));
}
@override
void dispose() {
// Close the stream controller
selected.close();
// Dispose the confetti controller
_centerController.dispose();
super.dispose();
}
// Variables to store the selected meal and its image
var selectedIdea = "";
late var selectedImg;
// Function to set the selected meal and image
void setValue(value) {
selectedIdea = _ideas[value].meal.toString();
selectedImg = _ideas[value].img;
}
@override
Widget build(BuildContext context) {
// Flag to handle initial wheel focus
var flag = false;
return Scaffold(
appBar: AppBar(
centerTitle: true,
// AppBar title
title: const Text('Gfg Lunch Wheel'),
// AppBar background color
backgroundColor: Colors.green,
// AppBar text color
foregroundColor: Colors.white,
),
body: _ideas.length > 2
? Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
setState(() {
selected.add(
// Spin the wheel
Fortune.randomInt(0, _ideas.length),
);
});
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 350,
child: FortuneWheel(
// Stream for selected index
selected: selected.stream,
items: [
for (var it in _ideas)
FortuneItem(child: Text(it.meal)), // Wheel items
],
onAnimationEnd: () {
// Play confetti animation
_centerController.play();
showDialog(
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
scrollable: true,
// Dialog title
title: Text("Hurray! today's meal is????"),
content: Stack(
alignment: Alignment.center,
children: [
// Confetti animation
Align(
alignment: Alignment.topRight,
child: SizedBox(
width: 300,
height: 300,
child: Center(
child: ConfettiWidget(
confettiController:
_centerController,
blastDirection: pi,
maxBlastForce: 10,
minBlastForce: 1,
emissionFrequency: 0.03,
numberOfParticles: 100,
gravity: 0,
),
),
),
),
// Selected meal details
Column(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Text(
selectedIdea,
style: TextStyle(fontSize: 22),
),
// Display meal image
Image.network(selectedImg),
],
),
],
),
);
},
);
},
);
},
onFocusItemChanged: (value) {
if (flag == true) {
// Set selected meal
setValue(value);
} else {
// Handle initial focus
flag = true;
}
},
),
),
],
),
),
)
: Center(
// Show loading indicator
child: CircularProgressIndicator(color: Colors.green),
),
);
}
}