Refactored

This commit is contained in:
Sewmina 2024-10-28 17:34:48 +05:30
parent fc1f6189e6
commit 2714797fcc
220 changed files with 1996 additions and 776 deletions

BIN
images/token.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
images/vault.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:math';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:mhunt_launcher/Backend/Structures.dart'; import 'package:mhunt_launcher/Backend/Structures.dart';
@ -7,63 +8,68 @@ import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'DebugHelper.dart'; import 'DebugHelper.dart';
class Backend{ class Backend {
static const String API_ENDPOINT = "https://vps.playpoolstudios.com/metahunt/api/launcher/"; static const String API_ENDPOINT = "https://vps.playpoolstudios.com/metahunt/api/launcher/";
static const String SOLOGIN_ENDPOINT = "http://vps.playpoolstudios.com:20017/";
static List<GameData> Games = [ static List<GameData> Games = [
GameData(0,"mhunt","Metahunt", "High-Stake Battle Royale game with Play to earn abilities", "images/mhunt_thumbnail.png", true,"METAHUNT.exe"), GameData(0, "mhunt", "Metahunt", "High-Stake Battle Royale game with Play to earn abilities", "images/mhunt_thumbnail.png", true, "METAHUNT.exe"),
GameData(1,"pop3d","Pop3D", "a game I dont know much about xD", "images/pop3d_thumbnail.png", false, "pop3d.exe"), GameData(1, "pop3d", "Pop3D", "a game I dont know much about xD", "images/pop3d_thumbnail.png", false, "pop3d.exe"),
]; ];
static SharedPreferences? prefs; static SharedPreferences? prefs;
static Directory? docPath; static Directory? docPath;
static String Username=""; static String Username = "";
static String displayName = ""; static String displayName = "";
static String walletAddress = "";
static String pubKey = "";
static Map<String,dynamic> UserJson = {'username':'test', 'passwd':'test123'}; static Map<String, dynamic> UserJson = {'username': 'test', 'passwd': 'test123'};
static Future<bool> Login(String username, String password) async{ static Future<bool> Login(String username, String password) async {
var loginResponse = null; var loginResponse = null;
init(); init();
try { try {
loginResponse = (await http.post(Uri.parse('${API_ENDPOINT}login.php'), loginResponse = (await http.post(Uri.parse('${API_ENDPOINT}login.php'), body: <String, String>{"username": username, "password": password}));
body: <String, String>{"username": username, "password": password})); Debug.LogResponse(loginResponse.body.toString(), src: '${API_ENDPOINT}login.php');
Debug.LogResponse(loginResponse.body.toString(),src: '${API_ENDPOINT}login.php');
if(loginResponse.body.toString().contains("no user")){
return false;
}
try { try {
Username=username; Username = username;
SetUsernamePassword(username, password); SetUsernamePassword(username, password);
return true; return true;
} catch (e) { } catch (e) {}
}
} catch (e) { } catch (e) {
Debug.LogError("Error while login $e"); Debug.LogError("Error while login $e");
return false;
} }
return false; return false;
} }
static void init()async{ static void init() async {
prefs = await SharedPreferences.getInstance(); prefs = await SharedPreferences.getInstance();
docPath = await getDownloadsDirectory(); docPath = await getDownloadsDirectory();
} }
static Future<bool> Register(String username, String password, String displayname) async{ static Future<bool> Register(String username, String password, String displayname) async {
var loginResponse = null; var loginResponse = null;
init(); init();
try { try {
loginResponse = (await http.post(Uri.parse('${API_ENDPOINT}register.php'), loginResponse = (await http.post(Uri.parse('${API_ENDPOINT}register.php'), body: <String, String>{"username": username, "password": password, "display_name": displayname}));
body: <String, String>{"username": username, "password": password, "display_name": displayname})); Debug.LogResponse(loginResponse.body.toString(), src: '${API_ENDPOINT}register.php');
Debug.LogResponse(loginResponse.body.toString(),src: '${API_ENDPOINT}register.php');
try { try {
SetUsernamePassword(username, password); SetUsernamePassword(username, password);
Username = username; Username = username;
displayName=displayname; Debug.Log("User is " + username);
displayName = displayname;
return true; return true;
} catch (e) { } catch (e) {}
}
} catch (e) { } catch (e) {
Debug.LogError("Error while login $e"); Debug.LogError("Error while login $e");
} }
@ -71,44 +77,49 @@ class Backend{
return false; return false;
} }
static void SetUsernamePassword(String username, String passwd){ static Future<String> GetPubkey() async{
UserJson = {'username':username, 'passwd':passwd}; var response = await http.get(Uri.parse('${SOLOGIN_ENDPOINT}getPubkey?email=${Username}'));
pubKey = jsonDecode(response.body.toString())["pub_key"];
return pubKey;
} }
static Future<List<LeaderboardEntry>> GetLeaderboard(String gameCode) async{ static void SetUsernamePassword(String username, String passwd) {
UserJson = {'username': username, 'passwd': passwd};
}
static Future<List<LeaderboardEntry>> GetLeaderboard(String gameCode) async {
String url = '${API_ENDPOINT}/${gameCode}/get_leaderboard.php'; String url = '${API_ENDPOINT}/${gameCode}/get_leaderboard.php';
var leaderboardResponse = await http.get(Uri.parse(url)); var leaderboardResponse = await http.get(Uri.parse(url));
return LeaderboardEntry.listFromJson(leaderboardResponse.body); return LeaderboardEntry.listFromJson(leaderboardResponse.body);
} }
static Future<List<Map<String,dynamic>>> GetNewsForGame(int gameId)async{ static Future<List<Map<String, dynamic>>> GetNewsForGame(int gameId) async {
String url = '${API_ENDPOINT}${Games[gameId].code}/get_news.php'; String url = '${API_ENDPOINT}${Games[gameId].code}/get_news.php';
try{ try {
var res = await http.get(Uri.parse(url)); var res = await http.get(Uri.parse(url));
List<dynamic> jsonList = jsonDecode(res.body); List<dynamic> jsonList = jsonDecode(res.body);
List<Map<String,dynamic>> output = []; List<Map<String, dynamic>> output = [];
jsonList.forEach((element) { jsonList.forEach((element) {
output.add(element as Map<String,dynamic>); output.add(element as Map<String, dynamic>);
}); });
return output; return output;
}catch(e){ } catch (e) {
Debug.LogError(e); Debug.LogError(e);
} }
return [{}]; return [{}];
} }
static Future<Map<String,dynamic>> GetUserStatsForGame(int gameId) async{ static Future<Map<String, dynamic>> GetUserStatsForGame(int gameId) async {
var loginResponse = null; var loginResponse = null;
init(); init();
try { try {
String url = '${API_ENDPOINT}${Games[gameId].code}/get_user_stats.php'; String url = '${API_ENDPOINT}${Games[gameId].code}/get_user_stats.php';
loginResponse = (await http.post(Uri.parse(url), loginResponse = (await http.post(Uri.parse(url), body: <String, String>{"username": Username ?? "test"}));
body: <String, String>{"username": prefs!.getString("username") ?? "test"})); Debug.LogResponse(loginResponse.body.toString(), src: url);
Debug.LogResponse(loginResponse.body.toString(),src: url);
return jsonDecode(loginResponse.body); return jsonDecode(loginResponse.body);
} catch (e) { } catch (e) {
@ -118,13 +129,13 @@ class Backend{
return {}; return {};
} }
static Future<String> CreateRequest() async{ static Future<String> CreateRequest() async {
var loginResponse = null; var loginResponse = null;
try { try {
String url = '${API_ENDPOINT}create_request.php'; String url = '${API_ENDPOINT}create_request.php';
loginResponse = await http.get(Uri.parse(url)); loginResponse = await http.get(Uri.parse(url));
Debug.LogResponse(loginResponse.body.toString(),src: url); Debug.LogResponse(loginResponse.body.toString(), src: url);
return loginResponse.body.toString(); return loginResponse.body.toString();
} catch (e) { } catch (e) {
@ -134,14 +145,13 @@ class Backend{
return "-1"; return "-1";
} }
static Future<String> GetRequestResponse(String id) async{ static Future<String> GetRequestResponse(String id) async {
var loginResponse = null; var loginResponse = null;
try { try {
String url = '${API_ENDPOINT}get_request_response.php'; String url = '${API_ENDPOINT}get_request_response.php';
loginResponse = (await http.post(Uri.parse(url), loginResponse = (await http.post(Uri.parse(url), body: <String, String>{"id": id.toString()}));
body: <String, String>{"id":id.toString()})); Debug.LogResponse(loginResponse.body.toString(), src: url);
Debug.LogResponse(loginResponse.body.toString(),src: url);
return loginResponse.body; return loginResponse.body;
} catch (e) { } catch (e) {
@ -151,14 +161,13 @@ class Backend{
return "-1"; return "-1";
} }
static Future<String> GetDisplayName(String id) async{ static Future<String> GetDisplayName(String id) async {
var response = null; var response = null;
try { try {
String url = '${API_ENDPOINT}get_display_name.php'; String url = '${API_ENDPOINT}get_display_name.php';
response = (await http.post(Uri.parse(url), response = (await http.post(Uri.parse(url), body: <String, String>{"id": id.toString()}));
body: <String, String>{"id":id.toString()})); Debug.LogResponse(response.body.toString(), src: url);
Debug.LogResponse(response.body.toString(),src: url);
return response.body; return response.body;
} catch (e) { } catch (e) {
@ -168,18 +177,17 @@ class Backend{
return "-1"; return "-1";
} }
static Future<bool> GetUsernameValidation(String username) async{ static Future<bool> GetUsernameValidation(String username) async {
var loginResponse = null; var loginResponse = null;
try { try {
String url = '${API_ENDPOINT}validate_username.php'; String url = '${API_ENDPOINT}validate_username.php';
loginResponse = (await http.post(Uri.parse(url), loginResponse = (await http.post(Uri.parse(url), body: <String, String>{"username": username}));
body: <String, String>{"username":username})); Debug.LogResponse(loginResponse.body.toString(), src: url);
Debug.LogResponse(loginResponse.body.toString(),src: url);
if(loginResponse.body == "0"){ if (loginResponse.body == "0") {
return true; return true;
}else{ } else {
return false; return false;
} }
} catch (e) { } catch (e) {
@ -188,10 +196,39 @@ class Backend{
return false; return false;
} }
static Future<String> GetNextGuestUsername() async{
try{
String url = '${API_ENDPOINT}get_next_guest_username.php';
var response = await http.get(Uri.parse(url));
return response.body.toString();
}catch(e){
}
Random random = new Random();
return 'guest ${random.nextInt(10000000)}';
}
static VaultData vault = VaultData('0x0', 0, 0);
static Future<VaultData> RefreshVaultData() async{
var response = null;
try{
String url = '${API_ENDPOINT}get_vault_data.php';
response = (await http.post(Uri.parse(url), body: <String,String>{"id": Username}));
Debug.LogResponse(response.body.toString(), src:url);
vault = jsonDecode(response.body.toString());
}catch(e){
}
return vault;
}
} }
class GameData {
class GameData{
int id; int id;
String code; String code;
String name; String name;
@ -200,5 +237,13 @@ class GameData{
bool isAvailable; bool isAvailable;
String exeName; String exeName;
GameData(this.id,this.code,this.name,this.description,this.imagePath,this.isAvailable,this.exeName); GameData(this.id, this.code, this.name, this.description, this.imagePath, this.isAvailable, this.exeName);
}
class VaultData{
String address;
int vc;
int php;
VaultData(this.address, this.vc, this.php);
} }

View File

@ -35,14 +35,16 @@ class InstallHelper{
localFiles = await getHashtable(pathDir); localFiles = await getHashtable(pathDir);
} }
//Get local hashtable //Get local hashtable
// Debug.Log(localFilesJson); Debug.LogResponse(jsonEncode(localFiles), src:"local files");
//Write to file //Write to file
if(!usedLocalSave){ if(!usedLocalSave){
String localFilesJson = FileHashEntry.listToJson(localFiles); String localFilesJson = FileHashEntry.listToJson(localFiles);
Backend.prefs!.setString(GetValidationSaveKey(gameId),localFilesJson); Backend.prefs!.setString(GetValidationSaveKey(gameId),localFilesJson);
if(kDebugMode) { if(kDebugMode) {
File writeJsonFile = File(Path.join(pathDir.parent.path, "hashes.txt")); String hashFilePath = Path.join(pathDir.parent.path, "hashes.txt");
File writeJsonFile = File(hashFilePath);
writeJsonFile.writeAsString(localFilesJson); writeJsonFile.writeAsString(localFilesJson);
Debug.Log("Wrote hash into ${hashFilePath}");
} }
} }

39
lib/Shared/Dialogs.dart Normal file
View File

@ -0,0 +1,39 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../main.dart';
class Dialogs{
static showAlertDialog(BuildContext context, String title, String message) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
backgroundColor: Color(0xFF1F1F1F),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: Text(title),
content: Text(message),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
}

View File

@ -0,0 +1,75 @@
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher_string.dart';
import '../../Backend/Backend.dart';
import '../CustomWidgets.dart';
Widget AccountPage(){
return Padding(
padding: const EdgeInsets.all(25.0),
child: Column(
children: [
Row(
children: [
Text("Hello, ${Backend.displayName}", style: TextStyle(fontSize: 30)),
],
),
SizedBox(height: 100,),
Text(Backend.pubKey),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
Text("Vault Credits",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 15),),
Row(
children: [
Image.asset('images/vault.png',width: 40,height: 40,),
Text(Backend.vault.php.toString(),style: TextStyle(fontSize: 50),),
],
)
],
),
SizedBox(width: 60,),
Column(
children: [
Text("Pre-hunt Points",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 15),),
Row(
children: [
Image.asset('images/token.png',width: 40,height: 40,),
Text(Backend.vault.vc.toString(),style: TextStyle(fontSize: 50),),
],
)
],
),
],
),
// Text("Your wallet address is "),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Text(Backend.walletAddress, style: TextStyle(fontSize: 25),),
// InkWell(child: Padding(
// padding: const EdgeInsets.all(16.0),
// child: Icon(Icons.copy),
// ), onTap: (){
// //Copy wallet
// },)
// ],
// ),
SizedBox(height: 50,),
GlassButton(onTap: (){
launchUrlString('https://auth.playpoolstudios.com');
}, child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Open Dashboard"),
SizedBox(width: 10,),
Icon(Icons.open_in_new, color: Colors.grey)
],
), width: 250, height: 50)
],
),
);
}

View File

@ -0,0 +1,342 @@
import 'dart:io';
import 'package:filepicker_windows/filepicker_windows.dart';
import 'package:flutter/material.dart';
import '../../Backend/Backend.dart';
import '../../Backend/FileHashEntry.dart';
import '../../Backend/InstallHelper.dart';
import '../../Backend/Structures.dart';
import '../CustomWidgets.dart';
Widget Dashboard({
required BuildContext context,
required Map<int, List<FileHashEntry>> downloadQueue,
required int dashboardSelectedGameIndex,
required List<FileHashEntry> missingFilesForSelectedGame,
required bool calculatingFiles,
required bool isUninstalling,
required bool isRunning,
required Map<String, dynamic> myStatsForSelectedGame,
required List<LeaderboardEntry> leaderboardForSelectedGame,
required List<Map<String, dynamic>> newsForSelectedGame,
required Function(int) onSelectedGameChanged,
required Function onUpdate,
required Function(int) onUninstallClicked,
required dynamic OnGameActionButtonClicked,
}) {
GameData selectedGameData = Backend.Games[dashboardSelectedGameIndex];
String filePath = InstallHelper.GetFilePath(dashboardSelectedGameIndex);
bool folderExists = Directory(filePath).existsSync();
String ActionBtnTxt = "Install";
if (missingFilesForSelectedGame.length <= 0) {
ActionBtnTxt = "Play";
} else {
ActionBtnTxt =
("Download ${FileHashEntry.getTotalSizeInMbytes(missingFilesForSelectedGame).toStringAsFixed(0)} MB");
}
if (calculatingFiles) {
ActionBtnTxt = "Validating";
}
if (downloadQueue.containsKey(dashboardSelectedGameIndex)) {
ActionBtnTxt = "Downloading";
}
if (isUninstalling) {
ActionBtnTxt = "Uninstalling";
}
if(isRunning){
ActionBtnTxt = "Running";
}
Widget ActionButton = GlassButton(
onTap: OnGameActionButtonClicked,
child: Text(ActionBtnTxt),
width: 200,
color: Colors.blue,
opacity: 0.5,
height: 50);
final screenHeight = MediaQuery.of(context).size.height;
List<DataRow> leaderboardList = [];
// leaderboardList.add(TableRow(children: [Text("username"),Text("kills"), Text("deaths")]));
// leaderboardList.add(TableRow());
leaderboardList
.addAll(List.generate(leaderboardForSelectedGame.length, (i) {
return DataRow(cells: <DataCell>[
DataCell(Text(leaderboardForSelectedGame[i].place.toString())),
DataCell(Text(leaderboardForSelectedGame[i].username)),
DataCell(Text(leaderboardForSelectedGame[i].kills.toString())),
DataCell(Text(leaderboardForSelectedGame[i].deaths.toString())),
DataCell(Text(leaderboardForSelectedGame[i].xp.toString())),
]);
}));
return Theme(
data: ThemeData(splashColor: Colors.transparent),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: screenHeight * 0.18,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
selectedGameData.name,
style: TextStyle(fontSize: 25),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(Backend.Games.length, (index) {
bool isSelected = index == dashboardSelectedGameIndex;
return InkWell(
onTap: (){
onSelectedGameChanged(index);
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 100),
margin: EdgeInsets.all(9),
height: 80 * (isSelected ? 1.5 : 1),
width: 130 * (isSelected ? 1.5 : 1),
decoration: BoxDecoration(
image: DecorationImage(
image:
AssetImage(Backend.Games[index].imagePath),
fit: BoxFit.fill),
borderRadius: BorderRadius.circular(20)),
),
);
}),
),
],
),
),
!Backend.Games[dashboardSelectedGameIndex].isAvailable
? Center(
child: Text("Coming Soon", style: TextStyle(fontSize: 40)))
: Container(
height: screenHeight * 0.72,
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 50),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ActionButton,
PopupMenuButton<String>(
iconColor: Colors.blueGrey,
onSelected: (val) {
if (val.toLowerCase().contains("uninstall")) {
onUninstallClicked(dashboardSelectedGameIndex);
}
},
itemBuilder: (BuildContext context) {
return {'Uninstall'}.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
),
GlassCard(
color: Colors.green,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text("My Stats",
style:
TextStyle(color: Colors.blueGrey)),
SizedBox(
width: 50,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Kills : ${(myStatsForSelectedGame['kills'] ?? "0")}"),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Deaths : ${(myStatsForSelectedGame['deaths'] ?? "0")}"),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Assist : ${(myStatsForSelectedGame['assists'] ?? "0")}"),
),
],
),
),
),
Container()
],
),
),
Container(
height: screenHeight * 0.6,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Padding(
padding: const EdgeInsets.all(20.0),
child: GlassCard(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
width: 350,
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 12.0, horizontal: 20),
child: Text(
"News",
style: TextStyle(fontSize: 20),
),
),
Expanded(
child: SingleChildScrollView(
child: Column(
children: List.generate(
newsForSelectedGame.length,
(index) {
return NewsCard(
newsForSelectedGame[index]
['title'],
newsForSelectedGame[index]
['message']);
}),
),
),
)
],
),
)),
),
SizedBox(
width: 50,
),
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(
0, 20, 0, 0),
child: Text(
"Leaderboard",
style: TextStyle(fontSize: 20),
),
),
DataTable(
dataTextStyle:
TextStyle(color: Colors.white),
headingTextStyle:
TextStyle(color: Colors.white),
dividerThickness: 0,
columns: [
DataColumn(
label:
Expanded(child: Text("Place"))),
DataColumn(
label: Expanded(
child: Text("Username"))),
DataColumn(
label:
Expanded(child: Text("Kills"))),
DataColumn(
label: Expanded(
child: Text("Deaths"))),
DataColumn(
label: Expanded(child: Text("XP"))),
],
rows: leaderboardList,
),
],
),
),
],
))
],
),
),
Container(
//Install path footer
padding: EdgeInsets.symmetric(horizontal: 10),
alignment: Alignment.bottomCenter,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(children: [Text("Install path "), Text(filePath)]),
GlassButton(
onTap: () {
DirectoryPicker file = DirectoryPicker();
final dir = file.getDirectory();
Backend.prefs!.setString(
'${selectedGameData.name}_path', dir!.path);
onUpdate();
},
child: Text("Change Install Location"),
width: 250)
],
),
SizedBox(
height: 10,
)
],
),
)
],
),
);
}
Widget NewsCard(String title, String message) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: GlassCard(
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(18.0),
child: Icon(
Icons.newspaper,
color: Colors.blueGrey,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(fontSize: 18),
textAlign: TextAlign.left,
),
Text(
message,
overflow: TextOverflow.clip,
)
],
)
],
)),
);
}

View File

@ -0,0 +1,129 @@
import 'package:flutter/material.dart';
import '../../Backend/Backend.dart';
import '../../Backend/FileHashEntry.dart';
import '../CustomWidgets.dart';
Widget DownloadCard({
required int gameId,
required Map<int, Map<FileHashEntry, num>> downloadProgress,
required Map<int, double> totalDownloadSize,
required Map<int, List<FileHashEntry>> downloadQueue,
required bool downloadRunning,
required Function(int) onChanged
}) {
int doneSize = 0;
if (downloadProgress.containsKey(gameId)) {
Map<FileHashEntry, num> _progress = downloadProgress[gameId]!;
_progress.forEach((key, value) {
doneSize += value.toInt();
});
}
double totalSize = totalDownloadSize[gameId]! / 1024 / 1024;
double doneSizeMb = doneSize / 1024 / 1024;
double progress = doneSizeMb / totalSize;
return Padding(
padding: const EdgeInsets.all(8.0),
child: GlassCard(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image:
AssetImage(Backend.Games[gameId].imagePath)),
borderRadius: BorderRadius.circular(50)),
width: 160,
height: 80,
),
Column(
children: [
Text(
Backend.Games[gameId].name,
style: TextStyle(fontSize: 20),
),
Text((doneSizeMb).toStringAsFixed(2) +
" MB" +
" / " +
totalSize.toStringAsFixed(2) +
" MB")
],
)
],
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 50, 20, 20),
child: LinearProgressIndicator(
value: progress,
backgroundColor: Colors.black.withOpacity(0.2),
color: Colors.blue,
),
),
),
InkWell(
child: Icon(Icons.cancel,
size: 40, color: Colors.red.withOpacity(0.6)),
onTap: () {
downloadQueue.remove(gameId);
downloadProgress.remove(gameId);
downloadRunning = false;
onChanged(gameId);
},
)
// Icon(Icons.download,size: 40,color: Colors.green.withOpacity(0.4),)
],
)
],
),
)),
);
}
Widget Downloads({
required Map<int, List<FileHashEntry>> downloadQueue,
required Map<int, Map<FileHashEntry, num>> downloadProgress,
required Map<int, double> totalDownloadSize,
required bool downloadRunning,
required Function(int) onChanged
}) {
if (downloadQueue.length <= 0) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.download_done_sharp,
size: 100,
color: Colors.white.withOpacity(0.5),
),
Text(
"No ongoing Downloads",
style:
TextStyle(fontSize: 40, color: Colors.white.withOpacity(0.4)),
),
],
),
);
}
return Container(
child: Container(
padding: EdgeInsets.all(100),
child: GlassCard(
child: Column(
children: List.generate(downloadQueue.keys.length, (index) {
int gameId = downloadQueue.keys.toList()[index];
return DownloadCard(gameId: gameId, downloadQueue:downloadQueue, downloadProgress: downloadProgress, downloadRunning: downloadRunning, totalDownloadSize: totalDownloadSize, onChanged: onChanged );
}),
))));
}

View File

@ -0,0 +1,98 @@
import 'package:flutter/material.dart';
import '../../Backend/Backend.dart';
import '../CustomWidgets.dart';
String hoveringGameCard = "";
Widget Library({
required int selectedSidebarIndex,
required Function(int) onGameChanged,
required Function onUpdate,
}) {
return Center(
child: Wrap(
spacing: 20,
children: List.generate(Backend.Games.length, (index) {
GameData gameData = Backend.Games[index];
return LibGameCard(
gameData: gameData,
selectedSidebarIndex: selectedSidebarIndex,
onUpdate: onUpdate,
onGameChanged: onGameChanged
);
}),
),
);
}
Widget LibGameCard({
required GameData gameData,
required int selectedSidebarIndex,
required Function(int) onGameChanged,
required Function onUpdate,
}) {
return InkWell(
onTap: () {
selectedSidebarIndex = 1;
onGameChanged(gameData.id);
},
onHover: (val) {
if (val) {
hoveringGameCard = gameData.name;
} else if (hoveringGameCard == gameData.name) {
hoveringGameCard = "";
}
onUpdate();
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 500),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.black,
image: DecorationImage(
image: AssetImage(gameData.imagePath), fit: BoxFit.fill)),
height: 200,
width: 300,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
hoveringGameCard != gameData.name
? Container()
: Expanded(
child: GlassContainer(
child: Center(
child: Text(
gameData.description,
textAlign: TextAlign.center,
),
),
opacity: 0.5,
color: Colors.black)),
GlassContainer(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: true? Container():Row(
children: [
Text(gameData.name),
gameData.isAvailable
? GlassButton(
onTap: () {},
child: Text("Install"),
width: 100,
color: Colors.blue,
opacity: 0.8)
: Text("Coming soon")
],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
),
),
opacity: 0.9,
color: Colors.black),
],
),
),
);
}

View File

@ -0,0 +1,127 @@
import 'package:flutter/material.dart';
import '../../Backend/Backend.dart';
import '../CustomWidgets.dart';
int selectedSidebarIndex = 0;
Widget SideBar(
{required double width, required double height,required Function(int) onChanged, int selectedIndex = 0}) {
return GlassContainer(
child: Container(
width: width,
height: height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
SizedBox(
height: 100,
),
SidebarTitle("Library", Icons.laptop_chromebook_outlined, onChanged,
index: 0),
SidebarTitle("Dashboard", Icons.dashboard,onChanged, index: 1),
SidebarTitle("Downloads", Icons.download,onChanged, index: 2),
],
),
InkWell(
onTap:(){
selectedSidebarIndex=3;
onChanged(3);
},
child: GlassContainer(child: Padding(
padding: const EdgeInsets.fromLTRB(10,0,10,10),
child: Row(
children: [
Icon(Icons.supervised_user_circle_rounded, size: 50),
SizedBox(width: 15,),
Column(crossAxisAlignment:CrossAxisAlignment.start,children: [
Text(Backend.displayName,style: TextStyle(fontSize: 24),),
// Text("Vault credits : 50")
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 10,vertical: 2),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.black.withAlpha(100)),
child: Row(
children: [
Container(
height: 30,
width: 30,
child: Image.asset('images/vault.png'),
),
SizedBox(width: 5,),
Text(Backend.vault.vc.toString())
],
),
),
SizedBox(width: 5,),
Container(
padding: EdgeInsets.symmetric(horizontal: 10,vertical: 2),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.black.withAlpha(100)),
child: Row(
children: [
Container(
height: 30,
width: 30,
child: Image.asset('images/token.png'),
),
SizedBox(width: 5,),
Text(Backend.vault.php.toString())
],
),
),
],
)
],
),
],)
],
),
)),
)
],
),
),
opacity: 0.15,
color: Colors.blueGrey);
}
Widget SidebarTitle(String title, IconData iconData, Function(int) onChanged, {int index = 0}) {
return InkWell(
onTap: () {
selectedSidebarIndex = index;
onChanged(index);
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 0),
child: GlassContainer(
opacity: selectedSidebarIndex == index ? 0.1 : 0,
color:
selectedSidebarIndex == index ? Colors.white : Colors.transparent,
child: Container(
height: 75,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(iconData),
SizedBox(
width: 20,
),
Text(
title,
style: TextStyle(fontSize: 20),
),
],
),
),
),
),
);
}

View File

@ -1,10 +1,11 @@
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:mhunt_launcher/home.dart'; import 'package:mhunt_launcher/home.dart';
import 'package:process_run/shell.dart'; import 'package:mhunt_launcher/login.dart';
class UpdateCheckScreen extends StatefulWidget { class UpdateCheckScreen extends StatefulWidget {
const UpdateCheckScreen({super.key}); const UpdateCheckScreen({super.key});
@ -15,8 +16,8 @@ class UpdateCheckScreen extends StatefulWidget {
class _UpdateCheckScreenState extends State<UpdateCheckScreen> { class _UpdateCheckScreenState extends State<UpdateCheckScreen> {
int localVersion = 0; int localVersion = 4;
String otaPath = Directory.current.path + "\\ota_wrapper_v2.exe"; String otaPath = Directory.current.path + "\\ota_wrapper_silent.vbs";
@override @override
void initState() { void initState() {
@ -25,31 +26,35 @@ class _UpdateCheckScreenState extends State<UpdateCheckScreen> {
CheckForUpdates(); CheckForUpdates();
} }
Future<List<ProcessResult>> runExecutable(String executable) async {
return await run(executable);
}
void CheckForUpdates() async{ void CheckForUpdates() async{
// http.Response remoteVersionResponse = await http.get(Uri.parse("https://vps.playpoolstudios.com/metahunt/api/launcher/get_version.php")); http.Response remoteVersionResponse = await http.get(Uri.parse("https://vps.playpoolstudios.com/metahunt/data/bin/launcher_win/get_version_code.php"));
// int remoteVersion = int.parse(remoteVersionResponse.body); int remoteVersion = int.parse(remoteVersionResponse.body);
if(!await File(otaPath).exists()){ print("local version:${localVersion}, remote version:${remoteVersion}");
print("otapath not existing"); if(remoteVersion>localVersion){
setState(() { updateStatus = 1;
updateStatus=2; }else{
}); updateStatus=2;
return; Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context)=> LoginPage()));
} }
try { // if(!await File(otaPath).exists()){
// print("otapath not existing");
final result = await runExecutable(otaPath + " noupdate"); // setState(() {
if (result[0].stdout.trim() == '0') { // updateStatus=2;
updateStatus = 2; // });
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context)=> HomePage())); // return;
}else{ // }
updateStatus = 1; // try {
} //
} catch (e) { // final result = await runExecutable(otaPath + " noupdate");
print('Error running the executable: $e'); // if (result[0].stdout.trim() == '0') {
} // updateStatus = 2;
// Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context)=> LoginPage()));
// }else{
// updateStatus = 1;
// }
// } catch (e) {
// print('Error running the executable: $e');
// }
setState(() { setState(() {
@ -57,10 +62,16 @@ class _UpdateCheckScreenState extends State<UpdateCheckScreen> {
}); });
} }
void update() async{ void update() async{
await Process.start(otaPath,[], runInShell: true); // await Process.start(otaPath,[], runInShell: true);
// await Future.delayed(const Duration(seconds: 5)); //
final process = await Process.start('wscript',[otaPath], runInShell: true);
updateStatus = 2; updateStatus = 2;
process.stdout.transform(utf8.decoder).listen((data) {
});
process.stderr.transform(utf8.decoder).listen((data) {
print(data);
});
await Future.delayed(const Duration(seconds: 1));
exit(0); exit(0);
setState(() { setState(() {

View File

@ -14,11 +14,17 @@ import 'package:mhunt_launcher/sidebar.dart';
import 'package:process_run/process_run.dart'; import 'package:process_run/process_run.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:path/path.dart' as Path; import 'package:path/path.dart' as Path;
import 'package:url_launcher/url_launcher_string.dart';
import 'Backend/DebugHelper.dart'; import 'Backend/DebugHelper.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'Backend/FileHashEntry.dart'; import 'Backend/FileHashEntry.dart';
import 'Backend/Structures.dart'; import 'Backend/Structures.dart';
import 'Widgets/Home/AccountsPage.dart';
import 'Widgets/Home/Dashboard.dart';
import 'Widgets/Home/Downloads.dart';
import 'Widgets/Home/Library.dart';
import 'Widgets/Home/Sidebar.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
const HomePage({super.key}); const HomePage({super.key});
@ -39,14 +45,38 @@ class _HomePageState extends State<HomePage> {
bool downloadRunning = false; bool downloadRunning = false;
int unwaitingFiles = 0; int unwaitingFiles = 0;
int dashboardSelectedGameIndex = 0; int dashboardSelectedGameIndex = 0;
String userPubKey = "loading";
@override @override
void initState() { void initState() {
// TODO: implement initState // TODO: implement initState
super.initState(); super.initState();
kickstartAnimations(); kickstartAnimations();
initData();
SetSelectedDashboardGame(0); SetSelectedDashboardGame(0);
SetVaultUpdateLoop();
}
void SetVaultUpdateLoop() async{
while(true){
await Backend.RefreshVaultData();
setState(() {
});
await Future.delayed(const Duration(seconds: 30));
}
}
void initData()async{
userPubKey= await Backend.GetPubkey();
setState(() {
});
} }
void kickstartAnimations() async { void kickstartAnimations() async {
@ -63,11 +93,50 @@ class _HomePageState extends State<HomePage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height; final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width; final screenWidth = MediaQuery.of(context).size.width;
Widget content = Library(); Widget content = Library(
selectedSidebarIndex: selectedSidebarIndex,
onGameChanged: SetSelectedDashboardGame,
onUpdate: (){
setState(() {
});
}
);
if (selectedSidebarIndex == 1) { if (selectedSidebarIndex == 1) {
content = Dashboard(); content = Dashboard(
context: context,
downloadQueue: downloadQueue,
dashboardSelectedGameIndex: dashboardSelectedGameIndex,
missingFilesForSelectedGame: missingFilesForSelectedGame,
calculatingFiles: calculatingFiles,
isRunning: runningProcs.containsKey(dashboardSelectedGameIndex),
isUninstalling: isUninstalling,
myStatsForSelectedGame: myStatsForSelectedGame,
leaderboardForSelectedGame: leaderboardForSelectedGame,
newsForSelectedGame: newsForSelectedGame,
onSelectedGameChanged: SetSelectedDashboardGame,
onUninstallClicked: UninstallGame,
OnGameActionButtonClicked: OnGameActionButtonClicked,
onUpdate: (){
setState(() {
});
}
);
} else if (selectedSidebarIndex == 2) { } else if (selectedSidebarIndex == 2) {
content = Downloads(); content = Downloads(
downloadQueue: downloadQueue,
downloadRunning: downloadRunning,
downloadProgress: downloadProgress,
totalDownloadSize: totalDownloadSize,
onChanged: (val){
setState(() {
SetSelectedDashboardGame(val);
});
}
);
}else if(selectedSidebarIndex == 3){ }else if(selectedSidebarIndex == 3){
content = AccountPage(); content = AccountPage();
} }
@ -83,7 +152,11 @@ class _HomePageState extends State<HomePage> {
children: [ children: [
SideBar( SideBar(
width: screenWidth * 0.2, width: screenWidth * 0.2,
height: screenHeight, height: screenHeight, onChanged: (val){
setState(() {
selectedSidebarIndex = val;
});
},
), ),
SizedBox( SizedBox(
width: screenWidth * 0.8, width: screenWidth * 0.8,
@ -96,301 +169,7 @@ class _HomePageState extends State<HomePage> {
); );
} }
Widget Library() {
return Center(
child: Wrap(
spacing: 20,
children: List.generate(Backend.Games.length, (index) {
GameData gameData = Backend.Games[index];
return LibGameCard(gameData);
}),
),
);
}
Widget AccountPage(){
return Padding(
padding: const EdgeInsets.all(25.0),
child: Column(
children: [
Row(
children: [
Text("Hello, ${Backend.displayName}", style: TextStyle(fontSize: 30)),
],
),
],
),
);
}
Widget Downloads() {
if (downloadQueue.length <= 0) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.download_done_sharp,
size: 100,
color: Colors.white.withOpacity(0.5),
),
Text(
"No ongoing Downloads",
style:
TextStyle(fontSize: 40, color: Colors.white.withOpacity(0.4)),
),
],
),
);
}
return Container(
child: Container(
padding: EdgeInsets.all(100),
child: GlassCard(
child: Column(
children: List.generate(downloadQueue.keys.length, (index) {
int gameId = downloadQueue.keys.toList()[index];
return DownloadCard(gameId, downloadQueue[gameId]!);
}),
))));
}
Widget DownloadCard(int gameId, List<FileHashEntry> files) {
int doneSize = 0;
if (downloadProgress.containsKey(gameId)) {
Map<FileHashEntry, num> _progress = downloadProgress[gameId]!;
_progress.forEach((key, value) {
doneSize += value.toInt();
});
}
double totalSize = totalDownloadSize[gameId]! / 1024 / 1024;
double doneSizeMb = doneSize / 1024 / 1024;
double progress = doneSizeMb / totalSize;
return Padding(
padding: const EdgeInsets.all(8.0),
child: GlassCard(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image:
AssetImage(Backend.Games[gameId].imagePath)),
borderRadius: BorderRadius.circular(50)),
width: 160,
height: 80,
),
Column(
children: [
Text(
Backend.Games[gameId].name,
style: TextStyle(fontSize: 20),
),
Text((doneSizeMb).toStringAsFixed(2) +
" MB" +
" / " +
totalSize.toStringAsFixed(2) +
" MB")
],
)
],
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 50, 20, 20),
child: LinearProgressIndicator(
value: progress,
backgroundColor: Colors.black.withOpacity(0.2),
color: Colors.blue,
),
),
),
InkWell(
child: Icon(Icons.cancel,
size: 40, color: Colors.red.withOpacity(0.6)),
onTap: () {
downloadQueue.remove(gameId);
downloadProgress.remove(gameId);
downloadRunning = false;
SetSelectedDashboardGame(gameId);
setState(() {});
},
)
// Icon(Icons.download,size: 40,color: Colors.green.withOpacity(0.4),)
],
)
],
),
)),
);
}
Widget SideBar(
{required double width, required double height, int selectedIndex = 0}) {
return GlassContainer(
child: Container(
width: width,
height: height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// SizedBox(width: 10,),
// Text("10")
// ],
// ),
// ),
SizedBox(
height: 100,
),
SidebarTitle("Library", Icons.laptop_chromebook_outlined,
index: 0),
SidebarTitle("Dashboard", Icons.dashboard, index: 1),
SidebarTitle("Downloads", Icons.download, index: 2),
],
),
InkWell(
onTap:(){
setState(() {
selectedSidebarIndex=3;
});
},
child: GlassContainer(child: Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
children: [
Icon(Icons.supervised_user_circle_rounded, size: 50),
SizedBox(width: 15,),
Column(crossAxisAlignment:CrossAxisAlignment.start,children: [
Text(Backend.displayName,style: TextStyle(fontSize: 24),),
// Text("Vault credits : 50")
],)
],
),
)),
)
],
),
),
opacity: 0.15,
color: Colors.blueGrey);
}
Widget SidebarTitle(String title, IconData iconData, {int index = 0}) {
return InkWell(
onTap: () {
setState(() {
selectedSidebarIndex = index;
});
},
child: Padding(
padding: EdgeInsets.symmetric(vertical: 0),
child: GlassContainer(
opacity: selectedSidebarIndex == index ? 0.1 : 0,
color:
selectedSidebarIndex == index ? Colors.white : Colors.transparent,
child: Container(
height: 75,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(iconData),
SizedBox(
width: 20,
),
Text(
title,
style: TextStyle(fontSize: 20),
),
],
),
),
),
),
);
}
String hoveringGameCard = "";
Widget LibGameCard(GameData gameData) {
return InkWell(
onTap: () {
selectedSidebarIndex = 1;
SetSelectedDashboardGame(gameData.id);
},
onHover: (val) {
if (val) {
hoveringGameCard = gameData.name;
} else if (hoveringGameCard == gameData.name) {
hoveringGameCard = "";
}
setState(() {});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 500),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.black,
image: DecorationImage(
image: AssetImage(gameData.imagePath), fit: BoxFit.fill)),
height: 200,
width: 300,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
hoveringGameCard != gameData.name
? Container()
: Expanded(
child: GlassContainer(
child: Center(
child: Text(
gameData.description,
textAlign: TextAlign.center,
),
),
opacity: 0.5,
color: Colors.black)),
GlassContainer(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: true? Container():Row(
children: [
Text(gameData.name),
gameData.isAvailable
? GlassButton(
onTap: () {},
child: Text("Install"),
width: 100,
color: Colors.blue,
opacity: 0.8)
: Text("Coming soon")
],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
),
),
opacity: 0.9,
color: Colors.black),
],
),
),
);
}
void SetSelectedDashboardGame(int i) async { void SetSelectedDashboardGame(int i) async {
calculatingFiles = true; calculatingFiles = true;
@ -448,7 +227,7 @@ class _HomePageState extends State<HomePage> {
if(runningProcs.containsKey(id)){return;} if(runningProcs.containsKey(id)){return;}
String exePath = InstallHelper.GetExeFilePath(dashboardSelectedGameIndex); String exePath = InstallHelper.GetExeFilePath(dashboardSelectedGameIndex);
// Process proc = await run(exePath,); // Process proc = await run(exePath,);
runningProcs.putIfAbsent(id, ()=> run(exePath + " username ${Backend.UserJson['username']} password ${Backend.UserJson['passwd']}")); runningProcs.putIfAbsent(id, ()=> run(exePath + " username ${Backend.Username} password ${Backend.UserJson['passwd']}"));
setState(() { setState(() {
}); });
@ -475,11 +254,6 @@ class _HomePageState extends State<HomePage> {
bool isUninstalling = false; bool isUninstalling = false;
void UninstallGame(int id) async { void UninstallGame(int id) async {
if(runningProcs.containsKey(id)){return;} if(runningProcs.containsKey(id)){return;}
// String exeFilePath = InstallHelper.GetExeFilePath(id);
// if(!File(exeFilePath).existsSync()){
// Debug.LogError("No game installed to uninstall");
// return;
// }
isUninstalling = true; isUninstalling = true;
setState(() {}); setState(() {});
@ -592,322 +366,4 @@ class _HomePageState extends State<HomePage> {
}); });
}); });
} }
Widget Dashboard() {
GameData selectedGameData = Backend.Games[dashboardSelectedGameIndex];
String filePath = InstallHelper.GetFilePath(dashboardSelectedGameIndex);
bool folderExists = Directory(filePath).existsSync();
String ActionBtnTxt = "Install";
if (missingFilesForSelectedGame.length <= 0) {
ActionBtnTxt = "Play";
} else {
ActionBtnTxt =
("Download ${FileHashEntry.getTotalSizeInMbytes(missingFilesForSelectedGame).toStringAsFixed(0)} MB");
}
if (calculatingFiles) {
ActionBtnTxt = "Validating";
}
if (downloadQueue.containsKey(dashboardSelectedGameIndex)) {
ActionBtnTxt = "Downloading";
}
if (isUninstalling) {
ActionBtnTxt = "Uninstalling";
}
if(runningProcs.containsKey(dashboardSelectedGameIndex)){
ActionBtnTxt = "Running";
}
Widget ActionButton = GlassButton(
onTap: OnGameActionButtonClicked,
child: Text(ActionBtnTxt),
width: 200,
color: Colors.blue,
opacity: 0.5,
height: 50);
final screenHeight = MediaQuery.of(context).size.height;
List<DataRow> leaderboardList = [];
// leaderboardList.add(TableRow(children: [Text("username"),Text("kills"), Text("deaths")]));
// leaderboardList.add(TableRow());
leaderboardList
.addAll(List.generate(leaderboardForSelectedGame.length, (i) {
return DataRow(cells: <DataCell>[
DataCell(Text(leaderboardForSelectedGame[i].place.toString())),
DataCell(Text(leaderboardForSelectedGame[i].username)),
DataCell(Text(leaderboardForSelectedGame[i].kills.toString())),
DataCell(Text(leaderboardForSelectedGame[i].deaths.toString())),
DataCell(Text(leaderboardForSelectedGame[i].xp.toString())),
]);
}));
return Theme(
data: ThemeData(splashColor: Colors.transparent),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: screenHeight * 0.18,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
selectedGameData.name,
style: TextStyle(fontSize: 25),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(Backend.Games.length, (index) {
bool isSelected = index == dashboardSelectedGameIndex;
return InkWell(
onTap: () {
SetSelectedDashboardGame(index);
setState(() {});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 100),
margin: EdgeInsets.all(9),
height: 80 * (isSelected ? 1.5 : 1),
width: 130 * (isSelected ? 1.5 : 1),
decoration: BoxDecoration(
image: DecorationImage(
image:
AssetImage(Backend.Games[index].imagePath),
fit: BoxFit.fill),
borderRadius: BorderRadius.circular(20)),
),
);
}),
),
],
),
),
!Backend.Games[dashboardSelectedGameIndex].isAvailable
? Center(
child: Text("Coming Soon", style: TextStyle(fontSize: 40)))
: Container(
height: screenHeight * 0.72,
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 50),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ActionButton,
PopupMenuButton<String>(
iconColor: Colors.blueGrey,
onSelected: (val) {
if (val
.toLowerCase()
.contains("uninstall")) {
UninstallGame(dashboardSelectedGameIndex);
}
},
itemBuilder: (BuildContext context) {
return {'Uninstall'}.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
),
GlassCard(
color: Colors.green,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text("My Stats",
style:
TextStyle(color: Colors.blueGrey)),
SizedBox(
width: 50,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Kills : ${(myStatsForSelectedGame['kills'] ?? "0")}"),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Deaths : ${(myStatsForSelectedGame['deaths'] ?? "0")}"),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Assist : ${(myStatsForSelectedGame['assists'] ?? "0")}"),
),
],
),
),
),
],
),
),
Container(
height: screenHeight * 0.6,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Padding(
padding: const EdgeInsets.all(20.0),
child: GlassCard(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
width: 350,
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 12.0, horizontal: 20),
child: Text(
"News",
style: TextStyle(fontSize: 20),
),
),
Expanded(
child: SingleChildScrollView(
child: Column(
children: List.generate(
newsForSelectedGame.length,
(index) {
return NewsCard(
newsForSelectedGame[index]
['title'],
newsForSelectedGame[index]
['message']);
}),
),
),
)
],
),
)),
),
SizedBox(
width: 50,
),
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(
0, 20, 0, 0),
child: Text(
"Leaderboard",
style: TextStyle(fontSize: 20),
),
),
DataTable(
dataTextStyle:
TextStyle(color: Colors.white),
headingTextStyle:
TextStyle(color: Colors.white),
dividerThickness: 0,
columns: [
DataColumn(
label:
Expanded(child: Text("Place"))),
DataColumn(
label: Expanded(
child: Text("Username"))),
DataColumn(
label:
Expanded(child: Text("Kills"))),
DataColumn(
label: Expanded(
child: Text("Deaths"))),
DataColumn(
label: Expanded(child: Text("XP"))),
],
rows: leaderboardList,
),
],
),
),
],
))
],
),
),
Container(
//Install path footer
padding: EdgeInsets.symmetric(horizontal: 10),
alignment: Alignment.bottomCenter,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(children: [Text("Install path "), Text(filePath)]),
GlassButton(
onTap: () {
DirectoryPicker file = DirectoryPicker();
final dir = file.getDirectory();
Backend.prefs!.setString(
'${selectedGameData.name}_path', dir!.path);
setState(() {});
},
child: Text("Change Install Location"),
width: 250)
],
),
SizedBox(
height: 10,
)
],
),
)
],
),
);
}
Widget NewsCard(String title, String message) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: GlassCard(
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(18.0),
child: Icon(
Icons.newspaper,
color: Colors.blueGrey,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(fontSize: 18),
textAlign: TextAlign.left,
),
Text(
message,
overflow: TextOverflow.clip,
)
],
)
],
)),
);
}
} }

View File

@ -1,12 +1,17 @@
import 'dart:math';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mhunt_launcher/Backend/Backend.dart'; import 'package:mhunt_launcher/Backend/Backend.dart';
import 'package:mhunt_launcher/Backend/DebugHelper.dart';
import 'package:mhunt_launcher/Widgets/CustomWidgets.dart'; import 'package:mhunt_launcher/Widgets/CustomWidgets.dart';
import 'package:mhunt_launcher/home.dart'; import 'package:mhunt_launcher/home.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'Shared/Dialogs.dart';
class LoginPage extends StatefulWidget { class LoginPage extends StatefulWidget {
const LoginPage({super.key}); const LoginPage({super.key});
@ -32,7 +37,6 @@ class _LoginPageState extends State<LoginPage> {
if (prefs.containsKey("username") && prefs.containsKey("password")) { if (prefs.containsKey("username") && prefs.containsKey("password")) {
usernameController.text = prefs.getString("username") ?? ''; usernameController.text = prefs.getString("username") ?? '';
passwordController.text = prefs.getString("password") ?? ''; passwordController.text = prefs.getString("password") ?? '';
LoginOrReg(); LoginOrReg();
} }
} }
@ -48,6 +52,7 @@ class _LoginPageState extends State<LoginPage> {
} }
TextEditingController usernameController = TextEditingController(); TextEditingController usernameController = TextEditingController();
TextEditingController gamertagController = TextEditingController();
TextEditingController passwordController = TextEditingController(); TextEditingController passwordController = TextEditingController();
@override @override
@ -64,7 +69,7 @@ class _LoginPageState extends State<LoginPage> {
setState(() {}); setState(() {});
}, },
child: Center( child: Center(
child: web3LoginCard() child: TraditionalLoginCard()
)) ))
); );
} }
@ -145,7 +150,7 @@ class _LoginPageState extends State<LoginPage> {
setState(() { setState(() {
web3loginState = 1; web3loginState = 1;
}); });
launchUrl(Uri.parse('https://auth.playpoolstudios.com/?request_id=${requestId}')); launchUrl(Uri.parse('https://auth.playpoolstudios.com/auth/?request_id=${requestId}'));
String requestResponse = "-1"; String requestResponse = "-1";
while(requestResponse == "-1"){ while(requestResponse == "-1"){
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
@ -190,72 +195,120 @@ class _LoginPageState extends State<LoginPage> {
} }
await Backend.Register(web3id,web3id,usernameEditingController.text); await Backend.Register(web3id,web3id,usernameEditingController.text);
await Backend.Login(usernameEditingController.text, web3id); await Backend.Login(web3id, web3id);
OnLoginSuccess(); OnLoginSuccess();
} }
bool isGuest = false;
Widget TraditionalLoginCard(){ Widget TraditionalLoginCard(){
return GlassCard( return GlassCard(
child: Container( child: Container(
padding: EdgeInsets.all(25), padding: EdgeInsets.all(25),
width: 600, width: 600,
height: 400, height: 400,
child: Column( child: isGuest? TraditionalLoginGuest() :TraditionalLoginMain()
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Welcome to W3B Launcher",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Text("Username "),
SizedBox(
width: 300,
child: TextField(
controller: usernameController,
))
],
mainAxisAlignment: MainAxisAlignment.center,
),
Row(children: [
Text("Password "),
SizedBox(
width: 300,
child: TextField(
controller: passwordController,
))
], mainAxisAlignment: MainAxisAlignment.center),
SizedBox(
height: 30,
),
GlassButton(onTap: LoginOrReg, child: Text(isReg ? "Register" : "Login"), width: 150, height: 40),
],
),
Row(children: [
Text(isReg ? "Already have an Account? " : "Don't have an Account? "),
InkWell(
child: Text(
isReg ? "Login Here" : "Register Here",
style: TextStyle(color: Colors.blue),
),
onTap: () {
setState(() {
isReg = !isReg;
});
},
)
], mainAxisAlignment: MainAxisAlignment.center)
],
),
)); ));
} }
Widget TraditionalLoginMain(){
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Welcome to W3B Launcher",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Text("Username "),
SizedBox(
width: 300,
child: TextField(
controller: usernameController,
))
],
mainAxisAlignment: MainAxisAlignment.center,
),
Row(children: [
Text("Password "),
SizedBox(
width: 300,
child: TextField(
controller: passwordController,
))
], mainAxisAlignment: MainAxisAlignment.center),
SizedBox(
height: 30,
),
GlassButton(onTap: LoginOrReg, child: Text(isReg ? "Register" : "Login"), width: 150, height: 40),
],
),
Row(children: [
Text(isReg ? "Already have an Account? " : "Don't have an Account? "),
InkWell(
child: Text(
isReg ? "Login Here" : "Register Here",
style: TextStyle(color: Colors.blue),
),
onTap: () {
setState(() {
isReg = !isReg;
});
},
)
], mainAxisAlignment: MainAxisAlignment.center),
GlassButton(onTap: (){setState(() {
isGuest=true;
});}, child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.person),
SizedBox(width: 10,),
Text("Guest Mode"),
],
), width: 130, height: 30)
],
);
}
Widget TraditionalLoginGuest(){
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Welcome to W3B Launcher - Guest Mode",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
Column(
children: [
Row(
children: [
Text("Gamer Tag "),
SizedBox(
width: 300,
child: TextField(
controller: gamertagController,
))
],
mainAxisAlignment: MainAxisAlignment.center,
),
SizedBox(height: 15,),
SizedBox(width: 250,child:usernameExists ? Text("Username is taken",style: TextStyle(color: Colors.red),) : Container()),
GlassButton(onTap:GuestModeComplete , child: Text("Complete Login"), width: 250,height: 40,color: Colors.green)
],
),
GlassButton(onTap: (){setState(() {
isGuest=false;
});}, child: Text("Back"), width: 200, color: Colors.blueGrey)
],
);
}
void LoginOrReg() async { void LoginOrReg() async {
// if(kDebugMode){ // if(kDebugMode){
// Navigator.of(context).push(MaterialPageRoute(builder: (context)=>HomePage())); // Navigator.of(context).push(MaterialPageRoute(builder: (context)=>HomePage()));
@ -268,8 +321,35 @@ class _LoginPageState extends State<LoginPage> {
success = await Backend.Login(usernameController.text, passwordController.text); success = await Backend.Login(usernameController.text, passwordController.text);
} }
Debug.Log('${isReg ? "Register": "Login"} was ${success ? "success" : "faild"}');
if (success) { if (success) {
OnLoginSuccess(); OnLoginSuccess();
}else{
if(isReg){
Dialogs.showAlertDialog(context, 'Failed Register', "Username already exists");
}else{
Dialogs.showAlertDialog(context, 'Failed Login', "Username or Password is incorrect");
}
}
}
void GuestModeComplete()async{
bool usernameValidated = await Backend.GetUsernameValidation(gamertagController.text);
if(!usernameValidated){
setState(() {
usernameExists=true;
});
}
String username = await Backend.GetNextGuestUsername();
bool success= await Backend.Register(username, username, gamertagController.text);
if(success){
usernameController.text = username;
passwordController.text = username;
OnLoginSuccess();
} }
} }
@ -277,7 +357,7 @@ class _LoginPageState extends State<LoginPage> {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('username', usernameController.text); prefs.setString('username', usernameController.text);
prefs.setString('password', passwordController.text); prefs.setString('password', passwordController.text);
prefs.setString('displayname', Backend.displayName);
Navigator.of(context).push(MaterialPageRoute(builder: (context) => HomePage())); Navigator.of(context).push(MaterialPageRoute(builder: (context) => HomePage()));
} }
} }

BIN
ota/Microsoft.CSharp.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/Newtonsoft.Json.dll Normal file

Binary file not shown.

BIN
ota/System.AppContext.dll Normal file

Binary file not shown.

BIN
ota/System.Buffers.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/System.Collections.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/System.Console.dll Normal file

Binary file not shown.

BIN
ota/System.Core.dll Normal file

Binary file not shown.

BIN
ota/System.Data.Common.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ota/System.Data.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/System.Drawing.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ota/System.Formats.Asn1.dll Normal file

Binary file not shown.

BIN
ota/System.Formats.Tar.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/System.IO.Pipes.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ota/System.IO.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/System.Linq.dll Normal file

Binary file not shown.

BIN
ota/System.Memory.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ota/System.Net.Http.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ota/System.Net.Mail.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/System.Net.Ping.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ota/System.Net.Quic.dll Normal file

Binary file not shown.

BIN
ota/System.Net.Requests.dll Normal file

Binary file not shown.

BIN
ota/System.Net.Security.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ota/System.Net.Sockets.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/System.Net.WebProxy.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ota/System.Net.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
ota/System.Numerics.dll Normal file

Binary file not shown.

BIN
ota/System.ObjectModel.dll Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More