Commit 7b5fe38f authored by Leon Tappe's avatar Leon Tappe 🔥
Browse files

implement new settings for user view

parent be01710d
...@@ -359,7 +359,7 @@ ...@@ -359,7 +359,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 16; CURRENT_PROJECT_VERSION = 18;
DEVELOPMENT_TEAM = VK3N2H79U2; DEVELOPMENT_TEAM = VK3N2H79U2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
...@@ -367,7 +367,7 @@ ...@@ -367,7 +367,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 0.6.2; MARKETING_VERSION = 0.7.0;
PRODUCT_BUNDLE_IDENTIFIER = de.upb.asta.digital3gManagement; PRODUCT_BUNDLE_IDENTIFIER = de.upb.asta.digital3gManagement;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
...@@ -493,7 +493,7 @@ ...@@ -493,7 +493,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 16; CURRENT_PROJECT_VERSION = 18;
DEVELOPMENT_TEAM = VK3N2H79U2; DEVELOPMENT_TEAM = VK3N2H79U2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
...@@ -501,7 +501,7 @@ ...@@ -501,7 +501,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 0.6.2; MARKETING_VERSION = 0.7.0;
PRODUCT_BUNDLE_IDENTIFIER = de.upb.asta.digital3gManagement; PRODUCT_BUNDLE_IDENTIFIER = de.upb.asta.digital3gManagement;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
...@@ -521,7 +521,7 @@ ...@@ -521,7 +521,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 16; CURRENT_PROJECT_VERSION = 18;
DEVELOPMENT_TEAM = VK3N2H79U2; DEVELOPMENT_TEAM = VK3N2H79U2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
...@@ -529,7 +529,7 @@ ...@@ -529,7 +529,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 0.6.2; MARKETING_VERSION = 0.7.0;
PRODUCT_BUNDLE_IDENTIFIER = de.upb.asta.digital3gManagement; PRODUCT_BUNDLE_IDENTIFIER = de.upb.asta.digital3gManagement;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
......
...@@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; ...@@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import '../models/runtime_setting.dart';
import '../models/seed.dart'; import '../models/seed.dart';
class SeedResponse { class SeedResponse {
...@@ -33,6 +34,22 @@ class UserApi { ...@@ -33,6 +34,22 @@ class UserApi {
} }
} }
Future<Map<String, dynamic>> getSettings() async {
final response = await _client.get(Uri.parse('$_baseUrl/settings'));
if (response.statusCode == 200 && response.body.isNotEmpty) {
final Map<String, dynamic> settings = json.decode(response.body);
for (var setting in settings.keys) {
if (setting.contains('runtime')) {
settings[setting] = RuntimeSetting.fromMap(json.decode(settings[setting]));
}
}
return settings;
} else {
return {};
}
}
Future<SeedResponse> makeSeed(String ticket) async { Future<SeedResponse> makeSeed(String ticket) async {
_log.fine('makeSeed for ticket "$ticket"'); _log.fine('makeSeed for ticket "$ticket"');
final response = await _client.post( final response = await _client.post(
......
import 'dart:convert';
class RuntimeSetting {
RuntimeType type;
Duration? duration;
int? months;
RuntimeSetting(this.type, {this.duration, this.months});
factory RuntimeSetting.fromMap(Map map) => RuntimeSetting(
runtimeTypeNames[map['type']],
duration: map['duration'] != null ? Duration(hours: map['duration']) : null,
months: map['months'],
);
Map get toMap => {
'type': type.name.split('.').last,
'duration': duration?.inHours,
'months': months,
};
@override
String toString() => json.encode(toMap);
}
enum RuntimeType {
duration,
nextSemester,
months,
}
const Map runtimeTypeNames = {
'duration': RuntimeType.duration,
'months': RuntimeType.months,
'nextSemester': RuntimeType.nextSemester,
};
\ No newline at end of file
...@@ -8,14 +8,9 @@ import 'package:provider/provider.dart'; ...@@ -8,14 +8,9 @@ import 'package:provider/provider.dart';
import '../api/admin_api.dart'; import '../api/admin_api.dart';
import '../api/auth_api.dart'; import '../api/auth_api.dart';
import '../models/runtime_setting.dart';
import '../widgets/card_list_tile.dart'; import '../widgets/card_list_tile.dart';
const Map runtimeTypeNames = {
'duration': RuntimeType.duration,
'months': RuntimeType.months,
'nextSemester': RuntimeType.nextSemester,
};
const List<String> settingNames = [ const List<String> settingNames = [
'runtime_recovered', 'runtime_recovered',
'runtime_tested', 'runtime_tested',
...@@ -40,35 +35,6 @@ final Map<String, dynamic> settingDefaults = { ...@@ -40,35 +35,6 @@ final Map<String, dynamic> settingDefaults = {
'motd_internal': '', 'motd_internal': '',
}; };
class RuntimeSetting {
RuntimeType type;
Duration? duration;
int? months;
RuntimeSetting(this.type, {this.duration, this.months});
factory RuntimeSetting.fromMap(Map map) => RuntimeSetting(
runtimeTypeNames[map['type']],
duration: map['duration'] != null ? Duration(hours: map['duration']) : null,
months: map['months'],
);
Map get toMap => {
'type': type.name.split('.').last,
'duration': duration?.inHours,
'months': months,
};
@override
String toString() => json.encode(toMap);
}
enum RuntimeType {
duration,
nextSemester,
months,
}
class ServerSettingsPage extends StatefulWidget { class ServerSettingsPage extends StatefulWidget {
const ServerSettingsPage({Key? key}) : super(key: key); const ServerSettingsPage({Key? key}) : super(key: key);
......
...@@ -19,6 +19,7 @@ import 'package:qr_flutter/qr_flutter.dart'; ...@@ -19,6 +19,7 @@ import 'package:qr_flutter/qr_flutter.dart';
import '../api/auth_api.dart'; import '../api/auth_api.dart';
import '../api/user_api.dart'; import '../api/user_api.dart';
import '../models/runtime_setting.dart';
class FormData { class FormData {
DateTime? certificationDate; DateTime? certificationDate;
...@@ -64,6 +65,13 @@ class _UserViewState extends State<UserView> { ...@@ -64,6 +65,13 @@ class _UserViewState extends State<UserView> {
UserApi? _userApi; UserApi? _userApi;
String _motd = '';
// ticket runtime defaults showcasing all different modes
RuntimeSetting _testedRuntime =
RuntimeSetting(RuntimeType.duration, duration: const Duration(hours: 24));
RuntimeSetting _recoveredRuntime = RuntimeSetting(RuntimeType.months, months: 3);
RuntimeSetting _vaccinatedRuntime = RuntimeSetting(RuntimeType.nextSemester);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Center( return Center(
...@@ -71,6 +79,15 @@ class _UserViewState extends State<UserView> { ...@@ -71,6 +79,15 @@ class _UserViewState extends State<UserView> {
constraints: const BoxConstraints(maxWidth: 512.0), constraints: const BoxConstraints(maxWidth: 512.0),
child: ListView( child: ListView(
children: [ children: [
if (_motd.isNotEmpty)
PaddedCard(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
'Systemnachricht',
style: Theme.of(context).textTheme.headline6,
),
Text(_motd),
])),
PaddedCard( PaddedCard(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
...@@ -195,47 +212,55 @@ class _UserViewState extends State<UserView> { ...@@ -195,47 +212,55 @@ class _UserViewState extends State<UserView> {
); );
} }
@override
void didChangeDependencies() async {
await initializeDateFormatting('de', null);
_client = Provider.of<AuthApi>(context, listen: false).client;
_userApi = UserApi(_client!, BlocProvider.of<BackendSwitcher>(context).state);
super.didChangeDependencies();
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
initializeDateFormatting('de', null);
_client = Provider.of<AuthApi>(context, listen: false).client;
_userApi = UserApi(_client!, BlocProvider.of<BackendSwitcher>(context).state);
_initKey(); _initKey();
_expiryText = _makeExpiryString(); _initSettings().then((_) => _expiryText = _makeExpiryString());
} }
DateTime? _calculateExpiryDate(FormData form) { DateTime? _calculateExpiryDate(FormData form) {
var date = form.certificationDate;
var time = form.certificationTime;
if (form.isTested) { if (form.isTested) {
date = DateTime(date!.year, date.month, date.day).add(const Duration(hours: 24)); return _calculateForType(form, _testedRuntime);
date = date.add(Duration(hours: time!.hour, minutes: time.minute));
} else if (form.isRecovered) { } else if (form.isRecovered) {
if (DateTime.now().difference(date!) < const Duration(days: 29)) { if (DateTime.now().difference(form.certificationDate!) < const Duration(days: 29)) {
throw Exception('test'); throw Exception('test');
} }
date = DateTime(date.year, date.month + 3, date.day - 1, 23, 59); return _calculateForType(form, _recoveredRuntime);
} else if (form.isVaccinated) { } else if (form.isVaccinated) {
final now = DateTime.now(); return _calculateForType(form, _vaccinatedRuntime);
final thisSs = DateTime(now.year, 4); }
final thisWs = DateTime(now.year, 10); }
if (now.isAfter(thisSs) && now.isBefore(thisWs)) {
date = thisWs; DateTime? _calculateForType(FormData form, RuntimeSetting runtime) {
} else if (now.isAfter(thisWs) && now.isAfter(thisSs)) { var date = form.certificationDate;
date = DateTime(now.year + 1, 4); var time = form.certificationTime;
} else if (now.isBefore(thisWs) && now.isBefore(thisSs)) { switch (runtime.type) {
date = thisSs; case RuntimeType.duration:
} date = DateTime(date!.year, date.month, date.day).add(runtime.duration!);
} else { date = date.add(Duration(hours: time!.hour, minutes: time.minute));
return null; return date;
case RuntimeType.months:
date = DateTime(date!.year, date.month + runtime.months!, date.day - 1, 23, 59);
return date;
case RuntimeType.nextSemester:
final now = DateTime.now();
final thisSs = DateTime(now.year, 4);
final thisWs = DateTime(now.year, 10);
if (now.isAfter(thisSs) && now.isBefore(thisWs)) {
date = thisWs;
} else if (now.isAfter(thisWs) && now.isAfter(thisSs)) {
date = DateTime(now.year + 1, 4);
} else if (now.isBefore(thisWs) && now.isBefore(thisSs)) {
date = thisSs;
}
return date;
default:
return null;
} }
return date;
} }
Future<Uint8List?> _getPublicKey() async { Future<Uint8List?> _getPublicKey() async {
...@@ -271,13 +296,25 @@ class _UserViewState extends State<UserView> { ...@@ -271,13 +296,25 @@ class _UserViewState extends State<UserView> {
} }
} }
Future<void> _initSettings() async {
final settings = await _userApi!.getSettings();
_testedRuntime = settings['runtime_tested'] as RuntimeSetting;
_recoveredRuntime = settings['runtime_recovered'] as RuntimeSetting;
_vaccinatedRuntime = settings['runtime_vaccinated'] as RuntimeSetting;
_motd = settings['motd_internal'] ?? '';
if (mounted) setState(() => true);
}
String _makeExpiryString() { String _makeExpiryString() {
DateTime? expiry; DateTime? expiry;
try { try {
expiry = _calculateExpiryDate(_formData); expiry = _calculateExpiryDate(_formData);
} catch (e) { } catch (e) {
if (e.toString().contains('test')) { if (e.toString().contains('test')) {
return 'Bitte ein gültiges Datum wählen'; return 'Das angegebene Datum erfüllt nicht die Anforderungen für einen Nachweis';
} }
} }
......
...@@ -14,7 +14,7 @@ packages: ...@@ -14,7 +14,7 @@ packages:
name: asn1lib name: asn1lib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "1.1.0"
async: async:
dependency: transitive dependency: transitive
description: description:
...@@ -461,7 +461,7 @@ packages: ...@@ -461,7 +461,7 @@ packages:
name: url_launcher_linux name: url_launcher_linux
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.2" version: "2.0.3"
url_launcher_macos: url_launcher_macos:
dependency: transitive dependency: transitive
description: description:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment