372 lines
11 KiB
Dart
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;
|
|
});
|
|
});
|
|
}
|
|
}
|