HopSpotFrontend/lib/pages/wheel_page.dart
2025-05-13 21:06:14 +02:00

204 lines
5.4 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:flutter_fortune_wheel/flutter_fortune_wheel.dart';
import 'package:pvt15/pages/game_page.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class WheelPage extends StatefulWidget {
const WheelPage({super.key});
@override
State<WheelPage> createState() => _WheelPageState();
}
class _WheelPageState extends State<WheelPage> {
final StreamController<int> controller = StreamController<int>();
Map<String, dynamic> challenges = {};
// A list of game titles that represent the segments of the wheel.
List<String> wheelItems = [];
// Closes the controller's stream when the widget is disposed.
// This ensures proper cleanup of resources and prevents memory leaks.
@override
void dispose() {
controller.close();
super.dispose();
}
@override
void initState() {
super.initState();
initializeChallenge();
}
void initializeChallenge() async {
await fetchChallenges();
setState(() { // Load the challenge
_loadChallenges();
});
}
// Simulates a spin of the fortune wheel by generating a random index.
void _spin() {
final result = Random().nextInt(wheelItems.length);
controller.add(result);
}
// Returns a description for the given title.
String _getDescriptionFor(String title) {
switch (title) {
case 'Rita & gissa':
return 'Text';
case 'Charader':
return 'Text';
case 'Dansbattle':
return 'Text';
case 'Gissa låten':
return 'Text';
case 'Sanningar':
return 'Text';
case 'Selfiejakt':
return 'Text';
default:
return 'Okänt spel';
}
}
// Builds the main UI for the wheel screen.
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color.fromARGB(248, 180, 8, 129),
body: Center(
child: wheelItems.isEmpty ? const CircularProgressIndicator() // Waiting for wheel to build
:GestureDetector(
onTap: _spin,
child: _buildWheelContainer(),
),
),
);
}
// Builds the main container that holds the fortune wheel and its instructional text.
Widget _buildWheelContainer() {
return Container(
height: 500,
width: 370,
decoration: BoxDecoration(
color: const Color.fromARGB(255, 153, 101, 150),
borderRadius: BorderRadius.circular(40),
),
child: Stack(
alignment: Alignment.center,
children: [
_buildContainerText(),
_buildWheel(),
],
),
);
}
// Builds the wheel and listens to spins and triggers an action when the animation ends.
Widget _buildWheel() {
return SizedBox(
width: 320,
height: 320,
child: FortuneWheel(
animateFirst: false,
selected: controller.stream,
onAnimationEnd: _handleWheelResult,
items: _buildWheelItems(),
indicators: <FortuneIndicator>[
_buildFortuneIndicator(),
],
),
);
}
// Build fortune indicator
_buildFortuneIndicator() {
return FortuneIndicator(
alignment: Alignment.topCenter,
child: Container(
width: 12,
height: 12,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
),
);
}
// Builds a text widget that instructs the user to click on the wheel
Widget _buildContainerText() {
return Positioned(
top: 20,
child: Text(
'Klicka på hjulet!',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
);
}
// Builds and returns the list of FortuneItem widgets that make up the wheel's segments
List<FortuneItem> _buildWheelItems() {
return wheelItems.map(
(item) => FortuneItem(
child: Text(
item,
style: const TextStyle(
fontSize: 18,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
).toList();
}
// Handles the result of the wheel spin.
// It retrieves the selected item's title and description, then navigates to corresponding gamePage
void _handleWheelResult() {
String selectedTitle = "Charader";
final selectedDescription = _getDescriptionFor(selectedTitle);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GamePage(
title: selectedTitle,
description: selectedDescription,
),
),
);
}
// Fetch the challenges through the api
Future<void> fetchChallenges() async {
final url = Uri.parse('https://group-1-15.pvt.dsv.su.se/api/challenges');
try {
final response = await http.get(url);
if (response.statusCode == 200) { // (HTTP 200 OK)
challenges = jsonDecode(utf8.decode(response.bodyBytes)); // convert the JSON string into a map
// var charaderChallenges = challenges["Charader"];
// debugPrint("Charader challenges: $charaderChallenges");
// debugPrint(challenges.toString());
}
} catch (e) {
debugPrint('Ett fel inträffade vid anrop till backend: $e');
throw Exception('Ett fel inträffade vid anrop till backend: $e');
}
}
void _loadChallenges() async {
wheelItems = challenges.keys.toList();
}
}