861 lines
30 KiB
Dart
861 lines
30 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 'Backend/DebugHelper.dart';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import 'Backend/FileHashEntry.dart';
|
|
import 'Backend/Structures.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;
|
|
|
|
@override
|
|
void initState() {
|
|
// TODO: implement initState
|
|
super.initState();
|
|
kickstartAnimations();
|
|
|
|
SetSelectedDashboardGame(0);
|
|
}
|
|
|
|
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();
|
|
if (selectedSidebarIndex == 1) {
|
|
content = Dashboard();
|
|
} else if (selectedSidebarIndex == 2) {
|
|
content = Downloads();
|
|
}
|
|
|
|
return Scaffold(
|
|
backgroundColor: Colors.transparent,
|
|
body: CustomBody(
|
|
context: context,
|
|
onAnimEnd: () {
|
|
setState(() {});
|
|
},
|
|
child: Row(
|
|
children: [
|
|
SideBar(
|
|
width: screenWidth * 0.2,
|
|
height: screenHeight,
|
|
),
|
|
SizedBox(
|
|
width: screenWidth * 0.8,
|
|
height: screenHeight,
|
|
child: content,
|
|
)
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget Library() {
|
|
return Center(
|
|
child: Wrap(
|
|
spacing: 20,
|
|
children: List.generate(Backend.Games.length, (index) {
|
|
GameData gameData = Backend.Games[index];
|
|
return LibGameCard(gameData);
|
|
}),
|
|
),
|
|
);
|
|
}
|
|
|
|
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(
|
|
children: [
|
|
SizedBox(
|
|
height: 100,
|
|
),
|
|
SidebarTitle("Library", Icons.laptop_chromebook_outlined,
|
|
index: 0),
|
|
SidebarTitle("Dashboard", Icons.dashboard, index: 1),
|
|
SidebarTitle("Downloads", Icons.download, index: 2),
|
|
],
|
|
),
|
|
),
|
|
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 {
|
|
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.UserJson['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;}
|
|
// String exeFilePath = InstallHelper.GetExeFilePath(id);
|
|
// if(!File(exeFilePath).existsSync()){
|
|
// Debug.LogError("No game installed to uninstall");
|
|
// 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;
|
|
});
|
|
});
|
|
}
|
|
|
|
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,
|
|
)
|
|
],
|
|
)
|
|
],
|
|
)),
|
|
);
|
|
}
|
|
}
|