mhunt_launcher/lib/home.dart
2024-10-29 00:12:00 +05:30

372 lines
11 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:background_downloader/background_downloader.dart';
import 'package:filepicker_windows/filepicker_windows.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:mhunt_launcher/Backend/Backend.dart';
import 'package:mhunt_launcher/Backend/InstallHelper.dart';
import 'package:mhunt_launcher/Backend/ProcessMan.dart';
import 'package:mhunt_launcher/Widgets/CustomWidgets.dart';
import 'package:mhunt_launcher/sidebar.dart';
import 'package:process_run/process_run.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:path/path.dart' as Path;
import 'package:url_launcher/url_launcher_string.dart';
import 'Backend/DebugHelper.dart';
import 'package:http/http.dart' as http;
import 'Backend/FileHashEntry.dart';
import 'Backend/Structures.dart';
import 'Widgets/Home/AccountsPage/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 {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Map<int, List<FileHashEntry>> downloadQueue = {};
Map<int, double> totalDownloadSize = {};
List<FileHashEntry> missingFilesForSelectedGame = [];
List<LeaderboardEntry> leaderboardForSelectedGame = [];
Map<String, dynamic> myStatsForSelectedGame = {};
List<Map<String, dynamic>> newsForSelectedGame = [];
bool calculatingFiles = false;
Map<int, Map<FileHashEntry, num>> downloadProgress = {};
int selectedSidebarIndex = 0;
bool downloadRunning = false;
int unwaitingFiles = 0;
int dashboardSelectedGameIndex = 0;
String userPubKey = "loading";
@override
void initState() {
// TODO: implement initState
super.initState();
kickstartAnimations();
initData();
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 {
await Future.delayed(const Duration(milliseconds: 500));
setState(() {
op1 = 1;
op2 = 1;
op3 = 1;
});
}
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
Widget content = Library(
selectedSidebarIndex: selectedSidebarIndex,
onGameChanged: SetSelectedDashboardGame,
onUpdate: (){
setState(() {
});
}
);
if (selectedSidebarIndex == 1) {
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) {
content = Downloads(
downloadQueue: downloadQueue,
downloadRunning: downloadRunning,
downloadProgress: downloadProgress,
totalDownloadSize: totalDownloadSize,
onChanged: (val){
setState(() {
SetSelectedDashboardGame(val);
});
}
);
}else if(selectedSidebarIndex == 3){
content = AccountPage(context, (){setState(() {
});});
}
return Scaffold(
backgroundColor: Colors.transparent,
body: CustomBody(
context: context,
onAnimEnd: () {
setState(() {});
},
child: Row(
children: [
SideBar(
width: screenWidth * 0.2,
height: screenHeight, onChanged: (val){
setState(() {
selectedSidebarIndex = val;
});
},
),
SizedBox(
width: screenWidth * 0.8,
height: screenHeight,
child: content,
)
],
),
),
);
}
void SetSelectedDashboardGame(int i) async {
calculatingFiles = true;
setState(() {});
dashboardSelectedGameIndex = i;
if (!Backend.Games[i].isAvailable) {
return;
}
leaderboardForSelectedGame =
await Backend.GetLeaderboard(Backend.Games[i].code);
myStatsForSelectedGame = await Backend.GetUserStatsForGame(i);
newsForSelectedGame = await Backend.GetNewsForGame(i);
setState(() {});
missingFilesForSelectedGame =
await InstallHelper.GetMissingFiles(i, force: true);
calculatingFiles = false;
setState(() {});
}
void OnGameActionButtonClicked() {
if (calculatingFiles) {
return;
}
if(isUninstalling){return;}
// if(downloadRunning){
// Debug.Log("Download running");
// setState(() {selectedSidebarIndex = (2);});
// return;}
if (missingFilesForSelectedGame.length <= 0) {
if(runningProcs.containsKey(dashboardSelectedGameIndex)){
// runningProcs[dashboardSelectedGameIndex][0].
}else{
StartGame(dashboardSelectedGameIndex);
}
// ProcessMan.RunGame(
// InstallHelper.GetExeFilePath(dashboardSelectedGameIndex));
} else {
setState(() {selectedSidebarIndex = (2);});
if (downloadQueue.containsKey(dashboardSelectedGameIndex)) {
Debug.Log("already downloading");
return;
//Already downloading
}
StartDownload(dashboardSelectedGameIndex, missingFilesForSelectedGame);
}
}
Map<int, Future<List<ProcessResult>>> runningProcs = {};
void StartGame(int id)async{
if(runningProcs.containsKey(id)){return;}
String exePath = InstallHelper.GetExeFilePath(dashboardSelectedGameIndex);
// Process proc = await run(exePath,);
runningProcs.putIfAbsent(id, ()=> run(exePath + " username ${Backend.Username} password ${Backend.UserJson['passwd']}"));
setState(() {
});
await runningProcs[id];
runningProcs.remove(id);
setState(() {
});
}
void StartDownload(int gameId, List<FileHashEntry> missingList) {
if(downloadQueue.containsKey(dashboardSelectedGameIndex)){return;}
downloadQueue.putIfAbsent(dashboardSelectedGameIndex, () => []);//missingList
totalDownloadSize.putIfAbsent(dashboardSelectedGameIndex,
() => 0);//FileHashEntry.getTotalSizeInBytes(missingList).toDouble()
downloadQueue[dashboardSelectedGameIndex]=missingList;
totalDownloadSize[dashboardSelectedGameIndex] = FileHashEntry.getTotalSizeInBytes(missingList).toDouble();
CheckDownloads();
}
bool isUninstalling = false;
void UninstallGame(int id) async {
if(runningProcs.containsKey(id)){return;}
isUninstalling = true;
setState(() {});
String path = InstallHelper.GetFilePath(id);
Directory parent = Directory(path);
if (parent.existsSync()) {
await parent.delete(recursive: true);
}
parent.create(recursive: true);
setState(() {
isUninstalling = false;
});
SetSelectedDashboardGame(id);
}
//DOWNLOAD//
void CheckDownloads() async {
if (downloadRunning) {
return;
}
downloadRunning = true;
while (downloadQueue.length > 0) {
int gameId = downloadQueue.keys.toList()[0];
if (downloadQueue[gameId]!.length <= 0) {
if (unwaitingFiles <= 0) {
downloadQueue.remove(gameId);
downloadProgress.remove(gameId);
}
await Future.delayed(const Duration(milliseconds: 500));
continue;
}
FileHashEntry entry = downloadQueue[gameId]![0];
double fileSizeMb = entry.bytes / 1024 / 1024;
if (fileSizeMb < 20) {
Debug.Log("Downloading ${entry.file} smaller file : " +
fileSizeMb.toString());
if (fileSizeMb < 1 && unwaitingFiles < 10) {
unwaitingFiles++;
DownloadFile(entry, gameId).then((value) => unwaitingFiles--);
} else {
await DownloadFile(entry, gameId);
}
} else {
Debug.Log(
"Downloading ${entry.file} larger file : " + fileSizeMb.toString());
await DownloadLargeFile(entry, gameId);
}
// Debug.Log("${allAddedDownloads[gameId]!.length} : ${downloadQueue[gameId]!.length}" );
downloadQueue[gameId]!.removeAt(0);
setState(() {});
}
downloadRunning = false;
}
Future<void> DownloadLargeFile(FileHashEntry entry, int gameId) async {
String url = InstallHelper.GetFileUrl(entry.file, gameId);
String savepath = "${InstallHelper.GetFilePath(gameId)}${entry.file}";
String filename = savepath.contains('\\')
? savepath.substring(savepath.lastIndexOf('\\') + 1)
: savepath.substring(savepath.lastIndexOf('/') + 1);
if (!File(savepath).parent.existsSync()) {
File(savepath).parent.create(recursive: true);
}
// await DownloadFile(downloadQueue[gameId]![0], gameId);
if (!downloadProgress.containsKey(gameId)) {
downloadProgress.putIfAbsent(gameId, () => {entry: 0});
}
final task = DownloadTask(
url: url, filename: filename, directory: File(savepath).parent.path);
await FileDownloader().download(task, onProgress: (progress) {
downloadProgress[gameId]![entry] = entry.bytes * progress;
setState(() {});
});
downloadProgress[gameId]![entry] = entry.bytes;
}
Future<void> DownloadFile(FileHashEntry fileEntry, int gameId) async {
if (!downloadProgress.containsKey(gameId)) {
downloadProgress.putIfAbsent(gameId, () => {fileEntry: 0});
}
String url = InstallHelper.GetFileUrl(fileEntry.file, gameId);
var _response =
await http.Client().send(http.Request('GET', Uri.parse(url)));
// _total = _response.contentLength ?? 0;
List<int> _bytes = [];
int prog = 0;
_response.stream.listen((value) {
setState(() {
_bytes.addAll(value);
prog += value.length;
downloadProgress[gameId]![fileEntry] = prog;
});
}).onDone(() async {
File file =
new File("${InstallHelper.GetFilePath(gameId)}${fileEntry.file}");
if (!file.parent.existsSync()) {
await file.parent.create(recursive: true);
}
await file.writeAsBytes(_bytes);
setState(() {
// _image = file;
});
});
}
}