first commit
This commit is contained in:
127
lib/config/strings.dart
Normal file
127
lib/config/strings.dart
Normal file
@@ -0,0 +1,127 @@
|
||||
class AppStrings {
|
||||
AppStrings._();
|
||||
|
||||
// Tab
|
||||
static const tabHome = '主页';
|
||||
static const tabTickets = '票据';
|
||||
static const tabSettings = '设置';
|
||||
static const tabAbout = '关于';
|
||||
|
||||
// Login
|
||||
static const appTitle = 'Project Rapollo';
|
||||
static const loginSubtitle = '扫描或输入二维码进行登录';
|
||||
static const qrCodeToken = 'QR Code 令牌';
|
||||
static const qrHint = '粘贴二维码解析内容...';
|
||||
static const qrParsedResult = '解析结果(截取后 64 位)';
|
||||
static const uploadQR = '上传二维码';
|
||||
static const login = '登录';
|
||||
static const loggingIn = '登录中...';
|
||||
static const qrScanSuccess = '二维码解析成功';
|
||||
static const qrScanFailed = '未能识别二维码,请手动粘贴内容';
|
||||
static const qrScanError = '解析失败';
|
||||
static const loginFailed = '登录失败';
|
||||
static const requestFailed = '请求失败';
|
||||
static const settingsTooltip = '设置';
|
||||
|
||||
// Home
|
||||
static const logoutTooltip = '退出登录';
|
||||
static const titleServerNotConfigured = '未配置 Title Server';
|
||||
static const titleServerNotConfiguredDesc = '请配置 Title Server 以获取用户数据。';
|
||||
static const openSettings = '打开设置';
|
||||
static const loadFailed = '数据加载失败';
|
||||
static const retry = '重试';
|
||||
static const unknownUser = '未知用户';
|
||||
static const online = '在线';
|
||||
static const offline = '离线';
|
||||
static const gameInfo = '游戏信息';
|
||||
static const lastGame = '最后游戏';
|
||||
static const lastPlay = '最后游玩';
|
||||
static const lastLogin = '最后登录';
|
||||
static const romVersion = 'Rom 版本';
|
||||
static const dataVersion = '数据版本';
|
||||
static const status = '状态';
|
||||
static const netMember = '联网会员';
|
||||
static const inherit = '继承';
|
||||
static const banState = '封禁状态';
|
||||
static const clean = '正常';
|
||||
static const dailyBonus = '每日奖励';
|
||||
static const notClaimed = '未领取';
|
||||
static const moreDetails = '更多详情';
|
||||
static const userId = '用户 ID';
|
||||
static const totalAwake = '总计 Awake';
|
||||
static const displayRate = '展示 Rate';
|
||||
static const iconId = '图标 ID';
|
||||
static const nameplateId = '名牌 ID';
|
||||
static const trophyId = '奖杯 ID';
|
||||
static const headphoneVol = '耳机音量';
|
||||
static const errorId = '错误 ID';
|
||||
static const rawApiResponse = '原始 API 响应 (调试)';
|
||||
static String rating(int r) => 'Rating: $r';
|
||||
|
||||
// Tickets
|
||||
static const ticketsTitle = '票据';
|
||||
static const musicConfig = '乐曲配置';
|
||||
static const musicId = 'Music ID';
|
||||
static const level = 'Level';
|
||||
static const achievement = 'Achievement';
|
||||
static const comboStatus = 'Combo Status';
|
||||
static const syncStatus = 'Sync Status';
|
||||
static const deluxscoreMax = 'Deluxscore Max';
|
||||
static const scoreRank = 'Score Rank';
|
||||
static const runTicket = '执行打歌';
|
||||
static const runningTicket = '执行中...';
|
||||
static const ticketNotConfigured = '请先配置 Title Server 设置。';
|
||||
static const ticketNeedLogin = '用户未登录,请先返回主页登录。';
|
||||
|
||||
static const stepCheckPreview = '检查登录状态';
|
||||
static const stepUserLogin = '登录游戏';
|
||||
static const stepFetchData = '获取用户数据';
|
||||
static const stepSimulatePlay = '模拟游戏时间';
|
||||
static const stepUploadPlaylog = '上传游玩记录';
|
||||
static const stepUpsertAll = '上传用户数据';
|
||||
static const stepLogout = '退出游戏';
|
||||
static const stepComplete = '打歌完成';
|
||||
static const stepFailed = '执行失败';
|
||||
|
||||
static const ticketErrorAlreadyLogin = '用户已在他处登录,请先退出。';
|
||||
static const ticketErrorChime = 'Chime 验证失败。';
|
||||
static String ticketLoginInfo(int loginId) => 'Login ID: $loginId';
|
||||
|
||||
static const myTickets = '功能票';
|
||||
static const refreshTickets = '刷新';
|
||||
static const loading = '加载中...';
|
||||
static const ticketsNotLoaded = '点击刷新按钮加载功能票。';
|
||||
static const noTickets = '暂无功能票。';
|
||||
|
||||
// Settings
|
||||
static const titleServerSettings = 'Title Server 设置';
|
||||
static const required = '必填';
|
||||
static const optional = '可选 (有默认值)';
|
||||
static const save = '保存';
|
||||
static const labelTitleServerUrl = 'Title Server URL';
|
||||
static const hintTitleServerUrl = 'http://maimai-gm.wahlap.com:42081';
|
||||
static const labelAesKey = 'AES Key';
|
||||
static const hintAesKey = 'your aes key string';
|
||||
static const labelAesIv = 'AES IV';
|
||||
static const hintAesIv = 'your aes iv string';
|
||||
static const labelClientId = 'Client ID';
|
||||
static const hintClientId = 'your client id';
|
||||
static const labelRegionId = 'Region ID';
|
||||
static const hintRegionId = '1';
|
||||
static const labelPlaceId = 'Place ID';
|
||||
static const hintPlaceId = '1403';
|
||||
static const labelObfuscateParam = 'Obfuscate Param';
|
||||
static const hintObfuscateParam = 'LatuAa81';
|
||||
static const labelApiVersion = 'API Version (Mai-Encoding)';
|
||||
static const hintApiVersion = '1.53';
|
||||
static String fieldRequired(String label) => '$label 不能为空';
|
||||
|
||||
// About
|
||||
static const aboutTitle = 'Project Rapollo';
|
||||
static const aboutDesc = '基于 QR Code 的 maimai DX 街机网络登录客户端。';
|
||||
static const credits = '致谢';
|
||||
static const creditBuiltWith = '构建框架';
|
||||
static const creditQRDecode = 'QR 解码';
|
||||
static const creditIconAssets = '图标资源';
|
||||
static const creditLicense = '许可证';
|
||||
}
|
||||
98
lib/config/title_server_config.dart
Normal file
98
lib/config/title_server_config.dart
Normal file
@@ -0,0 +1,98 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class TitleServerConfig {
|
||||
final String titleServerUrl;
|
||||
final String aesKey;
|
||||
final String aesIv;
|
||||
final String obfuscateParam;
|
||||
final String apiVersion;
|
||||
final String clientId;
|
||||
final int regionId;
|
||||
final int placeId;
|
||||
|
||||
const TitleServerConfig({
|
||||
required this.titleServerUrl,
|
||||
required this.aesKey,
|
||||
required this.aesIv,
|
||||
this.obfuscateParam = 'LatuAa81',
|
||||
this.apiVersion = '1.53',
|
||||
required this.clientId,
|
||||
this.regionId = 1,
|
||||
this.placeId = 1403,
|
||||
});
|
||||
|
||||
List<int> get aesKeyBytes => utf8.encode(aesKey);
|
||||
List<int> get aesIvBytes => utf8.encode(aesIv);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'titleServerUrl': titleServerUrl,
|
||||
'aesKey': aesKey,
|
||||
'aesIv': aesIv,
|
||||
'obfuscateParam': obfuscateParam,
|
||||
'apiVersion': apiVersion,
|
||||
'clientId': clientId,
|
||||
'regionId': regionId,
|
||||
'placeId': placeId,
|
||||
};
|
||||
|
||||
factory TitleServerConfig.fromJson(Map<String, dynamic> json) {
|
||||
return TitleServerConfig(
|
||||
titleServerUrl: json['titleServerUrl'] as String? ?? '',
|
||||
aesKey: json['aesKey'] as String? ?? '',
|
||||
aesIv: json['aesIv'] as String? ?? '',
|
||||
obfuscateParam: json['obfuscateParam'] as String? ?? 'LatuAa81',
|
||||
apiVersion: json['apiVersion'] as String? ?? '1.53',
|
||||
clientId: json['clientId'] as String? ?? '',
|
||||
regionId: json['regionId'] as int? ?? 1,
|
||||
placeId: json['placeId'] as int? ?? 1403,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TitleServerConfigHolder {
|
||||
static const _storageKey = 'title_server_config';
|
||||
|
||||
static final TitleServerConfigHolder _instance = TitleServerConfigHolder._();
|
||||
factory TitleServerConfigHolder() => _instance;
|
||||
TitleServerConfigHolder._();
|
||||
|
||||
TitleServerConfig? _config;
|
||||
TitleServerConfig? get config => _config;
|
||||
|
||||
bool get isConfigured {
|
||||
final c = _config;
|
||||
return c != null &&
|
||||
c.titleServerUrl.isNotEmpty &&
|
||||
c.aesKey.isNotEmpty &&
|
||||
c.aesIv.isNotEmpty &&
|
||||
c.clientId.isNotEmpty;
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final raw = prefs.getString(_storageKey);
|
||||
if (raw != null) {
|
||||
try {
|
||||
_config = TitleServerConfig.fromJson(
|
||||
jsonDecode(raw) as Map<String, dynamic>,
|
||||
);
|
||||
} catch (_) {
|
||||
_config = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> update(TitleServerConfig config) async {
|
||||
_config = config;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString(_storageKey, jsonEncode(config.toJson()));
|
||||
}
|
||||
|
||||
Future<void> clear() async {
|
||||
_config = null;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove(_storageKey);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user