Fix autoRun show issues

Fix Android 10 issues

Optimize ip show
This commit is contained in:
chen08209
2024-06-23 00:26:24 +08:00
parent 18add7fba3
commit ba91fab2b5
20 changed files with 270 additions and 199 deletions

View File

@@ -64,7 +64,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
toast!!.show()
}
@RequiresApi(Build.VERSION_CODES.Q)
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"moveTaskToBack" -> {
@@ -151,7 +150,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
val message = call.argument<String>("message")
tip(message)
result.success(true)
}
else -> {

View File

@@ -2,20 +2,13 @@ import 'package:flutter/material.dart';
import 'color.dart';
extension TextStyleExtension on TextStyle {
toLight() {
return copyWith(color: color?.toLight());
}
TextStyle get toLight => copyWith(color: color?.toLight());
toLighter() {
return copyWith(color: color?.toLighter());
}
TextStyle get toLighter => copyWith(color: color?.toLighter());
TextStyle get toSoftBold => copyWith(fontWeight: FontWeight.w500);
toSoftBold() {
return copyWith(fontWeight: FontWeight.w500);
}
TextStyle get toBold => copyWith(fontWeight: FontWeight.bold);
toBold() {
return copyWith(fontWeight: FontWeight.bold);
}
}
TextStyle get toMinus => copyWith(fontSize: fontSize! - 1);
}

View File

@@ -1,7 +1,6 @@
import 'dart:async';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/plugins/app.dart';
import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@@ -267,6 +266,7 @@ class AppController {
}
init() async {
updateLogStatus();
if (!config.silentLaunch) {
window?.show();
}
@@ -290,14 +290,13 @@ class AppController {
}
afterInit() async {
if (config.autoRun) {
await proxyManager.updateStartTime();
if (proxyManager.isStart) {
await updateSystemProxy(true);
} else {
await proxyManager.updateStartTime();
await updateSystemProxy(proxyManager.isStart);
await updateSystemProxy(config.autoRun);
}
autoUpdateProfiles();
updateLogStatus();
autoCheckUpdate();
}

View File

@@ -31,7 +31,7 @@ class CoreInfo extends StatelessWidget {
style: context
.textTheme
.titleMedium
?.toSoftBold(),
?.toSoftBold,
),
),
const SizedBox(
@@ -44,7 +44,7 @@ class CoreInfo extends StatelessWidget {
style: context
.textTheme
.titleLarge
?.toSoftBold(),
?.toSoftBold,
),
),
],

View File

@@ -19,7 +19,7 @@ class _IntranetIpState extends State<IntranetIp> {
List<NetworkInterface> interfaces = await NetworkInterface.list();
for (final interface in interfaces) {
for (final address in interface.addresses) {
if (address.type == InternetAddressType.IPv4 && !address.isLoopback) {
if (!address.isLoopback) {
return address.address;
}
}
@@ -50,7 +50,7 @@ class _IntranetIpState extends State<IntranetIp> {
),
child: Container(
padding: const EdgeInsets.all(16).copyWith(top: 0),
height: globalState.appController.measure.titleLargeHeight + 16,
height: globalState.appController.measure.titleLargeHeight + 24 - 1,
child: ValueListenableBuilder(
valueListenable: ipNotifier,
builder: (_, value, __) {
@@ -65,7 +65,7 @@ class _IntranetIpState extends State<IntranetIp> {
child: TooltipText(
text: Text(
value,
style: context.textTheme.titleLarge?.toSoftBold(),
style: context.textTheme.titleLarge?.toSoftBold.toMinus,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@@ -74,8 +74,11 @@ class _IntranetIpState extends State<IntranetIp> {
],
)
: const Padding(
padding: EdgeInsets.all(4),
child: CircularProgressIndicator(),
padding: EdgeInsets.all(2),
child: AspectRatio(
aspectRatio: 1,
child: CircularProgressIndicator(),
),
),
);
},

View File

@@ -135,7 +135,7 @@ class _NetworkDetectionState extends State<NetworkDetection> {
),
Container(
height:
globalState.appController.measure.titleLargeHeight + 24,
globalState.appController.measure.titleLargeHeight + 24 - 1,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.all(16).copyWith(top: 0),
child: FadeBox(
@@ -150,7 +150,7 @@ class _NetworkDetectionState extends State<NetworkDetection> {
text: Text(
ipInfo.ip,
style: context.textTheme.titleLarge
?.toSoftBold(),
?.toSoftBold.toMinus,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@@ -164,9 +164,9 @@ class _NetworkDetectionState extends State<NetworkDetection> {
if (timeout) {
return Text(
"timeout",
style: context.textTheme.titleMedium
style: context.textTheme.titleLarge
?.copyWith(color: Colors.red)
.toSoftBold(),
.toSoftBold.toMinus,
maxLines: 1,
overflow: TextOverflow.ellipsis,
);

View File

@@ -47,8 +47,8 @@ class _NetworkSpeedState extends State<NetworkSpeed> {
final showValue = value.showValue;
final showUnit = "${value.showUnit}/s";
final titleLargeSoftBold =
Theme.of(context).textTheme.titleLarge?.toSoftBold();
final bodyMedium = Theme.of(context).textTheme.bodySmall?.toLight();
Theme.of(context).textTheme.titleLarge?.toSoftBold;
final bodyMedium = Theme.of(context).textTheme.bodySmall?.toLight;
final valueText = Text(
showValue,
style: titleLargeSoftBold,
@@ -75,7 +75,7 @@ class _NetworkSpeedState extends State<NetworkSpeed> {
Flexible(
child: Text(
label,
style: Theme.of(context).textTheme.titleSmall?.toSoftBold(),
style: Theme.of(context).textTheme.titleSmall?.toSoftBold,
),
),
],

View File

@@ -67,7 +67,7 @@ class OutboundMode extends StatelessWidget {
.of(context)
.textTheme
.titleMedium
?.toSoftBold(),
?.toSoftBold,
),
),
],

View File

@@ -13,19 +13,17 @@ class StartButton extends StatefulWidget {
class _StartButtonState extends State<StartButton>
with SingleTickerProviderStateMixin {
bool isStart = false;
bool isInit = false;
late AnimationController _controller;
bool isStart = false;
@override
void initState() {
isStart = globalState.appController.appState.isStart;
super.initState();
_controller = AnimationController(
vsync: this,
value: isStart ? 1 : 0,
value: 0,
duration: const Duration(milliseconds: 200),
);
super.initState();
}
@override
@@ -35,9 +33,12 @@ class _StartButtonState extends State<StartButton>
}
handleSwitchStart() {
isStart = !isStart;
updateController();
updateSystemProxy();
final appController = globalState.appController;
if (isStart == appController.appState.isStart) {
isStart = !isStart;
updateController();
appController.updateSystemProxy(isStart);
}
}
updateController() {
@@ -48,11 +49,18 @@ class _StartButtonState extends State<StartButton>
}
}
updateSystemProxy() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
final appController = globalState.appController;
await appController.updateSystemProxy(isStart);
});
Widget _updateControllerContainer(Widget child) {
return Selector<AppState, bool>(
selector: (_, appState) => appState.isStart,
builder: (_, isStart, child) {
if(isStart != this.isStart){
this.isStart = isStart;
updateController();
}
return child!;
},
child: child,
);
}
@override
@@ -72,8 +80,7 @@ class _StartButtonState extends State<StartButton>
other.getTimeDifference(
DateTime.now(),
),
style:
Theme.of(context).textTheme.titleMedium?.toSoftBold(),
style: Theme.of(context).textTheme.titleMedium?.toSoftBold,
),
)
.width +
@@ -119,24 +126,14 @@ class _StartButtonState extends State<StartButton>
child: child,
);
},
child: Selector<AppState, bool>(
selector: (_, appState) => appState.runTime != null,
builder: (_, isRun, child) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (isStart != isRun) {
isStart = isRun;
updateController();
}
});
return child!;
},
child: Selector<AppState, int?>(
child: _updateControllerContainer(
Selector<AppState, int?>(
selector: (_, appState) => appState.runTime,
builder: (_, int? value, __) {
final text = other.getTimeText(value);
return Text(
text,
style: Theme.of(context).textTheme.titleMedium?.toSoftBold(),
style: Theme.of(context).textTheme.titleMedium?.toSoftBold,
);
},
),

View File

@@ -42,7 +42,7 @@ class TrafficUsage extends StatelessWidget {
),
Text(
trafficValue.showUnit,
style: context.textTheme.labelMedium?.toLight(),
style: context.textTheme.labelMedium?.toLight,
),
],
);

View File

@@ -1,4 +1,4 @@
export 'proxies.dart';
export 'proxies/proxies.dart';
export 'dashboard/dashboard.dart';
export 'tools.dart';
export 'profiles/profiles.dart';

View File

@@ -253,7 +253,7 @@ class _ProfileItemState extends State<ProfileItem> {
),
Text(
profile.lastUpdateDate?.lastUpdateTimeDesc ?? '',
style: textTheme.labelMedium?.toLight(),
style: textTheme.labelMedium?.toLight,
),
],
),
@@ -284,7 +284,7 @@ class _ProfileItemState extends State<ProfileItem> {
),
Text(
"$useShow / $totalShow",
style: textTheme.labelMedium?.toLight(),
style: textTheme.labelMedium?.toLight,
),
const SizedBox(
height: 2,
@@ -293,14 +293,14 @@ class _ProfileItemState extends State<ProfileItem> {
children: [
Text(
appLocalizations.expirationTime,
style: textTheme.labelMedium?.toLighter(),
style: textTheme.labelMedium?.toLighter,
),
const SizedBox(
width: 4,
),
Text(
expireShow,
style: textTheme.labelMedium?.toLighter(),
style: textTheme.labelMedium?.toLighter,
),
],
)

View File

@@ -0,0 +1,59 @@
import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/widgets/card.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ProxiesExpansionPanelFragment extends StatefulWidget {
const ProxiesExpansionPanelFragment({super.key});
@override
State<ProxiesExpansionPanelFragment> createState() =>
_ProxiesExpansionPanelFragmentState();
}
class _ProxiesExpansionPanelFragmentState
extends State<ProxiesExpansionPanelFragment> {
@override
Widget build(BuildContext context) {
return Selector2<AppState, Config, ProxiesSelectorState>(
selector: (_, appState, config) {
final currentGroups = appState.currentGroups;
final groupNames = currentGroups.map((e) => e.name).toList();
return ProxiesSelectorState(
groupNames: groupNames,
currentGroupName: config.currentGroupName,
);
},
builder: (_, state, __) {
return ListView.separated(
padding: const EdgeInsets.all(16),
itemCount: state.groupNames.length,
itemBuilder: (_, index) {
final groupName = state.groupNames[index];
return CommonCard(
child: ExpansionTile(
title: Text(groupName),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0.0),
side: const BorderSide(color: Colors.transparent),
),
collapsedShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0.0),
side: const BorderSide(color: Colors.transparent),
),
children: [
Text("1212313"),
],
),
);
},
separatorBuilder: (BuildContext context, int index) {
return const SizedBox(
height: 16,
);
},
);
},
);
}
}

View File

@@ -0,0 +1,72 @@
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/fragments/proxies/tabview.dart';
import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ProxiesFragment extends StatefulWidget {
const ProxiesFragment({super.key});
@override
State<ProxiesFragment> createState() => _ProxiesFragmentState();
}
class _ProxiesFragmentState extends State<ProxiesFragment> {
_initActions() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final commonScaffoldState =
context.findAncestorStateOfType<CommonScaffoldState>();
final items = [
CommonPopupMenuItem(
action: ProxiesSortType.none,
label: appLocalizations.defaultSort,
iconData: Icons.sort,
),
CommonPopupMenuItem(
action: ProxiesSortType.delay,
label: appLocalizations.delaySort,
iconData: Icons.network_ping),
CommonPopupMenuItem(
action: ProxiesSortType.name,
label: appLocalizations.nameSort,
iconData: Icons.sort_by_alpha),
];
commonScaffoldState?.actions = [
Selector<Config, ProxiesSortType>(
selector: (_, config) => config.proxiesSortType,
builder: (_, proxiesSortType, __) {
return CommonPopupMenu<ProxiesSortType>.radio(
items: items,
onSelected: (value) {
final config = context.read<Config>();
config.proxiesSortType = value;
},
selectedValue: proxiesSortType,
);
},
),
const SizedBox(
width: 8,
)
];
});
}
@override
Widget build(BuildContext context) {
return Selector<AppState, bool>(
selector: (_, appState) => appState.currentLabel == 'proxies',
builder: (_, isCurrent, child) {
if (isCurrent) {
_initActions();
}
return child!;
},
child: const ProxiesTabFragment(),
);
}
}

View File

@@ -1,65 +1,23 @@
import 'package:collection/collection.dart';
import 'package:fl_clash/clash/clash.dart';
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/state.dart';
import 'package:fl_clash/widgets/widgets.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../enum/enum.dart';
import '../models/models.dart';
import '../common/common.dart';
import '../widgets/widgets.dart';
class ProxiesFragment extends StatefulWidget {
const ProxiesFragment({super.key});
class ProxiesTabFragment extends StatefulWidget {
const ProxiesTabFragment({super.key});
@override
State<ProxiesFragment> createState() => _ProxiesFragmentState();
State<ProxiesTabFragment> createState() => _ProxiesTabFragmentState();
}
class _ProxiesFragmentState extends State<ProxiesFragment>
with TickerProviderStateMixin {
class _ProxiesTabFragmentState extends State<ProxiesTabFragment> with TickerProviderStateMixin {
TabController? _tabController;
_initActions() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final commonScaffoldState =
context.findAncestorStateOfType<CommonScaffoldState>();
final items = [
CommonPopupMenuItem(
action: ProxiesSortType.none,
label: appLocalizations.defaultSort,
iconData: Icons.sort,
),
CommonPopupMenuItem(
action: ProxiesSortType.delay,
label: appLocalizations.delaySort,
iconData: Icons.network_ping),
CommonPopupMenuItem(
action: ProxiesSortType.name,
label: appLocalizations.nameSort,
iconData: Icons.sort_by_alpha),
];
commonScaffoldState?.actions = [
Selector<Config, ProxiesSortType>(
selector: (_, config) => config.proxiesSortType,
builder: (_, proxiesSortType, __) {
return CommonPopupMenu<ProxiesSortType>.radio(
items: items,
onSelected: (value) {
final config = context.read<Config>();
config.proxiesSortType = value;
},
selectedValue: proxiesSortType,
);
},
),
const SizedBox(
width: 8,
)
];
});
}
_handleTabControllerChange() {
final indexIsChanging = _tabController?.indexIsChanging ?? false;
if (indexIsChanging) return;
@@ -71,6 +29,7 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
appController.config.updateCurrentGroupName(currentGroups[index].name);
}
}
@override
void dispose() {
super.dispose();
@@ -79,79 +38,70 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
@override
Widget build(BuildContext context) {
return Selector<AppState, bool>(
selector: (_, appState) => appState.currentLabel == 'proxies',
builder: (_, isCurrent, child) {
if (isCurrent) {
_initActions();
}
return child!;
return Selector2<AppState, Config, ProxiesSelectorState>(
selector: (_, appState, config) {
final currentGroups = appState.currentGroups;
final groupNames = currentGroups.map((e) => e.name).toList();
return ProxiesSelectorState(
groupNames: groupNames,
currentGroupName: config.currentGroupName,
);
},
child: Selector2<AppState, Config, ProxiesSelectorState>(
selector: (_, appState, config) {
final currentGroups = appState.currentGroups;
final groupNames = currentGroups.map((e) => e.name).toList();
return ProxiesSelectorState(
groupNames: groupNames,
currentGroupName: config.currentGroupName,
);
},
shouldRebuild: (prev, next) {
if (!const ListEquality<String>()
.equals(prev.groupNames, next.groupNames)) {
_tabController?.removeListener(_handleTabControllerChange);
_tabController?.dispose();
_tabController = null;
return true;
}
return false;
},
builder: (_, state, __) {
final index = state.groupNames.indexWhere(
(item) => item == state.currentGroupName,
);
_tabController ??= TabController(
length: state.groupNames.length,
initialIndex: index == -1 ? 0 : index,
vsync: this,
)..addListener(_handleTabControllerChange);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
shouldRebuild: (prev, next) {
if (!const ListEquality<String>()
.equals(prev.groupNames, next.groupNames)) {
_tabController?.removeListener(_handleTabControllerChange);
_tabController?.dispose();
_tabController = null;
return true;
}
return false;
},
builder: (_, state, __) {
final index = state.groupNames.indexWhere(
(item) => item == state.currentGroupName,
);
_tabController ??= TabController(
length: state.groupNames.length,
initialIndex: index == -1 ? 0 : index,
vsync: this,
)..addListener(_handleTabControllerChange);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
controller: _tabController,
padding: const EdgeInsets.symmetric(horizontal: 16),
dividerColor: Colors.transparent,
isScrollable: true,
tabAlignment: TabAlignment.start,
overlayColor:
const WidgetStatePropertyAll(Colors.transparent),
tabs: [
for (final groupName in state.groupNames)
Tab(
text: groupName,
),
],
),
Expanded(
child: TabBarView(
controller: _tabController,
padding: const EdgeInsets.symmetric(horizontal: 16),
dividerColor: Colors.transparent,
isScrollable: true,
tabAlignment: TabAlignment.start,
overlayColor:
const WidgetStatePropertyAll(Colors.transparent),
tabs: [
children: [
for (final groupName in state.groupNames)
Tab(
text: groupName,
KeepContainer(
key: ObjectKey(groupName),
child: ProxiesTabView(
groupName: groupName,
),
),
],
),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
for (final groupName in state.groupNames)
KeepContainer(
key: ObjectKey(groupName),
child: ProxiesTabView(
groupName: groupName,
),
),
],
),
)
],
);
},
),
)
],
);
},
);
}
}
@@ -167,7 +117,7 @@ class ProxiesTabView extends StatelessWidget {
List<Proxy> _sortOfName(List<Proxy> proxies) {
return List.of(proxies)
..sort(
(a, b) => other.sortByChar(a.name, b.name),
(a, b) => other.sortByChar(a.name, b.name),
);
}
@@ -175,7 +125,7 @@ class ProxiesTabView extends StatelessWidget {
final appState = context.read<AppState>();
return proxies = List.of(proxies)
..sort(
(a, b) {
(a, b) {
final aDelay = appState.getDelay(a.name);
final bDelay = appState.getDelay(b.name);
if (aDelay == null && bDelay == null) {
@@ -193,10 +143,10 @@ class ProxiesTabView extends StatelessWidget {
}
_getProxies(
BuildContext context,
List<Proxy> proxies,
ProxiesSortType proxiesSortType,
) {
BuildContext context,
List<Proxy> proxies,
ProxiesSortType proxiesSortType,
) {
if (proxiesSortType == ProxiesSortType.delay) {
return _sortOfDelay(context, proxies);
}
@@ -379,7 +329,7 @@ class ProxyCard extends StatelessWidget {
style: context.textTheme.bodySmall?.copyWith(
overflow: TextOverflow.ellipsis,
color:
context.textTheme.bodySmall?.color?.toLight(),
context.textTheme.bodySmall?.color?.toLight(),
),
),
);

View File

@@ -187,7 +187,7 @@
"connections": "Connections",
"connectionsDesc": "View current connection",
"nullRequestsDesc": "No requests",
"nullConnectionsDesc": "No Connections",
"nullConnectionsDesc": "No connections",
"intranetIp": "Intranet IP",
"view": "View",
"cut": "Cut",

View File

@@ -186,7 +186,7 @@ class MessageLookup extends MessageLookupByLibrary {
"notSelectedTip": MessageLookupByLibrary.simpleMessage(
"The current proxy group cannot be selected."),
"nullConnectionsDesc":
MessageLookupByLibrary.simpleMessage("No Connections"),
MessageLookupByLibrary.simpleMessage("No connections"),
"nullCoreInfoDesc":
MessageLookupByLibrary.simpleMessage("Unable to obtain core info"),
"nullLogsDesc": MessageLookupByLibrary.simpleMessage("No logs"),

View File

@@ -1930,10 +1930,10 @@ class AppLocalizations {
);
}
/// `No Connections`
/// `No connections`
String get nullConnectionsDesc {
return Intl.message(
'No Connections',
'No connections',
name: 'nullConnectionsDesc',
desc: '',
args: [],

View File

@@ -11,7 +11,7 @@ class NullStatus extends StatelessWidget {
return Center(
child: Text(
label,
style: Theme.of(context).textTheme.titleMedium?.toBold(),
style: Theme.of(context).textTheme.titleMedium?.toBold,
),
);
}

View File

@@ -1,7 +1,7 @@
name: fl_clash
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
publish_to: 'none'
version: 0.8.26
version: 0.8.27
environment:
sdk: '>=3.1.0 <4.0.0'