Add debug mode
This commit is contained in:
@@ -78,7 +78,9 @@
|
|||||||
"pageTitle": "logs",
|
"pageTitle": "logs",
|
||||||
"clearLogsButtonText": "clear",
|
"clearLogsButtonText": "clear",
|
||||||
"filterHint": "filter",
|
"filterHint": "filter",
|
||||||
"allLevelsFilter": "all"
|
"allLevelsFilter": "all",
|
||||||
|
"shareCoreLogs": "share core logs",
|
||||||
|
"shareAppLogs": "share app logs"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"pageTitle": "settings",
|
"pageTitle": "settings",
|
||||||
@@ -120,7 +122,9 @@
|
|||||||
"miscellaneous": {
|
"miscellaneous": {
|
||||||
"sectionTitle": "miscellaneous",
|
"sectionTitle": "miscellaneous",
|
||||||
"connectionTestUrl": "connection test url",
|
"connectionTestUrl": "connection test url",
|
||||||
"concurrentTestCount": "concurrent test count"
|
"concurrentTestCount": "concurrent test count",
|
||||||
|
"debugMode": "debug mode",
|
||||||
|
"debugModeMsg": "restart the app for this to take effect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
|
|||||||
@@ -78,7 +78,9 @@
|
|||||||
"pageTitle": "لاگها",
|
"pageTitle": "لاگها",
|
||||||
"clearLogsButtonText": "پاکسازی",
|
"clearLogsButtonText": "پاکسازی",
|
||||||
"filterHint": "فیلتر",
|
"filterHint": "فیلتر",
|
||||||
"allLevelsFilter": "همه"
|
"allLevelsFilter": "همه",
|
||||||
|
"shareCoreLogs": "اشتراکگذاری لاگ هسته",
|
||||||
|
"shareAppLogs": "اشتراکگذاری لاگ برنامه"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"pageTitle": "تنظیمات",
|
"pageTitle": "تنظیمات",
|
||||||
@@ -120,7 +122,9 @@
|
|||||||
"miscellaneous": {
|
"miscellaneous": {
|
||||||
"sectionTitle": "متفرقه",
|
"sectionTitle": "متفرقه",
|
||||||
"connectionTestUrl": "لینک تست کانکشن",
|
"connectionTestUrl": "لینک تست کانکشن",
|
||||||
"concurrentTestCount": "شمار تست همزمان"
|
"concurrentTestCount": "شمار تست همزمان",
|
||||||
|
"debugMode": "دیباگ مود",
|
||||||
|
"debugModeMsg": "برای اعمال این تغییر اپ را ریاستارت کنید"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||||
import 'package:hiddify/core/app/app.dart';
|
import 'package:hiddify/core/app/app.dart';
|
||||||
|
import 'package:hiddify/core/prefs/misc_prefs.dart';
|
||||||
import 'package:hiddify/core/prefs/prefs.dart';
|
import 'package:hiddify/core/prefs/prefs.dart';
|
||||||
import 'package:hiddify/data/data_providers.dart';
|
import 'package:hiddify/data/data_providers.dart';
|
||||||
import 'package:hiddify/features/common/active_profile/active_profile_notifier.dart';
|
import 'package:hiddify/features/common/active_profile/active_profile_notifier.dart';
|
||||||
@@ -41,10 +42,12 @@ Future<void> lazyBootstrap(WidgetsBinding widgetsBinding) async {
|
|||||||
overrides: [sharedPreferencesProvider.overrideWithValue(sharedPreferences)],
|
overrides: [sharedPreferencesProvider.overrideWithValue(sharedPreferences)],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final debug = container.read(debugModeProvider) || kDebugMode;
|
||||||
|
|
||||||
final filesEditor = container.read(filesEditorServiceProvider);
|
final filesEditor = container.read(filesEditorServiceProvider);
|
||||||
await filesEditor.init();
|
await filesEditor.init();
|
||||||
|
|
||||||
initLoggers(container.read);
|
initLoggers(container.read, debug);
|
||||||
_loggy.info(
|
_loggy.info(
|
||||||
"os: ${Platform.operatingSystem}(${Platform.operatingSystemVersion})",
|
"os: ${Platform.operatingSystem}(${Platform.operatingSystemVersion})",
|
||||||
);
|
);
|
||||||
@@ -76,9 +79,10 @@ Future<void> lazyBootstrap(WidgetsBinding widgetsBinding) async {
|
|||||||
|
|
||||||
void initLoggers(
|
void initLoggers(
|
||||||
Result Function<Result>(ProviderListenable<Result>) read,
|
Result Function<Result>(ProviderListenable<Result>) read,
|
||||||
|
bool debug,
|
||||||
) {
|
) {
|
||||||
const logLevel = kDebugMode ? LogLevel.all : LogLevel.info;
|
final logLevel = debug ? LogLevel.all : LogLevel.info;
|
||||||
final logToFile = !Platform.isAndroid && !Platform.isIOS;
|
final logToFile = debug || (!Platform.isAndroid && !Platform.isIOS);
|
||||||
Loggy.initLoggy(
|
Loggy.initLoggy(
|
||||||
logPrinter: MultiLogPrinter(
|
logPrinter: MultiLogPrinter(
|
||||||
const PrettyPrinter(),
|
const PrettyPrinter(),
|
||||||
@@ -86,8 +90,7 @@ void initLoggers(
|
|||||||
? FileLogPrinter(read(filesEditorServiceProvider).appLogsPath)
|
? FileLogPrinter(read(filesEditorServiceProvider).appLogsPath)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
// ignore: avoid_redundant_argument_values
|
logOptions: LogOptions(logLevel),
|
||||||
logOptions: const LogOptions(logLevel),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ final concurrentTestCountProvider = PrefNotifier.provider(
|
|||||||
"concurrent_test_count",
|
"concurrent_test_count",
|
||||||
Defaults.concurrentTestCount,
|
Defaults.concurrentTestCount,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final debugModeProvider = PrefNotifier.provider("debug_mode", false);
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class CoreFacadeImpl with ExceptionHandler, InfraLogger implements CoreFacade {
|
|||||||
@override
|
@override
|
||||||
Stream<Either<CoreServiceFailure, String>> watchLogs() {
|
Stream<Either<CoreServiceFailure, String>> watchLogs() {
|
||||||
return singbox
|
return singbox
|
||||||
.watchLogs(filesEditor.logsPath)
|
.watchLogs(filesEditor.coreLogsPath)
|
||||||
.handleExceptions(CoreServiceFailure.unexpected);
|
.handleExceptions(CoreServiceFailure.unexpected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dartx/dartx.dart';
|
import 'package:dartx/dartx.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fpdart/fpdart.dart';
|
import 'package:fpdart/fpdart.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hiddify/core/core_providers.dart';
|
import 'package:hiddify/core/core_providers.dart';
|
||||||
|
import 'package:hiddify/core/prefs/misc_prefs.dart';
|
||||||
import 'package:hiddify/domain/clash/clash.dart';
|
import 'package:hiddify/domain/clash/clash.dart';
|
||||||
import 'package:hiddify/domain/failures.dart';
|
import 'package:hiddify/domain/failures.dart';
|
||||||
import 'package:hiddify/features/common/common.dart';
|
import 'package:hiddify/features/common/common.dart';
|
||||||
import 'package:hiddify/features/logs/notifier/notifier.dart';
|
import 'package:hiddify/features/logs/notifier/notifier.dart';
|
||||||
|
import 'package:hiddify/services/service_providers.dart';
|
||||||
import 'package:hiddify/utils/utils.dart';
|
import 'package:hiddify/utils/utils.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:recase/recase.dart';
|
import 'package:recase/recase.dart';
|
||||||
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:tint/tint.dart';
|
import 'package:tint/tint.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class LogsPage extends HookConsumerWidget {
|
class LogsPage extends HookConsumerWidget {
|
||||||
const LogsPage({super.key});
|
const LogsPage({super.key});
|
||||||
@@ -21,6 +27,45 @@ class LogsPage extends HookConsumerWidget {
|
|||||||
final asyncState = ref.watch(logsNotifierProvider);
|
final asyncState = ref.watch(logsNotifierProvider);
|
||||||
final notifier = ref.watch(logsNotifierProvider.notifier);
|
final notifier = ref.watch(logsNotifierProvider.notifier);
|
||||||
|
|
||||||
|
final debug = ref.watch(debugModeProvider);
|
||||||
|
|
||||||
|
final List<PopupMenuEntry> popupButtons = debug || PlatformUtils.isDesktop
|
||||||
|
? [
|
||||||
|
PopupMenuItem(
|
||||||
|
child: Text(t.logs.shareCoreLogs.sentenceCase),
|
||||||
|
onTap: () async {
|
||||||
|
if (Platform.isWindows || Platform.isLinux) {
|
||||||
|
await launchUrl(
|
||||||
|
ref.read(filesEditorServiceProvider).logsDir.uri,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final file = XFile(
|
||||||
|
ref.read(filesEditorServiceProvider).coreLogsPath,
|
||||||
|
mimeType: "text/plain",
|
||||||
|
);
|
||||||
|
await Share.shareXFiles([file]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
child: Text(t.logs.shareAppLogs.sentenceCase),
|
||||||
|
onTap: () async {
|
||||||
|
if (Platform.isWindows || Platform.isLinux) {
|
||||||
|
await launchUrl(
|
||||||
|
ref.read(filesEditorServiceProvider).logsDir.uri,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final file = XFile(
|
||||||
|
ref.read(filesEditorServiceProvider).appLogsPath,
|
||||||
|
mimeType: "text/plain",
|
||||||
|
);
|
||||||
|
await Share.shareXFiles([file]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
switch (asyncState) {
|
switch (asyncState) {
|
||||||
case AsyncData(value: final state):
|
case AsyncData(value: final state):
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -28,6 +73,14 @@ class LogsPage extends HookConsumerWidget {
|
|||||||
// TODO: fix height
|
// TODO: fix height
|
||||||
toolbarHeight: 90,
|
toolbarHeight: 90,
|
||||||
title: Text(t.logs.pageTitle.titleCase),
|
title: Text(t.logs.pageTitle.titleCase),
|
||||||
|
actions: [
|
||||||
|
if (popupButtons.isNotEmpty)
|
||||||
|
PopupMenuButton(
|
||||||
|
itemBuilder: (context) {
|
||||||
|
return popupButtons;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
bottom: PreferredSize(
|
bottom: PreferredSize(
|
||||||
preferredSize: const Size.fromHeight(36),
|
preferredSize: const Size.fromHeight(36),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hiddify/core/core_providers.dart';
|
import 'package:hiddify/core/core_providers.dart';
|
||||||
import 'package:hiddify/core/prefs/misc_prefs.dart';
|
import 'package:hiddify/core/prefs/misc_prefs.dart';
|
||||||
import 'package:hiddify/domain/constants.dart';
|
import 'package:hiddify/domain/constants.dart';
|
||||||
@@ -16,6 +17,7 @@ class MiscellaneousSettingTiles extends HookConsumerWidget {
|
|||||||
|
|
||||||
final connectionTestUrl = ref.watch(connectionTestUrlProvider);
|
final connectionTestUrl = ref.watch(connectionTestUrlProvider);
|
||||||
final concurrentTestCount = ref.watch(concurrentTestCountProvider);
|
final concurrentTestCount = ref.watch(concurrentTestCountProvider);
|
||||||
|
final debug = ref.watch(debugModeProvider);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -37,7 +39,7 @@ class MiscellaneousSettingTiles extends HookConsumerWidget {
|
|||||||
subtitle: Text(concurrentTestCount.toString()),
|
subtitle: Text(concurrentTestCount.toString()),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final val = await SettingsInputDialog<int>(
|
final val = await SettingsInputDialog<int>(
|
||||||
title: t.settings.miscellaneous.connectionTestUrl.titleCase,
|
title: t.settings.miscellaneous.concurrentTestCount.titleCase,
|
||||||
initialValue: concurrentTestCount,
|
initialValue: concurrentTestCount,
|
||||||
resetValue: Defaults.concurrentTestCount,
|
resetValue: Defaults.concurrentTestCount,
|
||||||
mapTo: (value) => int.tryParse(value),
|
mapTo: (value) => int.tryParse(value),
|
||||||
@@ -47,6 +49,34 @@ class MiscellaneousSettingTiles extends HookConsumerWidget {
|
|||||||
await ref.read(concurrentTestCountProvider.notifier).update(val);
|
await ref.read(concurrentTestCountProvider.notifier).update(val);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
SwitchListTile(
|
||||||
|
title: Text(t.settings.miscellaneous.debugMode.titleCase),
|
||||||
|
value: debug,
|
||||||
|
onChanged: (value) async {
|
||||||
|
if (value) {
|
||||||
|
await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(t.settings.miscellaneous.debugMode.titleCase),
|
||||||
|
content: Text(
|
||||||
|
t.settings.miscellaneous.debugModeMsg.sentenceCase,
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => context.pop(true),
|
||||||
|
child: Text(
|
||||||
|
MaterialLocalizations.of(context).okButtonLabel,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await ref.read(debugModeProvider.notifier).update(value);
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class FilesEditorService with InfraLogger {
|
|||||||
late final Directory baseDir;
|
late final Directory baseDir;
|
||||||
late final Directory workingDir;
|
late final Directory workingDir;
|
||||||
late final Directory tempDir;
|
late final Directory tempDir;
|
||||||
|
late final Directory logsDir;
|
||||||
late final Directory _configsDir;
|
late final Directory _configsDir;
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
@@ -24,10 +25,12 @@ class FilesEditorService with InfraLogger {
|
|||||||
workingDir = await getApplicationDocumentsDirectory();
|
workingDir = await getApplicationDocumentsDirectory();
|
||||||
}
|
}
|
||||||
tempDir = await getTemporaryDirectory();
|
tempDir = await getTemporaryDirectory();
|
||||||
|
logsDir = workingDir;
|
||||||
|
|
||||||
loggy.debug("base dir: ${baseDir.path}");
|
loggy.debug("base dir: ${baseDir.path}");
|
||||||
loggy.debug("working dir: ${workingDir.path}");
|
loggy.debug("working dir: ${workingDir.path}");
|
||||||
loggy.debug("temp dir: ${tempDir.path}");
|
loggy.debug("temp dir: ${tempDir.path}");
|
||||||
|
loggy.debug("logs dire: ${logsDir.path}");
|
||||||
|
|
||||||
_configsDir =
|
_configsDir =
|
||||||
Directory(p.join(workingDir.path, Constants.configsFolderName));
|
Directory(p.join(workingDir.path, Constants.configsFolderName));
|
||||||
@@ -49,13 +52,12 @@ class FilesEditorService with InfraLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _populateGeoAssets();
|
await _populateGeoAssets();
|
||||||
if (PlatformUtils.isDesktop) {
|
|
||||||
final logFile = File(logsPath);
|
final coreLogFile = File(coreLogsPath);
|
||||||
if (await logFile.exists()) {
|
if (await coreLogFile.exists()) {
|
||||||
await logFile.writeAsString("");
|
await coreLogFile.writeAsString("");
|
||||||
} else {
|
} else {
|
||||||
await logFile.create(recursive: true);
|
await coreLogFile.create(recursive: true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,8 +70,8 @@ class FilesEditorService with InfraLogger {
|
|||||||
return getApplicationDocumentsDirectory();
|
return getApplicationDocumentsDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
String get appLogsPath => p.join(workingDir.path, "app.log");
|
String get appLogsPath => p.join(logsDir.path, "app.log");
|
||||||
String get logsPath => p.join(workingDir.path, "box.log");
|
String get coreLogsPath => p.join(logsDir.path, "box.log");
|
||||||
|
|
||||||
String configPath(String fileName) {
|
String configPath(String fileName) {
|
||||||
return p.join(_configsDir.path, "$fileName.json");
|
return p.join(_configsDir.path, "$fileName.json");
|
||||||
|
|||||||
Reference in New Issue
Block a user