feat: mobile-like window size and always-visible stats
- Changed window size to mobile phone format (400x800) - Removed width condition for ActiveProxyFooter - now always visible - Added run-umbrix.sh launch script with icon copying - Stats cards now display on all screen sizes
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:grpc/grpc.dart';
|
||||
import 'package:hiddify/singbox/generated/core.pbgrpc.dart';
|
||||
import 'package:hiddify/singbox/service/singbox_service.dart';
|
||||
import 'package:umbrix/singbox/generated/core.pbgrpc.dart';
|
||||
import 'package:umbrix/singbox/service/singbox_service.dart';
|
||||
|
||||
abstract class CoreSingboxService extends CoreServiceClient
|
||||
implements SingboxService {
|
||||
|
||||
@@ -6,15 +6,15 @@ import 'dart:isolate';
|
||||
import 'package:combine/combine.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:hiddify/core/model/directories.dart';
|
||||
import 'package:hiddify/gen/singbox_generated_bindings.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_config_option.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_outbound.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_stats.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_status.dart';
|
||||
import 'package:hiddify/singbox/model/warp_account.dart';
|
||||
import 'package:hiddify/singbox/service/singbox_service.dart';
|
||||
import 'package:hiddify/utils/utils.dart';
|
||||
import 'package:umbrix/core/model/directories.dart';
|
||||
import 'package:umbrix/gen/singbox_generated_bindings.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_config_option.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_outbound.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_stats.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_status.dart';
|
||||
import 'package:umbrix/singbox/model/warp_account.dart';
|
||||
import 'package:umbrix/singbox/service/singbox_service.dart';
|
||||
import 'package:umbrix/utils/utils.dart';
|
||||
import 'package:loggy/loggy.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
@@ -3,18 +3,47 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:hiddify/core/model/directories.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_config_option.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_outbound.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_stats.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_status.dart';
|
||||
import 'package:hiddify/singbox/model/warp_account.dart';
|
||||
import 'package:hiddify/singbox/service/singbox_service.dart';
|
||||
import 'package:hiddify/utils/custom_loggers.dart';
|
||||
import 'package:umbrix/core/model/directories.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_config_option.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_outbound.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_stats.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_status.dart';
|
||||
import 'package:umbrix/singbox/model/warp_account.dart';
|
||||
import 'package:umbrix/singbox/service/singbox_service.dart';
|
||||
import 'package:umbrix/utils/custom_loggers.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
Map<String, dynamic> _normalizeOutboundGroupJson(Object? raw) {
|
||||
if (raw is Map<String, dynamic>) {
|
||||
if (raw.containsKey('tag')) return raw;
|
||||
if (raw.containsKey('a') && raw.containsKey('b')) {
|
||||
return <String, dynamic>{
|
||||
'tag': raw['a'],
|
||||
'type': raw['b'],
|
||||
'selected': raw['c'] ?? '',
|
||||
'items': (raw['d'] as List<dynamic>? ?? const <dynamic>[]).map(_normalizeOutboundGroupItemJson).toList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
throw FormatException('Invalid outbound group payload: ${raw.runtimeType}');
|
||||
}
|
||||
|
||||
Map<String, dynamic> _normalizeOutboundGroupItemJson(Object? raw) {
|
||||
if (raw is Map<String, dynamic>) {
|
||||
if (raw.containsKey('tag')) return raw;
|
||||
if (raw.containsKey('a') && raw.containsKey('b')) {
|
||||
return <String, dynamic>{
|
||||
'tag': raw['a'],
|
||||
'type': raw['b'],
|
||||
'url-test-delay': raw['c'] ?? 999999,
|
||||
};
|
||||
}
|
||||
}
|
||||
throw FormatException('Invalid outbound group item payload: ${raw.runtimeType}');
|
||||
}
|
||||
|
||||
class PlatformSingboxService with InfraLogger implements SingboxService {
|
||||
static const channelPrefix = "com.hiddify.app";
|
||||
static const channelPrefix = "com.umbrix.app";
|
||||
|
||||
static const methodChannel = MethodChannel("$channelPrefix/method");
|
||||
static const statusChannel = EventChannel("$channelPrefix/service.status", JSONMethodCodec());
|
||||
@@ -74,7 +103,7 @@ class PlatformSingboxService with InfraLogger implements SingboxService {
|
||||
() async {
|
||||
loggy.debug("changing options");
|
||||
await methodChannel.invokeMethod(
|
||||
"change_hiddify_options",
|
||||
"change_options",
|
||||
jsonEncode(options.toJson()),
|
||||
);
|
||||
return right(unit);
|
||||
@@ -170,9 +199,8 @@ class PlatformSingboxService with InfraLogger implements SingboxService {
|
||||
return groupsChannel.receiveBroadcastStream().map(
|
||||
(event) {
|
||||
if (event case String _) {
|
||||
return (jsonDecode(event) as List).map((e) {
|
||||
return SingboxOutboundGroup.fromJson(e as Map<String, dynamic>);
|
||||
}).toList();
|
||||
final decoded = jsonDecode(event) as List;
|
||||
return decoded.map((e) => SingboxOutboundGroup.fromJson(_normalizeOutboundGroupJson(e))).toList();
|
||||
}
|
||||
loggy.error("[group client] unexpected type, msg: $event");
|
||||
throw "invalid type";
|
||||
@@ -187,11 +215,7 @@ class PlatformSingboxService with InfraLogger implements SingboxService {
|
||||
(event) {
|
||||
if (event case String _) {
|
||||
final decoded = jsonDecode(event) as List;
|
||||
loggy.info("🔍 DECODED JSON: ${decoded.length} groups");
|
||||
return decoded.map((e) {
|
||||
loggy.info("🔍 GROUP DATA: $e");
|
||||
return SingboxOutboundGroup.fromJson(e as Map<String, dynamic>);
|
||||
}).toList();
|
||||
return decoded.map((e) => SingboxOutboundGroup.fromJson(_normalizeOutboundGroupJson(e))).toList();
|
||||
}
|
||||
loggy.error("[active group client] unexpected type, msg: $event");
|
||||
throw "invalid type";
|
||||
@@ -205,7 +229,7 @@ class PlatformSingboxService with InfraLogger implements SingboxService {
|
||||
@override
|
||||
Stream<SingboxStats> watchStats() {
|
||||
loggy.debug("watching stats");
|
||||
return statsChannel.receiveBroadcastStream().map(
|
||||
return statsChannel.receiveBroadcastStream().throttleTime(const Duration(milliseconds: 500)).map(
|
||||
(event) {
|
||||
if (event case Map<String, dynamic> _) {
|
||||
return SingboxStats.fromJson(event);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:hiddify/core/model/directories.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_config_option.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_outbound.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_stats.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_status.dart';
|
||||
import 'package:hiddify/singbox/model/warp_account.dart';
|
||||
import 'package:hiddify/singbox/service/ffi_singbox_service.dart';
|
||||
import 'package:hiddify/singbox/service/platform_singbox_service.dart';
|
||||
import 'package:umbrix/core/model/directories.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_config_option.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_outbound.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_stats.dart';
|
||||
import 'package:umbrix/singbox/model/singbox_status.dart';
|
||||
import 'package:umbrix/singbox/model/warp_account.dart';
|
||||
import 'package:umbrix/singbox/service/ffi_singbox_service.dart';
|
||||
import 'package:umbrix/singbox/service/platform_singbox_service.dart';
|
||||
|
||||
abstract interface class SingboxService {
|
||||
factory SingboxService() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:hiddify/singbox/service/singbox_service.dart';
|
||||
import 'package:umbrix/singbox/service/singbox_service.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'singbox_service_provider.g.dart';
|
||||
|
||||
Reference in New Issue
Block a user