Compare commits

...

2 commits

5 changed files with 112 additions and 20 deletions

View file

@ -1,3 +1,3 @@
// lib/globals.dart // lib/globals.dart
const String apiurl = "https://api.dthpp.mercurio.moe"; const String apiurl = "https://api.dthpp.mercurio.moe";
//const String apiurl = "http://10.0.0.10:9134"; //const String apiurl = "http://192.168.1.120:9134";

View file

@ -7,6 +7,9 @@ import 'views/joinmatch.dart';
import 'views/creatematch.dart'; import 'views/creatematch.dart';
import 'views/friendlist.dart'; import 'views/friendlist.dart';
import 'views/myprofile.dart'; import 'views/myprofile.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import '../globals.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
@override @override
@ -16,7 +19,6 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage> { class _HomePageState extends State<HomePage> {
int _selectedIndex = 0; int _selectedIndex = 0;
// Define the pages for each section
final List<Widget> _pages = [ final List<Widget> _pages = [
LeaderboardPage(), LeaderboardPage(),
JoinMatchPage(), JoinMatchPage(),
@ -40,14 +42,46 @@ class _HomePageState extends State<HomePage> {
); );
} }
Future<Map<String, String>> fetchCommitHashes() async {
const apiUrl = '$apiurl/version';
try {
final response = await http.get(Uri.parse(apiUrl));
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
String formatHash(String? hash) {
if (hash == null) return 'Unknown';
return '#${hash.substring(0, 8).toUpperCase()}';
}
return {
'backend': formatHash(data['backend']),
'frontend': formatHash(data['frontend']),
};
} else {
throw Exception('Failed to fetch commit hashes');
}
} catch (e) {
return {
'backend': 'Error fetching hash',
'frontend': 'Error fetching hash',
};
}
}
Future<void> _showOpenSourceLicenses() async { Future<void> _showOpenSourceLicenses() async {
final commitHashes = await fetchCommitHashes();
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) => AboutDialog( builder: (BuildContext context) => AboutDialog(
applicationIcon: const Icon(Icons.code), applicationIcon: const Icon(Icons.code),
applicationLegalese: '© 2024 Thomas Bassi @ Defence Tech.', applicationLegalese: '© 2024 Thomas Bassi @ Defence Tech.',
applicationName: 'DTHPP', applicationName: 'DTHPP',
applicationVersion: '#B22AF349A1', applicationVersion:
'API: ${commitHashes['backend']} - UI: ${commitHashes['frontend']}',
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(top: 16.0), padding: const EdgeInsets.only(top: 16.0),

View file

@ -4,6 +4,8 @@ import 'package:http/http.dart' as http;
import 'dart:convert'; import 'dart:convert';
import 'home.dart'; import 'home.dart';
import '../globals.dart'; import '../globals.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
class LoginPage extends StatefulWidget { class LoginPage extends StatefulWidget {
@override @override
@ -21,6 +23,17 @@ class _LoginPageState extends State<LoginPage> {
Future<void> _handleAuth() async { Future<void> _handleAuth() async {
final email = _emailController.text.trim(); final email = _emailController.text.trim();
final password = _passwordController.text.trim(); final password = _passwordController.text.trim();
final displayName = _displayNameController.text.trim();
// Input validation
if (email.isEmpty ||
password.isEmpty ||
(!_isLogin && displayName.isEmpty)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Please fill in all required fields.')),
);
return;
}
setState(() { setState(() {
_isLoading = true; _isLoading = true;
@ -36,8 +49,7 @@ class _LoginPageState extends State<LoginPage> {
context, MaterialPageRoute(builder: (context) => HomePage())); context, MaterialPageRoute(builder: (context) => HomePage()));
} }
} else { } else {
final uid = await _register( final uid = await _register(email, password, displayName);
email, password, _displayNameController.text.trim());
if (uid != null) { if (uid != null) {
setState(() { setState(() {
_isLogin = true; _isLogin = true;
@ -118,21 +130,61 @@ class _LoginPageState extends State<LoginPage> {
decoration: InputDecoration(labelText: 'Display Name'), decoration: InputDecoration(labelText: 'Display Name'),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
_isLoading if (_isLoading)
? CircularProgressIndicator() CircularProgressIndicator()
: ElevatedButton( else
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _handleAuth, onPressed: _handleAuth,
child: Text(_isLogin ? 'Login' : 'Register'), child: Text(_isLogin ? 'Login' : 'Register'),
), ),
TextButton( ElevatedButton(
onPressed: () { onPressed: () {
setState(() { setState(() {
_isLogin = !_isLogin; _isLogin = !_isLogin;
}); });
}, },
child: Text(_isLogin child: Text(_isLogin ? 'Register' : 'Back to Login'),
? 'Don\'t have an account? Register' ),
: 'Already have an account? Login'), ],
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: Icon(FontAwesomeIcons.github),
onPressed: () async {
final url = Uri.parse(
'https://git.mercurio.moe/Mercury/dth-pingpong-mobileapp');
if (await canLaunchUrl(url)) {
await launchUrl(
url,
mode: LaunchMode
.externalApplication, // Ensures it opens in the browser
);
} else {
throw 'Could not launch $url';
}
}),
IconButton(
icon: Icon(FontAwesomeIcons.chartSimple),
onPressed: () async {
final url =
Uri.parse('https://kuma.mercurio.moe/status/dthpp');
if (await canLaunchUrl(url)) {
await launchUrl(
url,
mode: LaunchMode
.externalApplication, // Ensures it opens in the browser
);
} else {
throw 'Could not launch $url';
}
}),
],
), ),
], ],
), ),

View file

@ -13,10 +13,8 @@ class _CreateMatchPageState extends State<CreateMatchPage> {
String? _matchId; String? _matchId;
bool _isLoading = false; bool _isLoading = false;
final String _createMatchApiUrl = final String _createMatchApiUrl = '$apiurl/creatematch';
'$apiurl/creatematch'; // Replace with your API endpoint
// Method to create a match
Future<void> _createMatch() async { Future<void> _createMatch() async {
setState(() { setState(() {
_isLoading = true; _isLoading = true;
@ -90,6 +88,12 @@ class _CreateMatchPageState extends State<CreateMatchPage> {
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
SizedBox(height: 16), SizedBox(height: 16),
Text(
'Due to current limitations in how we handle matchmaking, only the joining player can control the match. This is only a temporary solution to a problem we are actively fixing.',
style: TextStyle(fontSize: 14),
textAlign: TextAlign.center,
),
SizedBox(height: 16),
_isLoading _isLoading
? CircularProgressIndicator() // Show loading spinner ? CircularProgressIndicator() // Show loading spinner
: ElevatedButton( : ElevatedButton(

View file

@ -15,6 +15,8 @@ dependencies:
http: ^1.2.2 http: ^1.2.2
logger: ^2.5.0 logger: ^2.5.0
package_info: ^2.0.2 package_info: ^2.0.2
font_awesome_flutter: ^10.8.0
url_launcher: ^6.3.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: