171 lines
5.4 KiB
Dart
171 lines
5.4 KiB
Dart
import 'dart:collection';
|
|
import 'dart:convert';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:toolheim/data/warband_roaster.dart';
|
|
import 'package:yaml/yaml.dart';
|
|
|
|
class GitHubAdapter extends ChangeNotifier {
|
|
String _repository = 'Labernator/Mordheim';
|
|
String _path = 'Mordheim-BorderTownBurning/Warband Rosters';
|
|
|
|
List<String> _syncErrors = new List<String>();
|
|
DateTime _lastSync;
|
|
|
|
List<WarbandRoaster> _roasters = [];
|
|
String _activePlayerName = 'Aaron';
|
|
|
|
String get repository => _repository;
|
|
String get path => _path;
|
|
|
|
DateTime get lastSync => _lastSync;
|
|
UnmodifiableListView<String> get syncErrors => _syncErrors;
|
|
|
|
UnmodifiableListView<WarbandRoaster> get roasters =>
|
|
UnmodifiableListView(_roasters);
|
|
WarbandRoaster get activeRoaster => _roasters.firstWhere((roaster) {
|
|
return roaster.playerName == _activePlayerName;
|
|
});
|
|
|
|
void changeActiveRoaster(String playerName) {
|
|
_activePlayerName = playerName;
|
|
notifyListeners();
|
|
}
|
|
|
|
// TODO: Add persistence layer here
|
|
|
|
/// Search for warband files in the GitHub repository
|
|
///
|
|
/// This method will search for matching files and check their content in a
|
|
/// subfolder (see fields [repository] and [path]). If the file
|
|
/// contain errors or can't read, a sync error message will be written into
|
|
/// the [syncErrors] list.
|
|
void search() async {
|
|
_syncErrors.clear();
|
|
|
|
Stream<Map<String, String>> roasterStream() async* {
|
|
// Get all files which could be potential warband files (end with
|
|
// mordheim.yml and contain the word "heros").
|
|
http.Response response = await http.get(
|
|
"https://api.github.com/search/code?q=heros+repo:" +
|
|
_repository +
|
|
"+filename:mordheim.yml+path:\"" +
|
|
_path +
|
|
"\"");
|
|
|
|
// GitHub is not reachable
|
|
if (response.statusCode != 200) {
|
|
_syncErrors.add('Could not find any warband roaster files');
|
|
yield {};
|
|
return;
|
|
}
|
|
|
|
// No valid response from GitHub
|
|
dynamic searchResults;
|
|
try {
|
|
searchResults = jsonDecode(response.body);
|
|
} on FormatException catch (e) {
|
|
_syncErrors.add('Could not parse GitHub response.' + e.toString());
|
|
yield {};
|
|
return;
|
|
}
|
|
|
|
// Find suitable files for examination
|
|
RegExp fileRegex = new RegExp(r"[a-zA-Z]+\.mordheim\.ya?ml");
|
|
for (dynamic searchResult in searchResults['items']) {
|
|
if (fileRegex.hasMatch(searchResult['name'])) {
|
|
// We try to get the name of the player from the name of the folder
|
|
// in which the file resists
|
|
String completePath = searchResult['path'];
|
|
List<String> pathParts =
|
|
completePath.substring(_path.length + 1).split('/');
|
|
|
|
String playerName;
|
|
if (pathParts.length >= 2) {
|
|
playerName = pathParts.first;
|
|
}
|
|
|
|
// Fetch last change and some metainformation of the file
|
|
http.Response response = await http.get(
|
|
"https://api.github.com/repos/" +
|
|
_repository +
|
|
"/commits?path=" +
|
|
completePath);
|
|
|
|
if (response.statusCode != 200) {
|
|
_syncErrors.add('Could not load the warband metadata from GitHub.');
|
|
continue;
|
|
}
|
|
|
|
// No valid response from GitHub
|
|
dynamic commits;
|
|
try {
|
|
commits = jsonDecode(response.body);
|
|
} on FormatException catch (e) {
|
|
_syncErrors.add('Could not parse GitHub response.' + e.toString());
|
|
continue;
|
|
}
|
|
|
|
// No commits available
|
|
if (commits.length == 0) {
|
|
continue;
|
|
}
|
|
|
|
dynamic latestCommit = commits.first;
|
|
yield {
|
|
'filePath': completePath.toString(),
|
|
'shaHash': latestCommit['sha'],
|
|
'player': playerName.toString(),
|
|
'author': latestCommit['commit']['author']['name'],
|
|
'date': latestCommit['commit']['committer']['date'],
|
|
'message': latestCommit['commit']['message']
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
_roasters.clear();
|
|
notifyListeners();
|
|
await for (Map<String, String> player in roasterStream()) {
|
|
http.Response response = await http.get(
|
|
"https://raw.githubusercontent.com/" +
|
|
_repository +
|
|
'/master/' +
|
|
player['filePath']);
|
|
|
|
try {
|
|
YamlMap yamlObject = loadYaml(response.body);
|
|
WarbandRoaster roaster = WarbandRoaster.fromJson(yamlObject);
|
|
if (player['player'] != '') {
|
|
roaster.playerName = player['player'];
|
|
}
|
|
|
|
roaster.currentVersion = new Version(player['shaHash'], player['date'],
|
|
player['author'], player['message']);
|
|
|
|
// On a search, we drop all previous information about the warbands,
|
|
// Sp, lastSyncVersion is equal to the currentVersion.
|
|
roaster.lastSyncVersion = roaster.currentVersion;
|
|
|
|
_roasters.add(roaster);
|
|
notifyListeners();
|
|
} catch (e) {
|
|
_syncErrors.add(e.toString());
|
|
}
|
|
}
|
|
|
|
_lastSync = DateTime.now();
|
|
notifyListeners();
|
|
}
|
|
|
|
void update() async {
|
|
// TODO: Search for warband yml files
|
|
// TODO: Check if it is in the right format
|
|
// TODO: Store it into the database if valid
|
|
|
|
_lastSync = DateTime.now();
|
|
notifyListeners();
|
|
}
|
|
}
|