refactor: share low-risk UI and tracker helpers

This commit is contained in:
edde746
2026-05-02 01:58:50 +02:00
parent 646832c6b1
commit 50bc245677
18 changed files with 270 additions and 265 deletions
@@ -1,6 +1,5 @@
import 'dart:convert';
import '../oauth_proxy_client.dart';
import '../tracker_session_utils.dart';
/// Immutable AniList OAuth session.
///
@@ -14,7 +13,7 @@ class AnilistSession {
const AnilistSession({required this.accessToken, required this.expiresAt, required this.createdAt, this.username});
bool get isExpired => DateTime.now().millisecondsSinceEpoch ~/ 1000 >= expiresAt;
bool get isExpired => isTrackerTokenExpired(expiresAt);
AnilistSession copyWith({String? accessToken, int? expiresAt, String? username, int? createdAt}) {
return AnilistSession(
@@ -43,11 +42,11 @@ class AnilistSession {
/// and have no refresh; when the proxy doesn't echo an explicit expiry we
/// default to the documented year.
factory AnilistSession.fromProxyResult(OAuthProxyResult r) {
final createdAt = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final createdAt = trackerSessionNowEpochSeconds();
final expiresIn = r.expiresIn ?? 365 * 24 * 60 * 60;
return AnilistSession(accessToken: r.accessToken, expiresAt: createdAt + expiresIn, createdAt: createdAt);
}
String encode() => json.encode(toJson());
static AnilistSession decode(String raw) => AnilistSession.fromJson(json.decode(raw) as Map<String, dynamic>);
String encode() => encodeTrackerSessionJson(toJson());
static AnilistSession decode(String raw) => decodeTrackerSessionJson(raw, AnilistSession.fromJson);
}
+7 -8
View File
@@ -1,6 +1,5 @@
import 'dart:convert';
import '../oauth_proxy_client.dart';
import '../tracker_session_utils.dart';
/// Immutable MyAnimeList OAuth session.
///
@@ -21,8 +20,8 @@ class MalSession {
this.username,
});
bool get isExpired => DateTime.now().millisecondsSinceEpoch ~/ 1000 >= expiresAt;
bool get needsRefresh => DateTime.now().millisecondsSinceEpoch ~/ 1000 >= expiresAt - 300;
bool get isExpired => isTrackerTokenExpired(expiresAt);
bool get needsRefresh => trackerTokenNeedsRefresh(expiresAt);
MalSession copyWith({String? accessToken, String? refreshToken, int? expiresAt, String? username, int? createdAt}) {
return MalSession(
@@ -52,7 +51,7 @@ class MalSession {
/// Build a session from MAL's `/oauth2/token` response.
factory MalSession.fromTokenResponse(Map<String, dynamic> json) {
final createdAt = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final createdAt = trackerSessionNowEpochSeconds();
final expiresIn = (json['expires_in'] as num).toInt();
return MalSession(
accessToken: json['access_token'] as String,
@@ -65,7 +64,7 @@ class MalSession {
/// Build a session from an OAuth-proxy result. MAL's refresh_token is
/// required for the 31-day refresh loop.
factory MalSession.fromProxyResult(OAuthProxyResult r) {
final createdAt = DateTime.now().millisecondsSinceEpoch ~/ 1000;
final createdAt = trackerSessionNowEpochSeconds();
final expiresIn = r.expiresIn ?? 31 * 24 * 60 * 60;
return MalSession(
accessToken: r.accessToken,
@@ -75,6 +74,6 @@ class MalSession {
);
}
String encode() => json.encode(toJson());
static MalSession decode(String raw) => MalSession.fromJson(json.decode(raw) as Map<String, dynamic>);
String encode() => encodeTrackerSessionJson(toJson());
static MalSession decode(String raw) => decodeTrackerSessionJson(raw, MalSession.fromJson);
}
@@ -1,4 +1,4 @@
import 'dart:convert';
import '../tracker_session_utils.dart';
/// Immutable Simkl OAuth session.
///
@@ -27,11 +27,9 @@ class SimklSession {
/// Build a session from Simkl's device-code `/oauth/pin/<code>` response.
/// Simkl doesn't expose a creation timestamp so we stamp "now".
factory SimklSession.fromTokenResponse(Map<String, dynamic> json) => SimklSession(
accessToken: json['access_token'] as String,
createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000,
);
factory SimklSession.fromTokenResponse(Map<String, dynamic> json) =>
SimklSession(accessToken: json['access_token'] as String, createdAt: trackerSessionNowEpochSeconds());
String encode() => json.encode(toJson());
static SimklSession decode(String raw) => SimklSession.fromJson(json.decode(raw) as Map<String, dynamic>);
String encode() => encodeTrackerSessionJson(toJson());
static SimklSession decode(String raw) => decodeTrackerSessionJson(raw, SimklSession.fromJson);
}
@@ -0,0 +1,16 @@
import 'dart:convert' as convert;
/// Current epoch time in seconds, matching tracker OAuth expiry fields.
int trackerSessionNowEpochSeconds() => DateTime.now().millisecondsSinceEpoch ~/ 1000;
bool isTrackerTokenExpired(int expiresAt, {int? nowSeconds}) =>
(nowSeconds ?? trackerSessionNowEpochSeconds()) >= expiresAt;
bool trackerTokenNeedsRefresh(int expiresAt, {int refreshWindowSeconds = 300, int? nowSeconds}) =>
(nowSeconds ?? trackerSessionNowEpochSeconds()) >= expiresAt - refreshWindowSeconds;
String encodeTrackerSessionJson(Map<String, dynamic> value) => convert.json.encode(value);
T decodeTrackerSessionJson<T>(String raw, T Function(Map<String, dynamic> json) fromJson) {
return fromJson(convert.json.decode(raw) as Map<String, dynamic>);
}