♻️ Refactor logging module
This commit is contained in:
parent
32bf834108
commit
ae9743c84f
@ -730,5 +730,6 @@
|
|||||||
"forceUpdateDescription": "Force to show the application update popup, even the new version is not available.",
|
"forceUpdateDescription": "Force to show the application update popup, even the new version is not available.",
|
||||||
"debugLogging": "Runtime Logs",
|
"debugLogging": "Runtime Logs",
|
||||||
"runtimeLogsOpen": "Open Logs",
|
"runtimeLogsOpen": "Open Logs",
|
||||||
"runtimeLogsDescription": "Show the runtime logs to help debugging."
|
"runtimeLogsDescription": "Show the runtime logs to help debugging.",
|
||||||
|
"signinResetPasswordHint": "Please enter the username / email address to help us to find your account and reset your password."
|
||||||
}
|
}
|
||||||
|
@ -728,5 +728,6 @@
|
|||||||
"forceUpdateDescription": "强制更新应用程序,即使有更新的版本可能不可用。",
|
"forceUpdateDescription": "强制更新应用程序,即使有更新的版本可能不可用。",
|
||||||
"runtimeLogs": "运行时日志",
|
"runtimeLogs": "运行时日志",
|
||||||
"runtimeLogsOpen": "打开日志文件",
|
"runtimeLogsOpen": "打开日志文件",
|
||||||
"runtimeLogsDescription": "显示运行时的日志记录。"
|
"runtimeLogsDescription": "显示运行时的日志记录。",
|
||||||
|
"signinResetPasswordHint": "请输入用户名/电子邮箱地址以帮助我们找到您的帐户并重置密码。"
|
||||||
}
|
}
|
||||||
|
@ -728,5 +728,6 @@
|
|||||||
"forceUpdateDescription": "強制更新應用程序,即使有更新的版本可能不可用。",
|
"forceUpdateDescription": "強制更新應用程序,即使有更新的版本可能不可用。",
|
||||||
"runtimeLogs": "運行時日誌",
|
"runtimeLogs": "運行時日誌",
|
||||||
"runtimeLogsOpen": "打開日誌文件",
|
"runtimeLogsOpen": "打開日誌文件",
|
||||||
"runtimeLogsDescription": "顯示運行時的日誌記錄。"
|
"runtimeLogsDescription": "顯示運行時的日誌記錄。",
|
||||||
|
"signinResetPasswordHint": "請輸入用户名/電子郵箱地址以幫助我們找到您的帳户並重置密碼。"
|
||||||
}
|
}
|
||||||
|
@ -728,5 +728,6 @@
|
|||||||
"forceUpdateDescription": "強制更新應用程序,即使有更新的版本可能不可用。",
|
"forceUpdateDescription": "強制更新應用程序,即使有更新的版本可能不可用。",
|
||||||
"runtimeLogs": "運行時日誌",
|
"runtimeLogs": "運行時日誌",
|
||||||
"runtimeLogsOpen": "打開日誌文件",
|
"runtimeLogsOpen": "打開日誌文件",
|
||||||
"runtimeLogsDescription": "顯示運行時的日誌記錄。"
|
"runtimeLogsDescription": "顯示運行時的日誌記錄。",
|
||||||
|
"signinResetPasswordHint": "請輸入用戶名/電子郵箱地址以幫助我們找到您的帳戶並重置密碼。"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
@ -8,6 +7,7 @@ import 'package:drift/drift.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:surface/database/database.dart';
|
import 'package:surface/database/database.dart';
|
||||||
|
import 'package:surface/logger.dart';
|
||||||
import 'package:surface/providers/database.dart';
|
import 'package:surface/providers/database.dart';
|
||||||
import 'package:surface/providers/sn_attachment.dart';
|
import 'package:surface/providers/sn_attachment.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
@ -532,7 +532,7 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
},
|
},
|
||||||
).toJson(),
|
).toJson(),
|
||||||
));
|
));
|
||||||
log('[Messaging] Send read event request: $_readEventAnchor');
|
logging.debug('[Messaging] Send read event request: $_readEventAnchor');
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
import 'package:talker/talker.dart';
|
import 'package:talker/talker.dart';
|
||||||
|
|
||||||
final logging = Talker();
|
final logging = Talker(
|
||||||
|
settings: TalkerSettings(
|
||||||
|
enabled: true,
|
||||||
|
useHistory: true,
|
||||||
|
maxHistoryItems: 1000,
|
||||||
|
useConsoleLogs: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:surface/logger.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/types/link.dart';
|
import 'package:surface/types/link.dart';
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ class SnLinkPreviewProvider {
|
|||||||
final target = b64.encode(url);
|
final target = b64.encode(url);
|
||||||
if (_cache.containsKey(target)) return _cache[target];
|
if (_cache.containsKey(target)) return _cache[target];
|
||||||
|
|
||||||
log('[LinkPreview] Fetching $url ($target)');
|
logging.debug('[LinkPreview] Fetching $url ($target)');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final resp = await _sn.client.get('/cgi/re/link/$target');
|
final resp = await _sn.client.get('/cgi/re/link/$target');
|
||||||
@ -28,7 +28,7 @@ class SnLinkPreviewProvider {
|
|||||||
_cache[url] = meta;
|
_cache[url] = meta;
|
||||||
return meta;
|
return meta;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log('[LinkPreview] Failed to fetch $url ($target)...');
|
logging.warning('[LinkPreview] Failed to fetch $url ($target)...', err);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'dart:developer';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||||
@ -9,6 +8,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_udid/flutter_udid.dart';
|
import 'package:flutter_udid/flutter_udid.dart';
|
||||||
import 'package:local_notifier/local_notifier.dart';
|
import 'package:local_notifier/local_notifier.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:surface/logger.dart';
|
||||||
import 'package:surface/providers/config.dart';
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
@ -48,11 +48,13 @@ class NotificationProvider extends ChangeNotifier {
|
|||||||
var deviceUuid = await FlutterUdid.consistentUdid;
|
var deviceUuid = await FlutterUdid.consistentUdid;
|
||||||
|
|
||||||
if (deviceUuid.isEmpty) {
|
if (deviceUuid.isEmpty) {
|
||||||
log("Unable to active push notifications, couldn't get device uuid");
|
logging.warning(
|
||||||
|
'[Push Notification] Unable to active push notifications, couldn\'t get device uuid');
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
log('Device UUID is $deviceUuid');
|
logging.info('[Push Notification] Device UUID is $deviceUuid');
|
||||||
log('Registering device push notifications...');
|
logging
|
||||||
|
.info('[Push Notification] Registering device push notifications...');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Platform.isIOS || Platform.isMacOS) {
|
if (Platform.isIOS || Platform.isMacOS) {
|
||||||
@ -62,7 +64,7 @@ class NotificationProvider extends ChangeNotifier {
|
|||||||
provider = 'fcm';
|
provider = 'fcm';
|
||||||
token = await FirebaseMessaging.instance.getToken();
|
token = await FirebaseMessaging.instance.getToken();
|
||||||
}
|
}
|
||||||
log('Device Push Token is $token');
|
logging.info('[Push Notification] Device Push Token is $token');
|
||||||
|
|
||||||
await _sn.client.post(
|
await _sn.client.post(
|
||||||
'/cgi/id/notifications/subscription',
|
'/cgi/id/notifications/subscription',
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
@ -11,9 +10,12 @@ import 'package:package_info_plus/package_info_plus.dart';
|
|||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:surface/logger.dart';
|
||||||
import 'package:surface/providers/config.dart';
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/widget.dart';
|
import 'package:surface/providers/widget.dart';
|
||||||
import 'package:synchronized/synchronized.dart';
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
import 'package:talker_dio_logger/talker_dio_logger_interceptor.dart';
|
||||||
|
import 'package:talker_dio_logger/talker_dio_logger_settings.dart';
|
||||||
|
|
||||||
const kNetworkServerDirectory = [
|
const kNetworkServerDirectory = [
|
||||||
('Solar Network', 'https://api.sn.solsynth.dev'),
|
('Solar Network', 'https://api.sn.solsynth.dev'),
|
||||||
@ -36,6 +38,17 @@ class SnNetworkProvider {
|
|||||||
|
|
||||||
client = Dio();
|
client = Dio();
|
||||||
|
|
||||||
|
client.interceptors.add(
|
||||||
|
TalkerDioLogger(
|
||||||
|
talker: logging,
|
||||||
|
settings: const TalkerDioLoggerSettings(
|
||||||
|
printRequestHeaders: false,
|
||||||
|
printResponseHeaders: false,
|
||||||
|
printResponseMessage: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
client.interceptors.add(RetryInterceptor(
|
client.interceptors.add(RetryInterceptor(
|
||||||
dio: client,
|
dio: client,
|
||||||
retries: 3,
|
retries: 3,
|
||||||
@ -69,7 +82,6 @@ class SnNetworkProvider {
|
|||||||
_prefs = _config.prefs;
|
_prefs = _config.prefs;
|
||||||
client.options.baseUrl = _config.serverUrl;
|
client.options.baseUrl = _config.serverUrl;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Dio> createOffContextClient() async {
|
static Future<Dio> createOffContextClient() async {
|
||||||
@ -91,7 +103,8 @@ class SnNetworkProvider {
|
|||||||
RequestOptions options,
|
RequestOptions options,
|
||||||
RequestInterceptorHandler handler,
|
RequestInterceptorHandler handler,
|
||||||
) async {
|
) async {
|
||||||
final atk = await _getFreshAtk(client, prefs.getString(kAtkStoreKey), prefs.getString(kRtkStoreKey), (atk, rtk) {
|
final atk = await _getFreshAtk(client, prefs.getString(kAtkStoreKey),
|
||||||
|
prefs.getString(kRtkStoreKey), (atk, rtk) {
|
||||||
prefs.setString(kAtkStoreKey, atk);
|
prefs.setString(kAtkStoreKey, atk);
|
||||||
prefs.setString(kRtkStoreKey, rtk);
|
prefs.setString(kRtkStoreKey, rtk);
|
||||||
});
|
});
|
||||||
@ -103,7 +116,8 @@ class SnNetworkProvider {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
client.options.baseUrl = prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
client.options.baseUrl =
|
||||||
|
prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
@ -119,7 +133,8 @@ class SnNetworkProvider {
|
|||||||
platformInfo = 'Web; ${deviceInfo.vendor}';
|
platformInfo = 'Web; ${deviceInfo.vendor}';
|
||||||
} else if (Platform.isAndroid) {
|
} else if (Platform.isAndroid) {
|
||||||
final deviceInfo = await DeviceInfoPlugin().androidInfo;
|
final deviceInfo = await DeviceInfoPlugin().androidInfo;
|
||||||
platformInfo = 'Android; ${deviceInfo.brand} ${deviceInfo.model}; ${deviceInfo.id}';
|
platformInfo =
|
||||||
|
'Android; ${deviceInfo.brand} ${deviceInfo.model}; ${deviceInfo.id}';
|
||||||
} else if (Platform.isIOS) {
|
} else if (Platform.isIOS) {
|
||||||
final deviceInfo = await DeviceInfoPlugin().iosInfo;
|
final deviceInfo = await DeviceInfoPlugin().iosInfo;
|
||||||
platformInfo = 'iOS; ${deviceInfo.model}; ${deviceInfo.name}';
|
platformInfo = 'iOS; ${deviceInfo.model}; ${deviceInfo.name}';
|
||||||
@ -128,7 +143,8 @@ class SnNetworkProvider {
|
|||||||
platformInfo = 'MacOS; ${deviceInfo.model}; ${deviceInfo.hostName}';
|
platformInfo = 'MacOS; ${deviceInfo.model}; ${deviceInfo.hostName}';
|
||||||
} else if (Platform.isWindows) {
|
} else if (Platform.isWindows) {
|
||||||
final deviceInfo = await DeviceInfoPlugin().windowsInfo;
|
final deviceInfo = await DeviceInfoPlugin().windowsInfo;
|
||||||
platformInfo = 'Windows NT; ${deviceInfo.productName}; ${deviceInfo.computerName}';
|
platformInfo =
|
||||||
|
'Windows NT; ${deviceInfo.productName}; ${deviceInfo.computerName}';
|
||||||
} else if (Platform.isLinux) {
|
} else if (Platform.isLinux) {
|
||||||
final deviceInfo = await DeviceInfoPlugin().linuxInfo;
|
final deviceInfo = await DeviceInfoPlugin().linuxInfo;
|
||||||
platformInfo = 'Linux; ${deviceInfo.prettyName}';
|
platformInfo = 'Linux; ${deviceInfo.prettyName}';
|
||||||
@ -148,12 +164,15 @@ class SnNetworkProvider {
|
|||||||
final tkLock = Lock();
|
final tkLock = Lock();
|
||||||
|
|
||||||
Future<String?> getFreshAtk() async {
|
Future<String?> getFreshAtk() async {
|
||||||
return await _getFreshAtk(client, _prefs.getString(kAtkStoreKey), _prefs.getString(kRtkStoreKey), (atk, rtk) {
|
return await _getFreshAtk(
|
||||||
|
client, _prefs.getString(kAtkStoreKey), _prefs.getString(kRtkStoreKey),
|
||||||
|
(atk, rtk) {
|
||||||
setTokenPair(atk, rtk);
|
setTokenPair(atk, rtk);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<String?> _getFreshAtk(Dio client, String? atk, String? rtk, Function(String atk, String rtk)? onRefresh) async {
|
static Future<String?> _getFreshAtk(Dio client, String? atk, String? rtk,
|
||||||
|
Function(String atk, String rtk)? onRefresh) async {
|
||||||
if (_refreshCompleter != null) {
|
if (_refreshCompleter != null) {
|
||||||
return await _refreshCompleter!.future;
|
return await _refreshCompleter!.future;
|
||||||
} else {
|
} else {
|
||||||
@ -185,7 +204,8 @@ class SnNetworkProvider {
|
|||||||
final payload = b64.decode(rawPayload);
|
final payload = b64.decode(rawPayload);
|
||||||
final exp = jsonDecode(payload)['exp'];
|
final exp = jsonDecode(payload)['exp'];
|
||||||
if (exp <= DateTime.now().millisecondsSinceEpoch ~/ 1000) {
|
if (exp <= DateTime.now().millisecondsSinceEpoch ~/ 1000) {
|
||||||
log('Access token need refresh, doing it at ${DateTime.now()}');
|
logging.debug(
|
||||||
|
'[Auth] Access token need refresh, doing it at ${DateTime.now()}');
|
||||||
final result = await _refreshToken(client.options.baseUrl, rtk);
|
final result = await _refreshToken(client.options.baseUrl, rtk);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
atk = null;
|
atk = null;
|
||||||
@ -199,12 +219,12 @@ class SnNetworkProvider {
|
|||||||
_refreshCompleter!.complete(atk);
|
_refreshCompleter!.complete(atk);
|
||||||
return atk;
|
return atk;
|
||||||
} else {
|
} else {
|
||||||
log('Access token refresh failed...');
|
logging.error('[Auth] Access token refresh failed...');
|
||||||
_refreshCompleter!.complete(null);
|
_refreshCompleter!.complete(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log('Failed to authenticate user: $err');
|
logging.error('[Auth] Failed to authenticate user...', err);
|
||||||
_refreshCompleter!.completeError(err);
|
_refreshCompleter!.completeError(err);
|
||||||
} finally {
|
} finally {
|
||||||
_refreshCompleter = null;
|
_refreshCompleter = null;
|
||||||
@ -237,7 +257,8 @@ class SnNetworkProvider {
|
|||||||
return result.$1;
|
return result.$1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<(String, String)?> _refreshToken(String baseUrl, String? rtk) async {
|
static Future<(String, String)?> _refreshToken(
|
||||||
|
String baseUrl, String? rtk) async {
|
||||||
if (rtk == null) return null;
|
if (rtk == null) return null;
|
||||||
|
|
||||||
final dio = Dio();
|
final dio = Dio();
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:surface/logger.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/types/attachment.dart';
|
import 'package:surface/types/attachment.dart';
|
||||||
|
|
||||||
@ -51,7 +50,7 @@ class SnStickerProvider {
|
|||||||
return sticker;
|
return sticker;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
_cache[alias] = null;
|
_cache[alias] = null;
|
||||||
log('[Sticker] Failed to lookup sticker $alias: $err');
|
logging.warning('[Sticker] Failed to lookup sticker $alias', err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -66,7 +65,7 @@ class SnStickerProvider {
|
|||||||
_cacheSticker(sticker);
|
_cacheSticker(sticker);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log('[Sticker] Failed to list stickers: $err');
|
logging.error('[Sticker] Failed to list stickers...', err);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:surface/logger.dart';
|
||||||
import 'package:surface/providers/config.dart';
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/types/account.dart';
|
import 'package:surface/types/account.dart';
|
||||||
@ -30,8 +29,8 @@ class UserProvider extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
refreshUser().then((value) async {
|
refreshUser().then((value) async {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
log('Logged in as @${value.name}');
|
logging.info('[Auth] Logged in as @${value.name}');
|
||||||
log('Atk: ${await atk}');
|
logging.debug('[Auth] Access token: ${await atk}');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:surface/logger.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
import 'package:surface/types/websocket.dart';
|
import 'package:surface/types/websocket.dart';
|
||||||
@ -30,7 +30,7 @@ class WebSocketProvider extends ChangeNotifier {
|
|||||||
if (isConnected) return;
|
if (isConnected) return;
|
||||||
if (!_ua.isAuthorized) return;
|
if (!_ua.isAuthorized) return;
|
||||||
|
|
||||||
log('[WebSocket] Connecting to the server...');
|
logging.debug('[WebSocket] Connecting to the server...');
|
||||||
await connect();
|
await connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,17 +62,14 @@ class WebSocketProvider extends ChangeNotifier {
|
|||||||
await conn!.ready;
|
await conn!.ready;
|
||||||
_wsStream = conn!.stream.asBroadcastStream();
|
_wsStream = conn!.stream.asBroadcastStream();
|
||||||
listen();
|
listen();
|
||||||
log('[WebSocket] Connected to server!');
|
logging.info('[WebSocket] Connected to server!');
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err is WebSocketChannelException) {
|
logging.error('[WebSocket] Failed to connect to websocket...', err);
|
||||||
log('Failed to connect to websocket: ${(err.inner as dynamic).message}');
|
|
||||||
} else {
|
|
||||||
log('Failed to connect to websocket: $err');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!noRetry) {
|
if (!noRetry) {
|
||||||
log('Retry connecting to websocket in 3 seconds...');
|
logging.warning(
|
||||||
|
'[WebSocket] Retry connecting to websocket in 3 seconds...');
|
||||||
return Future.delayed(
|
return Future.delayed(
|
||||||
const Duration(seconds: 3),
|
const Duration(seconds: 3),
|
||||||
() => connect(noRetry: true),
|
() => connect(noRetry: true),
|
||||||
@ -100,7 +97,8 @@ class WebSocketProvider extends ChangeNotifier {
|
|||||||
_wsStream!.listen(
|
_wsStream!.listen(
|
||||||
(event) {
|
(event) {
|
||||||
final packet = WebSocketPackage.fromJson(jsonDecode(event));
|
final packet = WebSocketPackage.fromJson(jsonDecode(event));
|
||||||
log('Websocket incoming message: ${packet.method} ${packet.message}');
|
logging.debug(
|
||||||
|
'[Websocket] Incoming message: ${packet.method} ${packet.message}');
|
||||||
pk.sink.add(packet);
|
pk.sink.add(packet);
|
||||||
},
|
},
|
||||||
onDone: () {
|
onDone: () {
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/logger.dart';
|
import 'package:surface/logger.dart';
|
||||||
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
import 'package:talker/talker.dart';
|
import 'package:talker_dio_logger/dio_logs.dart';
|
||||||
|
import 'package:talker_flutter/talker_flutter.dart';
|
||||||
|
|
||||||
final Map<LogLevel, IconData> kLogLevelIcons = {
|
final Map<LogLevel, IconData> kLogLevelIcons = {
|
||||||
LogLevel.error: Symbols.error,
|
LogLevel.error: Symbols.error,
|
||||||
@ -16,15 +19,6 @@ final Map<LogLevel, IconData> kLogLevelIcons = {
|
|||||||
LogLevel.verbose: Symbols.info_i,
|
LogLevel.verbose: Symbols.info_i,
|
||||||
};
|
};
|
||||||
|
|
||||||
final Map<LogLevel, Color> kLogLevelColors = {
|
|
||||||
LogLevel.error: Colors.red,
|
|
||||||
LogLevel.critical: Colors.red,
|
|
||||||
LogLevel.warning: Colors.orange,
|
|
||||||
LogLevel.info: Colors.blue,
|
|
||||||
LogLevel.debug: Colors.green,
|
|
||||||
LogLevel.verbose: Colors.green,
|
|
||||||
};
|
|
||||||
|
|
||||||
final Map<LogLevel, bool> kLogLevelFilled = {
|
final Map<LogLevel, bool> kLogLevelFilled = {
|
||||||
LogLevel.error: false,
|
LogLevel.error: false,
|
||||||
LogLevel.critical: true,
|
LogLevel.critical: true,
|
||||||
@ -39,43 +33,132 @@ class DebugLoggingScreen extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final talkerTheme = TalkerScreenTheme.fromTheme(Theme.of(context));
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const PageBackButton(),
|
leading: const PageBackButton(),
|
||||||
title: Text('debugLogging').tr(),
|
title: Text('debugLogging').tr(),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
logging.cleanHistory();
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
icon: const Icon(Symbols.delete),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: SelectionArea(
|
body: ListView.builder(
|
||||||
child: ListView.builder(
|
reverse: true,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
|
||||||
itemCount: logging.history.length,
|
itemCount: logging.history.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final log = logging.history[index];
|
final log = logging.history[index];
|
||||||
return ListTile(
|
final color = log.getFlutterColor(talkerTheme);
|
||||||
leading: Icon(
|
return ListTile(
|
||||||
kLogLevelIcons[log.logLevel ?? LogLevel.debug] ?? Symbols.help,
|
minTileHeight: 0,
|
||||||
color: kLogLevelColors[log.logLevel ?? LogLevel.debug],
|
tileColor: color.withOpacity(0.2),
|
||||||
fill: (kLogLevelFilled[log.logLevel ?? LogLevel.debug] ?? false)
|
leading: Icon(
|
||||||
? 1
|
kLogLevelIcons[log.logLevel ?? LogLevel.debug] ?? Symbols.help,
|
||||||
: 0,
|
color: color,
|
||||||
),
|
fill: (kLogLevelFilled[log.logLevel ?? LogLevel.debug] ?? false)
|
||||||
title: Column(
|
? 1
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
: 0,
|
||||||
children: [
|
),
|
||||||
|
title: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (log is DioRequestLog)
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${log.requestOptions.method} ${log.displayMessage}',
|
||||||
|
style: GoogleFonts.robotoMono(fontSize: 13),
|
||||||
|
),
|
||||||
|
Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
dividerColor: Colors.transparent,
|
||||||
|
),
|
||||||
|
child: ExpansionTile(
|
||||||
|
title: Text('Payload').fontSize(13),
|
||||||
|
minTileHeight: 0,
|
||||||
|
tilePadding: EdgeInsets.zero,
|
||||||
|
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
log.requestOptions.data.toString(),
|
||||||
|
style: GoogleFonts.robotoMono(fontSize: 13),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
else if (log is DioResponseLog)
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${log.response.statusCode} ${log.displayMessage}',
|
||||||
|
style: GoogleFonts.robotoMono(fontSize: 13),
|
||||||
|
),
|
||||||
|
Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
dividerColor: Colors.transparent,
|
||||||
|
),
|
||||||
|
child: ExpansionTile(
|
||||||
|
title: Text('Payload').fontSize(13),
|
||||||
|
minTileHeight: 0,
|
||||||
|
tilePadding: EdgeInsets.zero,
|
||||||
|
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
log.response.data.toString(),
|
||||||
|
style: GoogleFonts.robotoMono(fontSize: 13),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
else
|
||||||
Text(
|
Text(
|
||||||
log.message ?? 'unknown'.tr(),
|
log.displayMessage,
|
||||||
style: GoogleFonts.robotoMono(fontSize: 13),
|
style: GoogleFonts.robotoMono(fontSize: 13),
|
||||||
),
|
),
|
||||||
if (log.error != null)
|
if (log.exception != null)
|
||||||
Text(
|
Text(
|
||||||
log.error!.toString(),
|
log.displayException,
|
||||||
style: GoogleFonts.robotoMono(fontSize: 13),
|
style: GoogleFonts.robotoMono(fontSize: 13),
|
||||||
).bold(),
|
).bold(),
|
||||||
],
|
if (log.error != null)
|
||||||
),
|
Text(
|
||||||
subtitle: Text(log.time.toString()).fontSize(11),
|
log.displayException,
|
||||||
);
|
style: GoogleFonts.robotoMono(fontSize: 13),
|
||||||
},
|
).bold(),
|
||||||
),
|
if (log.stackTrace != null)
|
||||||
|
Text(
|
||||||
|
log.displayStackTrace,
|
||||||
|
style: GoogleFonts.robotoMono(fontSize: 12),
|
||||||
|
).padding(top: 4),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
'${(log.title?.replaceAll('-', ' ') ?? 'default').capitalizeEachWord()} · ${log.displayTime()}',
|
||||||
|
).fontSize(11),
|
||||||
|
onTap: () {
|
||||||
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text: ['[${log.time}]', log.message, log.error?.toString()]
|
||||||
|
.where((ele) => ele != null)
|
||||||
|
.join('\n'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:cross_file/cross_file.dart';
|
import 'package:cross_file/cross_file.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
@ -8,6 +7,7 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/controllers/post_write_controller.dart';
|
import 'package:surface/controllers/post_write_controller.dart';
|
||||||
|
import 'package:surface/logger.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:video_compress/video_compress.dart';
|
import 'package:video_compress/video_compress.dart';
|
||||||
|
|
||||||
@ -17,10 +17,12 @@ class PendingVideoCompressDialog extends StatefulWidget {
|
|||||||
const PendingVideoCompressDialog({super.key, required this.media});
|
const PendingVideoCompressDialog({super.key, required this.media});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<PendingVideoCompressDialog> createState() => _PendingVideoCompressDialogState();
|
State<PendingVideoCompressDialog> createState() =>
|
||||||
|
_PendingVideoCompressDialogState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PendingVideoCompressDialogState extends State<PendingVideoCompressDialog> {
|
class _PendingVideoCompressDialogState
|
||||||
|
extends State<PendingVideoCompressDialog> {
|
||||||
VideoQuality _quality = VideoQuality.DefaultQuality;
|
VideoQuality _quality = VideoQuality.DefaultQuality;
|
||||||
|
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
@ -50,7 +52,7 @@ class _PendingVideoCompressDialogState extends State<PendingVideoCompressDialog>
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_progressSubscription = VideoCompress.compressProgress$.subscribe((event) {
|
_progressSubscription = VideoCompress.compressProgress$.subscribe((event) {
|
||||||
log('[Compress] Progress: $event');
|
logging.debug('[Paperclip.VideoCompress] Progress: $event');
|
||||||
setState(() {
|
setState(() {
|
||||||
_progress = event / 100;
|
_progress = event / 100;
|
||||||
_isBusy = event < 100;
|
_isBusy = event < 100;
|
||||||
@ -132,7 +134,9 @@ class _PendingVideoCompressDialogState extends State<PendingVideoCompressDialog>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text('attachmentCompressQualityHint', style: Theme.of(context).textTheme.bodySmall!).tr(),
|
Text('attachmentCompressQualityHint',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall!)
|
||||||
|
.tr(),
|
||||||
if (_isBusy)
|
if (_isBusy)
|
||||||
TweenAnimationBuilder<double>(
|
TweenAnimationBuilder<double>(
|
||||||
tween: Tween(begin: 0, end: _progress ?? 0),
|
tween: Tween(begin: 0, end: _progress ?? 0),
|
||||||
|
@ -133,7 +133,8 @@ extension AppPromptExtension on BuildContext {
|
|||||||
),
|
),
|
||||||
recognizer: TapGestureRecognizer()
|
recognizer: TapGestureRecognizer()
|
||||||
..onTap = () {
|
..onTap = () {
|
||||||
launchUrlString('https://kb.solsynth.dev/solar-network');
|
launchUrlString(
|
||||||
|
'https://kb.solsynth.dev/solar-network');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -157,7 +158,17 @@ extension ByteFormatter on int {
|
|||||||
if (this == 0) return '0 Bytes';
|
if (this == 0) return '0 Bytes';
|
||||||
const k = 1024;
|
const k = 1024;
|
||||||
final dm = decimals < 0 ? 0 : decimals;
|
final dm = decimals < 0 ? 0 : decimals;
|
||||||
final sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
final sizes = [
|
||||||
|
'Bytes',
|
||||||
|
'KiB',
|
||||||
|
'MiB',
|
||||||
|
'GiB',
|
||||||
|
'TiB',
|
||||||
|
'PiB',
|
||||||
|
'EiB',
|
||||||
|
'ZiB',
|
||||||
|
'YiB'
|
||||||
|
];
|
||||||
final i = (math.log(this) / math.log(k)).floor().toInt();
|
final i = (math.log(this) / math.log(k)).floor().toInt();
|
||||||
return '${(this / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
return '${(this / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
||||||
}
|
}
|
||||||
@ -167,4 +178,15 @@ extension StringFormatter on String {
|
|||||||
String capitalize() {
|
String capitalize() {
|
||||||
return "${this[0].toUpperCase()}${substring(1)}";
|
return "${this[0].toUpperCase()}${substring(1)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String capitalizeEachWord() {
|
||||||
|
if (isEmpty) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return split(' ')
|
||||||
|
.map((word) => word.isNotEmpty
|
||||||
|
? '${word[0].toUpperCase()}${word.substring(1)}'
|
||||||
|
: '')
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user