igen
This commit is contained in:
@@ -1,30 +1,30 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/database/query.dart';
|
||||
import 'package:filcnaplo/database/store.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
|
||||
class DatabaseProvider {
|
||||
// late Database _database;
|
||||
late DatabaseQuery query;
|
||||
late UserDatabaseQuery userQuery;
|
||||
late DatabaseStore store;
|
||||
late UserDatabaseStore userStore;
|
||||
|
||||
Future<void> init() async {
|
||||
Database db;
|
||||
|
||||
if (Platform.isLinux || Platform.isWindows) {
|
||||
db = await databaseFactoryFfi.openDatabase("app.db");
|
||||
} else {
|
||||
db = await openDatabase("app.db");
|
||||
}
|
||||
|
||||
query = DatabaseQuery(db: db);
|
||||
store = DatabaseStore(db: db);
|
||||
userQuery = UserDatabaseQuery(db: db);
|
||||
userStore = UserDatabaseStore(db: db);
|
||||
}
|
||||
}
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/database/query.dart';
|
||||
import 'package:filcnaplo/database/store.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
|
||||
class DatabaseProvider {
|
||||
// late Database _database;
|
||||
late DatabaseQuery query;
|
||||
late UserDatabaseQuery userQuery;
|
||||
late DatabaseStore store;
|
||||
late UserDatabaseStore userStore;
|
||||
|
||||
Future<void> init() async {
|
||||
Database db;
|
||||
|
||||
if (Platform.isLinux || Platform.isWindows) {
|
||||
db = await databaseFactoryFfi.openDatabase("app.db");
|
||||
} else {
|
||||
db = await openDatabase("app.db");
|
||||
}
|
||||
|
||||
query = DatabaseQuery(db: db);
|
||||
store = DatabaseStore(db: db);
|
||||
userQuery = UserDatabaseQuery(db: db);
|
||||
userStore = UserDatabaseStore(db: db);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,204 +1,204 @@
|
||||
// ignore_for_file: no_leading_underscores_for_local_identifiers
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/helpers/subject.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/lesson.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/week.dart';
|
||||
import 'package:filcnaplo/utils/format.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:live_activities/live_activities.dart';
|
||||
import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.i18n.dart';
|
||||
|
||||
enum LiveCardState { empty, duringLesson, duringBreak, morning, afternoon, night }
|
||||
|
||||
class LiveCardProvider extends ChangeNotifier {
|
||||
Lesson? currentLesson;
|
||||
Lesson? nextLesson;
|
||||
Lesson? prevLesson;
|
||||
List<Lesson>? nextLessons;
|
||||
|
||||
LiveCardState currentState = LiveCardState.empty;
|
||||
late Timer _timer;
|
||||
late final TimetableProvider _timetable;
|
||||
late final SettingsProvider _settings;
|
||||
|
||||
late Duration _delay;
|
||||
|
||||
final _liveActivitiesPlugin = LiveActivities();
|
||||
String? _latestActivityId;
|
||||
Map<String, String> _lastActivity = {};
|
||||
|
||||
LiveCardProvider({
|
||||
required TimetableProvider timetable,
|
||||
required SettingsProvider settings,
|
||||
}) : _timetable = timetable,
|
||||
_settings = settings {
|
||||
_liveActivitiesPlugin.init(appGroupId: "group.filcnaplo.livecard");
|
||||
_liveActivitiesPlugin.getAllActivitiesIds().then((value) {
|
||||
_latestActivityId = value.isNotEmpty ? value.first : null;
|
||||
});
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
|
||||
_delay = settings.bellDelayEnabled ? Duration(seconds: settings.bellDelay) : Duration.zero;
|
||||
update();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer.cancel();
|
||||
if (_latestActivityId != null && Platform.isIOS) _liveActivitiesPlugin.endActivity(_latestActivityId!);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// Debugging
|
||||
static DateTime _now() {
|
||||
return DateTime.now();
|
||||
}
|
||||
|
||||
String getFloorDifference() {
|
||||
final prevFloor = prevLesson!.getFloor();
|
||||
final nextFloor = nextLesson!.getFloor();
|
||||
if (prevFloor == null || nextFloor == null || prevFloor == nextFloor) {
|
||||
return "to room";
|
||||
}
|
||||
if (nextFloor == 0) {
|
||||
return "ground floor";
|
||||
}
|
||||
if (nextFloor > prevFloor) {
|
||||
return "up floor";
|
||||
} else {
|
||||
return "down floor";
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> toMap() {
|
||||
switch (currentState) {
|
||||
case LiveCardState.duringLesson:
|
||||
return {
|
||||
"icon": currentLesson != null ? SubjectIcon.resolveName(subject: currentLesson?.subject) : "book",
|
||||
"index": currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
|
||||
"title": currentLesson != null ? ShortSubject.resolve(subject: currentLesson?.subject).capital() : "",
|
||||
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "",
|
||||
"description": currentLesson?.description ?? "",
|
||||
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
|
||||
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
|
||||
"nextSubject": nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject).capital() : "",
|
||||
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
|
||||
};
|
||||
case LiveCardState.duringBreak:
|
||||
final iconFloorMap = {
|
||||
"to room": "chevron.right.2",
|
||||
"up floor": "arrow.up.right",
|
||||
"down floor": "arrow.down.left",
|
||||
"ground floor": "arrow.down.left",
|
||||
};
|
||||
|
||||
final diff = getFloorDifference();
|
||||
|
||||
return {
|
||||
"icon": iconFloorMap[diff] ?? "cup.and.saucer",
|
||||
"title": "Szünet",
|
||||
"description": "go $diff".i18n.fill([diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room]),
|
||||
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
|
||||
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
|
||||
"nextSubject": (nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject) : "").capital(),
|
||||
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
|
||||
"index": "",
|
||||
"subtitle": "",
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void update() async {
|
||||
if (Platform.isIOS) {
|
||||
final cmap = toMap();
|
||||
if (!mapEquals(cmap, _lastActivity)) {
|
||||
_lastActivity = cmap;
|
||||
|
||||
if (_lastActivity.isNotEmpty) {
|
||||
if (_latestActivityId == null) {
|
||||
_liveActivitiesPlugin.createActivity(_lastActivity).then((value) => _latestActivityId = value);
|
||||
} else {
|
||||
_liveActivitiesPlugin.updateActivity(_latestActivityId!, _lastActivity);
|
||||
}
|
||||
} else {
|
||||
if (_latestActivityId != null) _liveActivitiesPlugin.endActivity(_latestActivityId!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Lesson> today = _today(_timetable);
|
||||
|
||||
if (today.isEmpty) {
|
||||
await _timetable.fetch(week: Week.current());
|
||||
today = _today(_timetable);
|
||||
}
|
||||
|
||||
_delay = _settings.bellDelayEnabled ? Duration(seconds: _settings.bellDelay) : Duration.zero;
|
||||
|
||||
final now = _now().add(_delay);
|
||||
|
||||
// Filter cancelled lessons #20
|
||||
// Filter label lessons #128
|
||||
today = today.where((lesson) => lesson.status?.name != "Elmaradt" && lesson.subject.id != '' && !lesson.isEmpty).toList();
|
||||
|
||||
if (today.isNotEmpty) {
|
||||
// sort
|
||||
today.sort((a, b) => a.start.compareTo(b.start));
|
||||
|
||||
final _lesson = today.firstWhere((l) => l.start.isBefore(now) && l.end.isAfter(now), orElse: () => Lesson.fromJson({}));
|
||||
|
||||
if (_lesson.start.year != 0) {
|
||||
currentLesson = _lesson;
|
||||
} else {
|
||||
currentLesson = null;
|
||||
}
|
||||
|
||||
final _next = today.firstWhere((l) => l.start.isAfter(now), orElse: () => Lesson.fromJson({}));
|
||||
nextLessons = today.where((l) => l.start.isAfter(now)).toList();
|
||||
|
||||
if (_next.start.year != 0) {
|
||||
nextLesson = _next;
|
||||
} else {
|
||||
nextLesson = null;
|
||||
}
|
||||
|
||||
final _prev = today.lastWhere((l) => l.end.isBefore(now), orElse: () => Lesson.fromJson({}));
|
||||
|
||||
if (_prev.start.year != 0) {
|
||||
prevLesson = _prev;
|
||||
} else {
|
||||
prevLesson = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLesson != null) {
|
||||
currentState = LiveCardState.duringLesson;
|
||||
} else if (nextLesson != null && prevLesson != null) {
|
||||
currentState = LiveCardState.duringBreak;
|
||||
} else if (now.hour >= 12 && now.hour < 20) {
|
||||
currentState = LiveCardState.afternoon;
|
||||
} else if (now.hour >= 20) {
|
||||
currentState = LiveCardState.night;
|
||||
} else if (now.hour >= 5 && now.hour <= 10) {
|
||||
currentState = LiveCardState.morning;
|
||||
} else {
|
||||
currentState = LiveCardState.empty;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
bool get show => currentState != LiveCardState.empty;
|
||||
|
||||
Duration get delay => _delay;
|
||||
|
||||
bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day);
|
||||
|
||||
List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []).where((l) => _sameDate(l.date, _now())).toList();
|
||||
}
|
||||
// ignore_for_file: no_leading_underscores_for_local_identifiers
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/helpers/subject.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/lesson.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/week.dart';
|
||||
import 'package:filcnaplo/utils/format.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:live_activities/live_activities.dart';
|
||||
import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.i18n.dart';
|
||||
|
||||
enum LiveCardState { empty, duringLesson, duringBreak, morning, afternoon, night }
|
||||
|
||||
class LiveCardProvider extends ChangeNotifier {
|
||||
Lesson? currentLesson;
|
||||
Lesson? nextLesson;
|
||||
Lesson? prevLesson;
|
||||
List<Lesson>? nextLessons;
|
||||
|
||||
LiveCardState currentState = LiveCardState.empty;
|
||||
late Timer _timer;
|
||||
late final TimetableProvider _timetable;
|
||||
late final SettingsProvider _settings;
|
||||
|
||||
late Duration _delay;
|
||||
|
||||
final _liveActivitiesPlugin = LiveActivities();
|
||||
String? _latestActivityId;
|
||||
Map<String, String> _lastActivity = {};
|
||||
|
||||
LiveCardProvider({
|
||||
required TimetableProvider timetable,
|
||||
required SettingsProvider settings,
|
||||
}) : _timetable = timetable,
|
||||
_settings = settings {
|
||||
_liveActivitiesPlugin.init(appGroupId: "group.filcnaplo.livecard");
|
||||
_liveActivitiesPlugin.getAllActivitiesIds().then((value) {
|
||||
_latestActivityId = value.isNotEmpty ? value.first : null;
|
||||
});
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
|
||||
_delay = settings.bellDelayEnabled ? Duration(seconds: settings.bellDelay) : Duration.zero;
|
||||
update();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer.cancel();
|
||||
if (_latestActivityId != null && Platform.isIOS) _liveActivitiesPlugin.endActivity(_latestActivityId!);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// Debugging
|
||||
static DateTime _now() {
|
||||
return DateTime.now();
|
||||
}
|
||||
|
||||
String getFloorDifference() {
|
||||
final prevFloor = prevLesson!.getFloor();
|
||||
final nextFloor = nextLesson!.getFloor();
|
||||
if (prevFloor == null || nextFloor == null || prevFloor == nextFloor) {
|
||||
return "to room";
|
||||
}
|
||||
if (nextFloor == 0) {
|
||||
return "ground floor";
|
||||
}
|
||||
if (nextFloor > prevFloor) {
|
||||
return "up floor";
|
||||
} else {
|
||||
return "down floor";
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> toMap() {
|
||||
switch (currentState) {
|
||||
case LiveCardState.duringLesson:
|
||||
return {
|
||||
"icon": currentLesson != null ? SubjectIcon.resolveName(subject: currentLesson?.subject) : "book",
|
||||
"index": currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
|
||||
"title": currentLesson != null ? ShortSubject.resolve(subject: currentLesson?.subject).capital() : "",
|
||||
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "",
|
||||
"description": currentLesson?.description ?? "",
|
||||
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
|
||||
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
|
||||
"nextSubject": nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject).capital() : "",
|
||||
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
|
||||
};
|
||||
case LiveCardState.duringBreak:
|
||||
final iconFloorMap = {
|
||||
"to room": "chevron.right.2",
|
||||
"up floor": "arrow.up.right",
|
||||
"down floor": "arrow.down.left",
|
||||
"ground floor": "arrow.down.left",
|
||||
};
|
||||
|
||||
final diff = getFloorDifference();
|
||||
|
||||
return {
|
||||
"icon": iconFloorMap[diff] ?? "cup.and.saucer",
|
||||
"title": "Szünet",
|
||||
"description": "go $diff".i18n.fill([diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room]),
|
||||
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
|
||||
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(),
|
||||
"nextSubject": (nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject) : "").capital(),
|
||||
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
|
||||
"index": "",
|
||||
"subtitle": "",
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void update() async {
|
||||
if (Platform.isIOS) {
|
||||
final cmap = toMap();
|
||||
if (!mapEquals(cmap, _lastActivity)) {
|
||||
_lastActivity = cmap;
|
||||
|
||||
if (_lastActivity.isNotEmpty) {
|
||||
if (_latestActivityId == null) {
|
||||
_liveActivitiesPlugin.createActivity(_lastActivity).then((value) => _latestActivityId = value);
|
||||
} else {
|
||||
_liveActivitiesPlugin.updateActivity(_latestActivityId!, _lastActivity);
|
||||
}
|
||||
} else {
|
||||
if (_latestActivityId != null) _liveActivitiesPlugin.endActivity(_latestActivityId!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Lesson> today = _today(_timetable);
|
||||
|
||||
if (today.isEmpty) {
|
||||
await _timetable.fetch(week: Week.current());
|
||||
today = _today(_timetable);
|
||||
}
|
||||
|
||||
_delay = _settings.bellDelayEnabled ? Duration(seconds: _settings.bellDelay) : Duration.zero;
|
||||
|
||||
final now = _now().add(_delay);
|
||||
|
||||
// Filter cancelled lessons #20
|
||||
// Filter label lessons #128
|
||||
today = today.where((lesson) => lesson.status?.name != "Elmaradt" && lesson.subject.id != '' && !lesson.isEmpty).toList();
|
||||
|
||||
if (today.isNotEmpty) {
|
||||
// sort
|
||||
today.sort((a, b) => a.start.compareTo(b.start));
|
||||
|
||||
final _lesson = today.firstWhere((l) => l.start.isBefore(now) && l.end.isAfter(now), orElse: () => Lesson.fromJson({}));
|
||||
|
||||
if (_lesson.start.year != 0) {
|
||||
currentLesson = _lesson;
|
||||
} else {
|
||||
currentLesson = null;
|
||||
}
|
||||
|
||||
final _next = today.firstWhere((l) => l.start.isAfter(now), orElse: () => Lesson.fromJson({}));
|
||||
nextLessons = today.where((l) => l.start.isAfter(now)).toList();
|
||||
|
||||
if (_next.start.year != 0) {
|
||||
nextLesson = _next;
|
||||
} else {
|
||||
nextLesson = null;
|
||||
}
|
||||
|
||||
final _prev = today.lastWhere((l) => l.end.isBefore(now), orElse: () => Lesson.fromJson({}));
|
||||
|
||||
if (_prev.start.year != 0) {
|
||||
prevLesson = _prev;
|
||||
} else {
|
||||
prevLesson = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLesson != null) {
|
||||
currentState = LiveCardState.duringLesson;
|
||||
} else if (nextLesson != null && prevLesson != null) {
|
||||
currentState = LiveCardState.duringBreak;
|
||||
} else if (now.hour >= 12 && now.hour < 20) {
|
||||
currentState = LiveCardState.afternoon;
|
||||
} else if (now.hour >= 20) {
|
||||
currentState = LiveCardState.night;
|
||||
} else if (now.hour >= 5 && now.hour <= 10) {
|
||||
currentState = LiveCardState.morning;
|
||||
} else {
|
||||
currentState = LiveCardState.empty;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
bool get show => currentState != LiveCardState.empty;
|
||||
|
||||
Duration get delay => _delay;
|
||||
|
||||
bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day);
|
||||
|
||||
List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []).where((l) => _sameDate(l.date, _now())).toList();
|
||||
}
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:filcnaplo/api/client.dart';
|
||||
import 'package:filcnaplo/models/news.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class NewsProvider extends ChangeNotifier {
|
||||
// Private
|
||||
late List<News> _news;
|
||||
late int _state;
|
||||
late int _fresh;
|
||||
bool show = false;
|
||||
late BuildContext _context;
|
||||
|
||||
// Public
|
||||
List<News> get news => _news;
|
||||
int get state => _fresh - 1;
|
||||
|
||||
NewsProvider({
|
||||
List<News> initialNews = const [],
|
||||
required BuildContext context,
|
||||
}) {
|
||||
_news = List.castFrom(initialNews);
|
||||
_context = context;
|
||||
}
|
||||
|
||||
Future<void> restore() async {
|
||||
// Load news state from the database
|
||||
var state_ = Provider.of<SettingsProvider>(_context, listen: false).newsState;
|
||||
|
||||
if (state_ == -1) {
|
||||
var news_ = await FilcAPI.getNews();
|
||||
if (news_ != null) {
|
||||
state_ = news_.length;
|
||||
_news = news_;
|
||||
}
|
||||
}
|
||||
|
||||
_state = state_;
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
}
|
||||
|
||||
Future<void> fetch() async {
|
||||
var news_ = await FilcAPI.getNews();
|
||||
if (news_ == null) return;
|
||||
|
||||
_news = news_;
|
||||
_fresh = news_.length - _state;
|
||||
|
||||
if (_fresh < 0) {
|
||||
_state = news_.length;
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
}
|
||||
|
||||
_fresh = max(_fresh, 0);
|
||||
|
||||
if (_fresh > 0) {
|
||||
show = true;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void lock() => show = false;
|
||||
|
||||
void release() {
|
||||
if (_fresh == 0) return;
|
||||
|
||||
_fresh--;
|
||||
_state++;
|
||||
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
|
||||
if (_fresh > 0) {
|
||||
show = true;
|
||||
} else {
|
||||
show = false;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:filcnaplo/api/client.dart';
|
||||
import 'package:filcnaplo/models/news.dart';
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class NewsProvider extends ChangeNotifier {
|
||||
// Private
|
||||
late List<News> _news;
|
||||
late int _state;
|
||||
late int _fresh;
|
||||
bool show = false;
|
||||
late BuildContext _context;
|
||||
|
||||
// Public
|
||||
List<News> get news => _news;
|
||||
int get state => _fresh - 1;
|
||||
|
||||
NewsProvider({
|
||||
List<News> initialNews = const [],
|
||||
required BuildContext context,
|
||||
}) {
|
||||
_news = List.castFrom(initialNews);
|
||||
_context = context;
|
||||
}
|
||||
|
||||
Future<void> restore() async {
|
||||
// Load news state from the database
|
||||
var state_ = Provider.of<SettingsProvider>(_context, listen: false).newsState;
|
||||
|
||||
if (state_ == -1) {
|
||||
var news_ = await FilcAPI.getNews();
|
||||
if (news_ != null) {
|
||||
state_ = news_.length;
|
||||
_news = news_;
|
||||
}
|
||||
}
|
||||
|
||||
_state = state_;
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
}
|
||||
|
||||
Future<void> fetch() async {
|
||||
var news_ = await FilcAPI.getNews();
|
||||
if (news_ == null) return;
|
||||
|
||||
_news = news_;
|
||||
_fresh = news_.length - _state;
|
||||
|
||||
if (_fresh < 0) {
|
||||
_state = news_.length;
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
}
|
||||
|
||||
_fresh = max(_fresh, 0);
|
||||
|
||||
if (_fresh > 0) {
|
||||
show = true;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void lock() => show = false;
|
||||
|
||||
void release() {
|
||||
if (_fresh == 0) return;
|
||||
|
||||
_fresh--;
|
||||
_state++;
|
||||
|
||||
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state);
|
||||
|
||||
if (_fresh > 0) {
|
||||
show = true;
|
||||
} else {
|
||||
show = false;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +1,79 @@
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
enum Status { network, maintenance, syncing }
|
||||
|
||||
class StatusProvider extends ChangeNotifier {
|
||||
final List<Status> _stack = [];
|
||||
double _progress = 0.0;
|
||||
ConnectivityResult _networkType = ConnectivityResult.none;
|
||||
ConnectivityResult get networkType => _networkType;
|
||||
|
||||
StatusProvider() {
|
||||
_handleNetworkChanges();
|
||||
Connectivity().checkConnectivity().then((value) => _networkType = value);
|
||||
}
|
||||
|
||||
Status? getStatus() => _stack.isNotEmpty ? _stack[0] : null;
|
||||
// Status progress from 0.0 to 1.0
|
||||
double get progress => _progress;
|
||||
|
||||
void _handleNetworkChanges() {
|
||||
Connectivity().onConnectivityChanged.listen((event) {
|
||||
_networkType = event;
|
||||
if (event == ConnectivityResult.none) {
|
||||
if (!_stack.contains(Status.network)) {
|
||||
_stack.insert(0, Status.network);
|
||||
notifyListeners();
|
||||
}
|
||||
} else {
|
||||
if (_stack.contains(Status.network)) {
|
||||
_stack.remove(Status.network);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void triggerRequest(http.Response res) {
|
||||
if (res.headers.containsKey("x-maintenance-mode") || res.statusCode == 503) {
|
||||
if (!_stack.contains(Status.maintenance)) {
|
||||
_stack.insert(0, Status.maintenance);
|
||||
notifyListeners();
|
||||
}
|
||||
} else {
|
||||
if (_stack.contains(Status.maintenance)) {
|
||||
_stack.remove(Status.maintenance);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void triggerSync({required int current, required int max}) {
|
||||
double prev = _progress;
|
||||
|
||||
if (!_stack.contains(Status.syncing)) {
|
||||
_stack.add(Status.syncing);
|
||||
_progress = 0.0;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
if (max == 0) {
|
||||
_progress = 0.0;
|
||||
} else {
|
||||
_progress = current / max;
|
||||
}
|
||||
|
||||
if (_progress == 1.0) {
|
||||
notifyListeners();
|
||||
// Wait for animation
|
||||
Future.delayed(const Duration(milliseconds: 250), () {
|
||||
_stack.remove(Status.syncing);
|
||||
notifyListeners();
|
||||
});
|
||||
} else if (progress != prev) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
enum Status { network, maintenance, syncing }
|
||||
|
||||
class StatusProvider extends ChangeNotifier {
|
||||
final List<Status> _stack = [];
|
||||
double _progress = 0.0;
|
||||
ConnectivityResult _networkType = ConnectivityResult.none;
|
||||
ConnectivityResult get networkType => _networkType;
|
||||
|
||||
StatusProvider() {
|
||||
_handleNetworkChanges();
|
||||
Connectivity().checkConnectivity().then((value) => _networkType = value);
|
||||
}
|
||||
|
||||
Status? getStatus() => _stack.isNotEmpty ? _stack[0] : null;
|
||||
// Status progress from 0.0 to 1.0
|
||||
double get progress => _progress;
|
||||
|
||||
void _handleNetworkChanges() {
|
||||
Connectivity().onConnectivityChanged.listen((event) {
|
||||
_networkType = event;
|
||||
if (event == ConnectivityResult.none) {
|
||||
if (!_stack.contains(Status.network)) {
|
||||
_stack.insert(0, Status.network);
|
||||
notifyListeners();
|
||||
}
|
||||
} else {
|
||||
if (_stack.contains(Status.network)) {
|
||||
_stack.remove(Status.network);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void triggerRequest(http.Response res) {
|
||||
if (res.headers.containsKey("x-maintenance-mode") || res.statusCode == 503) {
|
||||
if (!_stack.contains(Status.maintenance)) {
|
||||
_stack.insert(0, Status.maintenance);
|
||||
notifyListeners();
|
||||
}
|
||||
} else {
|
||||
if (_stack.contains(Status.maintenance)) {
|
||||
_stack.remove(Status.maintenance);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void triggerSync({required int current, required int max}) {
|
||||
double prev = _progress;
|
||||
|
||||
if (!_stack.contains(Status.syncing)) {
|
||||
_stack.add(Status.syncing);
|
||||
_progress = 0.0;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
if (max == 0) {
|
||||
_progress = 0.0;
|
||||
} else {
|
||||
_progress = current / max;
|
||||
}
|
||||
|
||||
if (_progress == 1.0) {
|
||||
notifyListeners();
|
||||
// Wait for animation
|
||||
Future.delayed(const Duration(milliseconds: 250), () {
|
||||
_stack.remove(Status.syncing);
|
||||
notifyListeners();
|
||||
});
|
||||
} else if (progress != prev) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +1,88 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/api/providers/database_provider.dart';
|
||||
import 'package:filcnaplo/api/providers/status_provider.dart';
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/client/api.dart';
|
||||
import 'package:filcnaplo_kreta_api/client/client.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/student.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/week.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/message_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/note_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:home_widget/home_widget.dart';
|
||||
|
||||
// Mutex
|
||||
bool lock = false;
|
||||
|
||||
Future<void> syncAll(BuildContext context) {
|
||||
if (lock) return Future.value();
|
||||
// Lock
|
||||
lock = true;
|
||||
|
||||
// ignore: avoid_print
|
||||
print("INFO Syncing all");
|
||||
|
||||
UserProvider user = Provider.of<UserProvider>(context, listen: false);
|
||||
StatusProvider statusProvider = Provider.of<StatusProvider>(context, listen: false);
|
||||
|
||||
List<Future<void>> tasks = [];
|
||||
int taski = 0;
|
||||
|
||||
Future<void> syncStatus(Future<void> future) async {
|
||||
await future.onError((error, stackTrace) => null);
|
||||
taski++;
|
||||
statusProvider.triggerSync(current: taski, max: tasks.length);
|
||||
}
|
||||
|
||||
tasks = [
|
||||
syncStatus(Provider.of<GradeProvider>(context, listen: false).fetch()),
|
||||
syncStatus(Provider.of<TimetableProvider>(context, listen: false).fetch(week: Week.current())),
|
||||
syncStatus(Provider.of<ExamProvider>(context, listen: false).fetch()),
|
||||
syncStatus(Provider.of<HomeworkProvider>(context, listen: false).fetch(from: DateTime.now().subtract(const Duration(days: 30)))),
|
||||
syncStatus(Provider.of<MessageProvider>(context, listen: false).fetchAll()),
|
||||
syncStatus(Provider.of<NoteProvider>(context, listen: false).fetch()),
|
||||
syncStatus(Provider.of<EventProvider>(context, listen: false).fetch()),
|
||||
syncStatus(Provider.of<AbsenceProvider>(context, listen: false).fetch()),
|
||||
|
||||
// Sync student
|
||||
syncStatus(() async {
|
||||
if (user.user == null) return;
|
||||
Map? studentJson = await Provider.of<KretaClient>(context, listen: false).getAPI(KretaAPI.student(user.instituteCode!));
|
||||
if (studentJson == null) return;
|
||||
Student student = Student.fromJson(studentJson);
|
||||
|
||||
user.user?.name = student.name;
|
||||
|
||||
// Store user
|
||||
await Provider.of<DatabaseProvider>(context, listen: false).store.storeUser(user.user!);
|
||||
}()),
|
||||
];
|
||||
|
||||
Future<bool?> updateWidget() async {
|
||||
try {
|
||||
return HomeWidget.updateWidget(name: 'widget_timetable.WidgetTimetable');
|
||||
} on PlatformException catch (exception) {
|
||||
debugPrint('Error Updating Widget. $exception');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return Future.wait(tasks).then((value) {
|
||||
// Unlock
|
||||
lock = false;
|
||||
|
||||
// Update Widget
|
||||
if (Platform.isAndroid) updateWidget();
|
||||
});
|
||||
}
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/api/providers/database_provider.dart';
|
||||
import 'package:filcnaplo/api/providers/status_provider.dart';
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/client/api.dart';
|
||||
import 'package:filcnaplo_kreta_api/client/client.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/student.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/week.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/message_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/note_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:home_widget/home_widget.dart';
|
||||
|
||||
// Mutex
|
||||
bool lock = false;
|
||||
|
||||
Future<void> syncAll(BuildContext context) {
|
||||
if (lock) return Future.value();
|
||||
// Lock
|
||||
lock = true;
|
||||
|
||||
// ignore: avoid_print
|
||||
print("INFO Syncing all");
|
||||
|
||||
UserProvider user = Provider.of<UserProvider>(context, listen: false);
|
||||
StatusProvider statusProvider = Provider.of<StatusProvider>(context, listen: false);
|
||||
|
||||
List<Future<void>> tasks = [];
|
||||
int taski = 0;
|
||||
|
||||
Future<void> syncStatus(Future<void> future) async {
|
||||
await future.onError((error, stackTrace) => null);
|
||||
taski++;
|
||||
statusProvider.triggerSync(current: taski, max: tasks.length);
|
||||
}
|
||||
|
||||
tasks = [
|
||||
syncStatus(Provider.of<GradeProvider>(context, listen: false).fetch()),
|
||||
syncStatus(Provider.of<TimetableProvider>(context, listen: false).fetch(week: Week.current())),
|
||||
syncStatus(Provider.of<ExamProvider>(context, listen: false).fetch()),
|
||||
syncStatus(Provider.of<HomeworkProvider>(context, listen: false).fetch(from: DateTime.now().subtract(const Duration(days: 30)))),
|
||||
syncStatus(Provider.of<MessageProvider>(context, listen: false).fetchAll()),
|
||||
syncStatus(Provider.of<NoteProvider>(context, listen: false).fetch()),
|
||||
syncStatus(Provider.of<EventProvider>(context, listen: false).fetch()),
|
||||
syncStatus(Provider.of<AbsenceProvider>(context, listen: false).fetch()),
|
||||
|
||||
// Sync student
|
||||
syncStatus(() async {
|
||||
if (user.user == null) return;
|
||||
Map? studentJson = await Provider.of<KretaClient>(context, listen: false).getAPI(KretaAPI.student(user.instituteCode!));
|
||||
if (studentJson == null) return;
|
||||
Student student = Student.fromJson(studentJson);
|
||||
|
||||
user.user?.name = student.name;
|
||||
|
||||
// Store user
|
||||
await Provider.of<DatabaseProvider>(context, listen: false).store.storeUser(user.user!);
|
||||
}()),
|
||||
];
|
||||
|
||||
Future<bool?> updateWidget() async {
|
||||
try {
|
||||
return HomeWidget.updateWidget(name: 'widget_timetable.WidgetTimetable');
|
||||
} on PlatformException catch (exception) {
|
||||
debugPrint('Error Updating Widget. $exception');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return Future.wait(tasks).then((value) {
|
||||
// Unlock
|
||||
lock = false;
|
||||
|
||||
// Update Widget
|
||||
if (Platform.isAndroid) updateWidget();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/api/client.dart';
|
||||
import 'package:filcnaplo/models/release.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class UpdateProvider extends ChangeNotifier {
|
||||
// Private
|
||||
late List<Release> _releases;
|
||||
bool _available = false;
|
||||
bool get available => _available && _releases.isNotEmpty;
|
||||
|
||||
// Public
|
||||
List<Release> get releases => _releases;
|
||||
|
||||
UpdateProvider({
|
||||
List<Release> initialReleases = const [],
|
||||
required BuildContext context,
|
||||
}) {
|
||||
_releases = List.castFrom(initialReleases);
|
||||
}
|
||||
|
||||
static const currentVersion = String.fromEnvironment("APPVER", defaultValue: "1.0");
|
||||
|
||||
Future<void> fetch() async {
|
||||
if (!Platform.isAndroid) return;
|
||||
|
||||
_releases = await FilcAPI.getReleases() ?? [];
|
||||
_releases.sort((a, b) => -a.version.compareTo(b.version));
|
||||
|
||||
// Check for new releases
|
||||
if (_releases.isNotEmpty) {
|
||||
_available = _releases.first.version.compareTo(Version.fromString(currentVersion)) == 1;
|
||||
// ignore: avoid_print
|
||||
if (_available) print("INFO: New update: ${releases.first.version}");
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/api/client.dart';
|
||||
import 'package:filcnaplo/models/release.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class UpdateProvider extends ChangeNotifier {
|
||||
// Private
|
||||
late List<Release> _releases;
|
||||
bool _available = false;
|
||||
bool get available => _available && _releases.isNotEmpty;
|
||||
|
||||
// Public
|
||||
List<Release> get releases => _releases;
|
||||
|
||||
UpdateProvider({
|
||||
List<Release> initialReleases = const [],
|
||||
required BuildContext context,
|
||||
}) {
|
||||
_releases = List.castFrom(initialReleases);
|
||||
}
|
||||
|
||||
static const currentVersion = String.fromEnvironment("APPVER", defaultValue: "1.0");
|
||||
|
||||
Future<void> fetch() async {
|
||||
if (!Platform.isAndroid) return;
|
||||
|
||||
_releases = await FilcAPI.getReleases() ?? [];
|
||||
_releases.sort((a, b) => -a.version.compareTo(b.version));
|
||||
|
||||
// Check for new releases
|
||||
if (_releases.isNotEmpty) {
|
||||
_available = _releases.first.version.compareTo(Version.fromString(currentVersion)) == 1;
|
||||
// ignore: avoid_print
|
||||
if (_available) print("INFO: New update: ${releases.first.version}");
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo/models/user.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/student.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:home_widget/home_widget.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class UserProvider with ChangeNotifier {
|
||||
final Map<String, User> _users = {};
|
||||
String? _selectedUserId;
|
||||
User? get user => _users[_selectedUserId];
|
||||
|
||||
// _user properties
|
||||
String? get instituteCode => user?.instituteCode;
|
||||
String? get id => user?.id;
|
||||
String? get name => user?.name;
|
||||
String? get username => user?.username;
|
||||
String? get password => user?.password;
|
||||
Role? get role => user?.role;
|
||||
Student? get student => user?.student;
|
||||
String? get nickname => user?.nickname;
|
||||
String get picture => user?.picture ?? "";
|
||||
String? get displayName => user?.displayName;
|
||||
|
||||
final SettingsProvider _settings;
|
||||
|
||||
UserProvider({required SettingsProvider settings}) : _settings = settings;
|
||||
|
||||
void setUser(String userId) async {
|
||||
_selectedUserId = userId;
|
||||
await _settings.update(lastAccountId: userId);
|
||||
if (Platform.isAndroid) updateWidget();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<bool?> updateWidget() async {
|
||||
try {
|
||||
return HomeWidget.updateWidget(name: 'widget_timetable.WidgetTimetable');
|
||||
} on PlatformException catch (exception) {
|
||||
if (kDebugMode) {
|
||||
print('Error Updating Widget After setUser. $exception');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void addUser(User user) {
|
||||
_users[user.id] = user;
|
||||
if (kDebugMode) {
|
||||
print("DEBUG: Added User: ${user.id}");
|
||||
}
|
||||
}
|
||||
|
||||
void removeUser(String userId) async {
|
||||
_users.removeWhere((key, value) => key == userId);
|
||||
if (_users.isNotEmpty) {
|
||||
setUser(_users.keys.first);
|
||||
} else {
|
||||
await _settings.update(lastAccountId: "");
|
||||
}
|
||||
if (Platform.isAndroid) updateWidget();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
User getUser(String userId) {
|
||||
return _users[userId]!;
|
||||
}
|
||||
|
||||
List<User> getUsers() {
|
||||
return _users.values.toList();
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:filcnaplo/models/settings.dart';
|
||||
import 'package:filcnaplo/models/user.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/student.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:home_widget/home_widget.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class UserProvider with ChangeNotifier {
|
||||
final Map<String, User> _users = {};
|
||||
String? _selectedUserId;
|
||||
User? get user => _users[_selectedUserId];
|
||||
|
||||
// _user properties
|
||||
String? get instituteCode => user?.instituteCode;
|
||||
String? get id => user?.id;
|
||||
String? get name => user?.name;
|
||||
String? get username => user?.username;
|
||||
String? get password => user?.password;
|
||||
Role? get role => user?.role;
|
||||
Student? get student => user?.student;
|
||||
String? get nickname => user?.nickname;
|
||||
String get picture => user?.picture ?? "";
|
||||
String? get displayName => user?.displayName;
|
||||
|
||||
final SettingsProvider _settings;
|
||||
|
||||
UserProvider({required SettingsProvider settings}) : _settings = settings;
|
||||
|
||||
void setUser(String userId) async {
|
||||
_selectedUserId = userId;
|
||||
await _settings.update(lastAccountId: userId);
|
||||
if (Platform.isAndroid) updateWidget();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<bool?> updateWidget() async {
|
||||
try {
|
||||
return HomeWidget.updateWidget(name: 'widget_timetable.WidgetTimetable');
|
||||
} on PlatformException catch (exception) {
|
||||
if (kDebugMode) {
|
||||
print('Error Updating Widget After setUser. $exception');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void addUser(User user) {
|
||||
_users[user.id] = user;
|
||||
if (kDebugMode) {
|
||||
print("DEBUG: Added User: ${user.id}");
|
||||
}
|
||||
}
|
||||
|
||||
void removeUser(String userId) async {
|
||||
_users.removeWhere((key, value) => key == userId);
|
||||
if (_users.isNotEmpty) {
|
||||
setUser(_users.keys.first);
|
||||
} else {
|
||||
await _settings.update(lastAccountId: "");
|
||||
}
|
||||
if (Platform.isAndroid) updateWidget();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
User getUser(String userId) {
|
||||
return _users[userId]!;
|
||||
}
|
||||
|
||||
List<User> getUsers() {
|
||||
return _users.values.toList();
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user