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 createState() => _HomePageState(); } class _HomePageState extends State { Map> downloadQueue = {}; Map totalDownloadSize = {}; List missingFilesForSelectedGame = []; List leaderboardForSelectedGame = []; Map myStatsForSelectedGame = {}; List> newsForSelectedGame = []; bool calculatingFiles = false; Map> 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>> 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 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 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 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 _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; }); }); } }