Question
using Flutter I have created a treasure hunt app. It's such that when a user taps on a treasure to find it displays either found
using Flutter I have created a treasure hunt app. It's such that when a user taps on a treasure to find it displays either found or too far. I would like to make the user experience much better by displaying to the user the distance between them and the treasure. So when they start moving it should display how far they are and if they are still far away, the distance should be in red, if they are almost there it should be yellow and if they are within the 20m radius which I stated in this treasure hunt code, the distance should be in green which will then make the user know that they can tap on the treasure to find it. it saves them the stress of having to just keep tapping on the found treasure button without any clue on if they are close to the treasure or not. Please can anyone implement these features to my code? Please don't show an example code instead implement it into mine as it makes it easier for me to understand and learn my concept rather than a new concept. i have a treasure hunt distance view code that implements this logic but I'm struggling to integrate it or call it into my treasure hunt view where the user has to tap to find the treasures. and use it so the user can actually see their distance from a treasure.
Below is a treasurehunt distance view code.
import 'package:flutter/material.dart';
import 'package:hunt/hunt_views/treasure_view.dart';
import 'package:haversine_distance/haversine_distance.dart' as hd;
import 'package:location/location.dart' as lc;
class TreasureDistanceView extends StatefulWidget {
final Treasure treasure;
final lc.LocationData userLocation;
TreasureDistanceView({required this.treasure, required this.userLocation});
@override
_TreasureDistanceViewState createState() => _TreasureDistanceViewState();
}
class _TreasureDistanceViewState extends State
final hd.HaversineDistance haversineDistance = hd.HaversineDistance();
@override
Widget build(BuildContext context) {
double? userLatitude = widget.userLocation.latitude;
double? userLongitude = widget.userLocation.longitude;
double distance = 0.0;
if (userLatitude != null && userLongitude != null) {
distance = haversineDistance.haversine(
hd.Location(userLatitude, userLongitude),
hd.Location(widget.treasure.latitude, widget.treasure.longitude),
hd.Unit.METER,
);
}
Color distanceColor;
String distanceText;
if (distance <= 20) {
distanceText = "You found the treasure!";
distanceColor = Colors.green;
} else if (distance <= 50) {
distanceText = "You're getting close! Distance: ${distance.toStringAsFixed(1)}m";
distanceColor = Colors.yellow;
} else {
distanceText = "Distance: ${distance.toStringAsFixed(1)}m";
distanceColor = Colors.red;
}
return Text(
distanceText,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: distanceColor),
);
}
}
Below is the treasurehunt view where the logic takes place
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:haversine_distance/haversine_distance.dart' as hd;
import 'package:location/location.dart' as lc;
import 'package:share_plus/share_plus.dart';
class Treasure {
double latitude;
double longitude;
String name;
bool found = false;
Treasure(
{required this.latitude, required this.longitude, required this.name});
factory Treasure.fromSnapshot(DocumentSnapshot snapshot) {
return Treasure(
latitude: (snapshot.data() as Map
longitude: (snapshot.data() as Map
name: (snapshot.data() as Map
);
}
}
class TreasureHuntView extends StatefulWidget {
final String collectionName;
final List
TreasureHuntView({required this.collectionName, required this.treasures,});
@override
_TreasureHuntViewState createState() => _TreasureHuntViewState();
}
class _TreasureHuntViewState extends State
int foundTreasures = 0;
lc.LocationData? userLocation;
final lc.Location location = lc.Location();
final hd.HaversineDistance haversineDistance = hd.HaversineDistance();
Duration timeLeft = Duration(minutes: 1);
Timer? timer;
@override
void initState() {
super.initState();
location.getLocation().then((locationData) {
setState(() {
userLocation = locationData;
timer = Timer.periodic(Duration(seconds: 1), (Timer t) {
setState(() {
print(locationData);
timeLeft = timeLeft - Duration(seconds: 1);
if (timeLeft.inSeconds <= 0) {
t.cancel();
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Time is up!"),
content: const Text("You didn't find all the treasures in time."),
actions:
ElevatedButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
ElevatedButton(
child: const Text("Reset"),
onPressed: () {
Navigator.of(context).pop();
setState(() {
timeLeft = Duration(minutes: 10);
foundTreasures = 0;
widget.treasures.forEach((treasure) {
treasure.found = false;
});
});
},
),
],
);
},
);
}
});
});
});
}).catchError((e) {
// Handle the error here
print(e);
});
}
@override
void dispose() {
timer?.cancel();
super.dispose();
}
void _onTreasureTapped(int index) {
double distance = haversineDistance.haversine(
hd.Location(userLocation?.latitude ?? 0, userLocation?.longitude ?? 0),
hd.Location(widget.treasures[index].latitude,
widget.treasures[index].longitude),
hd.Unit.METER);
if (distance <= 20) {
setState(() {
widget.treasures[index].found = true;
foundTreasures++;
});
if (foundTreasures == widget.treasures.length) {
// Store user's details in the leaderboard collection
FirebaseFirestore.instance.collection('leaderboard').add({
'score': widget.treasures.length,
'time': DateTime.now(),
'treasurehunt': widget.collectionName,
});
// Show congratulatory dialog
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Congratulations!"),
content: const Text("You have found all the treasures!"),
actions:
ElevatedButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
ElevatedButton(
child: const Text("Reset"),
onPressed: () {
Navigator.of(context).pop();
setState(() {
foundTreasures = 0;
widget.treasures.forEach((treasure) {
treasure.found = false;
});
});
},
),
],
);
},
);
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Congratulations!"),
content: const Text("You have found a treasure! Keep searching."),
actions:
ElevatedButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Too far"),
content: const Text("You are too far from the treasure"),
actions:
ElevatedButton(
child: const Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:
Text(widget.collectionName, style: TextStyle(color: Colors.white)),
backgroundColor: Color.fromARGB(255, 255, 0, 255),
elevation: 0,
actions:
IconButton(
icon: Icon(Icons.share),
onPressed: () {
Share.share(
'Check out my score in this awesome treasure hunt game!',
subject: 'Treasure Hunt Game',
);
},
)
],
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 10,),
Text('Time left: ${timeLeft.inMinutes}:${timeLeft.inSeconds.remainder(60)}'),
Container(
padding: EdgeInsets.all(16),
child: Text(
"Found ${foundTreasures} of ${widget.treasures.length} treasures"),
),
Expanded(
child: GridView.builder(
itemCount: widget.treasures.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0),
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 5.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
child: Column(
children:
const SizedBox(height: 10.0),
Text(
widget.treasures[index].name,
style: TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10.0),
widget.treasures[index].found
? Icon(
Icons.check,
color: Colors.green,
)
: SizedBox(),
SizedBox(height: 10.0),
InkWell(
onTap: () => _onTreasureTapped(index),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(10.0)),
child: const Center(
child: Text(
"Find Treasure",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
),
)
],
),
);
},
),
),
],
),
);
}
}
below is the home page where the user selects what treasure hunt they want to play and when they select it then it takes them to the treasure hunt list which is the code above with the different treasures find. If you need any more information please do not hesitate to ask thanks
mport 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart' hide NavigationDrawer;
import 'package:google_nav_bar/google_nav_bar.dart';
import 'package:hunt/hunt_views/main_view.dart';
import 'package:hunt/hunt_views/map_view.dart';
import 'package:hunt/hunt_views/profile_view.dart';
import 'package:hunt/hunt_views/settings_view.dart';
import 'package:hunt/hunt_views/treasure_view.dart';
class HomeView extends StatefulWidget {
const HomeView({super.key});
@override
State
}
class _HomeViewState extends State
final user = FirebaseAuth.instance.currentUser!;
final CollectionReference completedTreasureHuntCollection =
FirebaseFirestore.instance.collection(
'completed_treasure_hunts',
);
List
List
List
List
Step by Step Solution
There are 3 Steps involved in it
Step: 1
To integrate the treasure hunt distance view logic into your existing treasure hunt app you can fo...Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started