Skip to content

Commit

Permalink
Optimize proxies expansion panel
Browse files Browse the repository at this point in the history
Fix text error
  • Loading branch information
chen08209 committed Jun 27, 2024
1 parent 0389b6e commit 5e3b0e4
Show file tree
Hide file tree
Showing 17 changed files with 157 additions and 68 deletions.
3 changes: 1 addition & 2 deletions lib/application.dart
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class ApplicationState extends State<Application> {
builder: (lightDynamic, darkDynamic) {
_updateSystemColorSchemes(lightDynamic, darkDynamic);
return MaterialApp(
debugShowCheckedModeBanner: false,
navigatorKey: globalState.navigatorKey,
localizationsDelegates: const [
AppLocalizations.delegate,
Expand All @@ -164,7 +165,6 @@ class ApplicationState extends State<Application> {
themeMode: state.themeMode,
theme: ThemeData(
useMaterial3: true,
fontFamily: '',
pageTransitionsTheme: _pageTransitionsTheme,
colorScheme: _getAppColorScheme(
brightness: Brightness.light,
Expand All @@ -174,7 +174,6 @@ class ApplicationState extends State<Application> {
),
darkTheme: ThemeData(
useMaterial3: true,
fontFamily: '',
pageTransitionsTheme: _pageTransitionsTheme,
colorScheme: _getAppColorScheme(
brightness: Brightness.dark,
Expand Down
2 changes: 1 addition & 1 deletion lib/clash/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class ClashCore {
final proxiesRawString = proxiesRaw.cast<Utf8>().toDartString();
return Isolate.run<List<Group>>(() {
if(proxiesRawString.isEmpty) return [];
final proxies = json.decode(proxiesRawString) as Map;
final proxies = (json.decode(proxiesRawString) ?? {}) as Map;
if(proxies.isEmpty) return [];
final groupNames = [
UsedProxy.GLOBAL.name,
Expand Down
6 changes: 5 additions & 1 deletion lib/common/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ extension BuildContextExtension on BuildContext {
return findAncestorStateOfType<CommonScaffoldState>();
}

Size get appSize{
return MediaQuery.of(this).size;
}

double get width {
return MediaQuery.of(this).size.width;
return appSize.width;
}

ColorScheme get colorScheme => Theme.of(this).colorScheme;
Expand Down
2 changes: 1 addition & 1 deletion lib/fragments/connections.dart
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class ConnectionItem extends StatelessWidget {
}

String _getRequestText(Metadata metadata) {
var text = "${metadata.network}:://";
var text = "${metadata.network}://";
final ips = [
metadata.host,
metadata.destinationIP,
Expand Down
2 changes: 1 addition & 1 deletion lib/fragments/dashboard/dashboard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class _DashboardFragmentState extends State<DashboardFragment> {
),
GridItem(
crossAxisCellCount: isDesktop ? 4 : 6,
child: const IntranetIp(),
child: const IntranetIP(),
),
],
);
Expand Down
10 changes: 5 additions & 5 deletions lib/fragments/dashboard/intranet_ip.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import 'package:fl_clash/state.dart';
import 'package:fl_clash/widgets/widgets.dart';
import 'package:flutter/material.dart';

class IntranetIp extends StatefulWidget {
const IntranetIp({super.key});
class IntranetIP extends StatefulWidget {
const IntranetIP({super.key});

@override
State<IntranetIp> createState() => _IntranetIpState();
State<IntranetIP> createState() => _IntranetIPState();
}

class _IntranetIpState extends State<IntranetIp> {
class _IntranetIPState extends State<IntranetIP> {
final ipNotifier = ValueNotifier<String>("");

Future<String?> getLocalIpAddress() async {
Expand Down Expand Up @@ -45,7 +45,7 @@ class _IntranetIpState extends State<IntranetIp> {
Widget build(BuildContext context) {
return CommonCard(
info: Info(
label: appLocalizations.intranetIp,
label: appLocalizations.intranetIP,
iconData: Icons.devices,
),
onPressed: (){
Expand Down
3 changes: 2 additions & 1 deletion lib/fragments/profiles/add_profile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ class _URLFormDialogState extends State<URLFormDialog> {
runSpacing: 16,
children: [
TextField(
maxLines: null,
maxLines: 5,
minLines: 1,
controller: urlController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
Expand Down
3 changes: 2 additions & 1 deletion lib/fragments/profiles/edit_profile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ class _EditProfileState extends State<EditProfile> {
ListItem(
title: TextFormField(
controller: urlController,
maxLines: null,
maxLines: 5,
minLines: 1,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: appLocalizations.url,
Expand Down
2 changes: 1 addition & 1 deletion lib/fragments/profiles/profiles.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class _ProfilesFragmentState extends State<ProfilesFragment> {
_updateProfiles() async {
final updateProfiles = profileItemKeys.map<Future>(
(key) async => await key.currentState?.updateProfile(false));
final result = await Future.wait(updateProfiles);
await Future.wait(updateProfiles);
}

_initScaffoldState() {
Expand Down
141 changes: 120 additions & 21 deletions lib/fragments/proxies.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import 'dart:io';
import 'dart:math';

import 'package:collection/collection.dart';
import 'package:fl_clash/clash/core.dart';
import 'package:fl_clash/common/common.dart';
Expand Down Expand Up @@ -227,6 +230,17 @@ class ProxiesExpansionPanelFragment extends StatefulWidget {

class _ProxiesExpansionPanelFragmentState
extends State<ProxiesExpansionPanelFragment> {

@override
void initState() {
super.initState();
}

@override
void dispose() {
super.dispose();
}

@override
Widget build(BuildContext context) {
return Selector2<AppState, Config, ProxiesSelectorState>(
Expand All @@ -245,7 +259,6 @@ class _ProxiesExpansionPanelFragmentState
itemBuilder: (_, index) {
final groupName = state.groupNames[index];
return ProxyGroupView(
key: Key(groupName),
groupName: groupName,
type: ProxiesType.expansion,
);
Expand Down Expand Up @@ -277,6 +290,8 @@ class ProxyGroupView extends StatefulWidget {

class _ProxyGroupViewState extends State<ProxyGroupView> {
var isLock = false;
final isBoundaryNotifier = ValueNotifier<bool>(false);
var isEnd = false;

String get groupName => widget.groupName;

Expand Down Expand Up @@ -368,6 +383,32 @@ class _ProxyGroupViewState extends State<ProxyGroupView> {
);
}

Widget _androidExpansionHandle(Widget child) {
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification is ScrollEndNotification) {
if (notification.metrics.atEdge) {
isEnd = notification.metrics.pixels ==
notification.metrics.maxScrollExtent;
isBoundaryNotifier.value = true;
}
}
return false;
},
child: Listener(
onPointerMove: (details) {
double yOffset = details.delta.dy;
if (yOffset > 0 && isEnd) {
isBoundaryNotifier.value = false;
} else if (yOffset < 0 && !isEnd) {
isBoundaryNotifier.value = false;
}
},
child: child,
),
);
}

Widget _buildExpansionGroupView({
required List<Proxy> proxies,
required int columns,
Expand All @@ -376,6 +417,14 @@ class _ProxyGroupViewState extends State<ProxyGroupView> {
final sortedProxies = globalState.appController.getSortProxies(
proxies,
);
final group =
globalState.appController.appState.getGroupWithName(groupName)!;
final itemHeight = _getItemHeight(proxyCardType);
final innerHeight = context.appSize.height - 200;
final lines = (sortedProxies.length / columns).ceil();
final minLines = innerHeight >= 200 ? (innerHeight / itemHeight).floor() : 3;
final hasScrollable = lines > minLines;
final height = (itemHeight + 8) * min(lines, minLines) - 8;
return Selector<Config, Set<String>>(
selector: (_, config) => config.currentUnfoldSet,
builder: (_, currentUnfoldSet, __) {
Expand Down Expand Up @@ -417,7 +466,7 @@ class _ProxyGroupViewState extends State<ProxyGroupView> {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
groupName,
group.type.name,
style: context.textTheme.labelMedium?.toLight,
),
Flexible(
Expand Down Expand Up @@ -485,25 +534,69 @@ class _ProxyGroupViewState extends State<ProxyGroupView> {
right: 8,
),
children: [
Grid(
mainAxisSpacing: 8,
crossAxisSpacing: 8,
crossAxisCount: columns,
children: [
for (final proxy in sortedProxies)
_currentProxyNameBuilder(
builder: (value) {
return ProxyCard(
style: CommonCardType.filled,
type: proxyCardType,
isSelected: value == proxy.name,
key: ValueKey('$groupName.${proxy.name}'),
proxy: proxy,
groupName: groupName,
);
},
),
],
SizedBox(
height: height,
child: Platform.isAndroid
? _androidExpansionHandle(
ValueListenableBuilder(
valueListenable: isBoundaryNotifier,
builder: (_, isBoundary, child) {
return GridView.builder(
physics: isBoundary || !hasScrollable
? const NeverScrollableScrollPhysics()
: const AlwaysScrollableScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
mainAxisExtent: _getItemHeight(proxyCardType),
),
itemCount: sortedProxies.length,
itemBuilder: (_, index) {
final proxy = sortedProxies[index];
return _currentProxyNameBuilder(
builder: (value) {
return ProxyCard(
style: CommonCardType.filled,
type: proxyCardType,
isSelected: value == proxy.name,
key: ValueKey('$groupName.${proxy.name}'),
proxy: proxy,
groupName: groupName,
);
});
},
);
},
),
)
: GridView.builder(
physics: !hasScrollable
? const NeverScrollableScrollPhysics()
: const AlwaysScrollableScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
mainAxisExtent: _getItemHeight(proxyCardType),
),
itemCount: sortedProxies.length,
itemBuilder: (_, index) {
final proxy = sortedProxies[index];
return _currentProxyNameBuilder(builder: (value) {
return ProxyCard(
style: CommonCardType.filled,
type: proxyCardType,
isSelected: value == proxy.name,
key: ValueKey('$groupName.${proxy.name}'),
proxy: proxy,
groupName: groupName,
);
});
},
),
),
],
),
Expand All @@ -512,6 +605,12 @@ class _ProxyGroupViewState extends State<ProxyGroupView> {
);
}

@override
void dispose() {
super.dispose();
isBoundaryNotifier.dispose();
}

@override
Widget build(BuildContext context) {
return Selector2<AppState, Config, ProxyGroupSelectorState>(
Expand Down
2 changes: 1 addition & 1 deletion lib/fragments/requests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ class RequestItem extends StatelessWidget {
}

String _getRequestText(Metadata metadata) {
var text = "${metadata.network}:://";
var text = "${metadata.network}://";
final ips = [
metadata.host,
metadata.destinationIP,
Expand Down
7 changes: 3 additions & 4 deletions lib/l10n/arb/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@
"checking": "Checking...",
"country": "Country",
"checkError": "Check error",
"ipCheckTimeout": "Ip check timeout",
"search": "Search",
"allowBypass": "Allow applications to bypass VPN",
"allowBypassDesc": "Some apps can bypass VPN when turned on",
Expand All @@ -173,8 +172,8 @@
"systemProxyDesc": "Attach HTTP proxy to VpnService",
"unifiedDelay": "Unified delay",
"unifiedDelayDesc": "Remove extra delays such as handshaking",
"tcpConcurrent": "Tcp concurrent",
"tcpConcurrentDesc": "Enabling it will allow tcp concurrency",
"tcpConcurrent": "TCP concurrent",
"tcpConcurrentDesc": "Enabling it will allow TCP concurrency",
"geodataLoader": "Geo Low Memory Mode",
"geodataLoaderDesc": "Enabling will use the Geo low memory loader",
"requests": "Requests",
Expand All @@ -188,7 +187,7 @@
"connectionsDesc": "View current connection",
"nullRequestsDesc": "No requests",
"nullConnectionsDesc": "No connections",
"intranetIp": "Intranet IP",
"intranetIP": "Intranet IP",
"view": "View",
"cut": "Cut",
"copy": "Copy",
Expand Down
5 changes: 2 additions & 3 deletions lib/l10n/arb/intl_zh_CN.arb
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@
"checking": "检测中...",
"country": "区域",
"checkError": "检测失败",
"ipCheckTimeout": "Ip检测超时",
"search": "搜索",
"allowBypass": "允许应用绕过VPN",
"allowBypassDesc": "开启后部分应用可绕过VPN",
Expand All @@ -174,7 +173,7 @@
"unifiedDelay": "统一延迟",
"unifiedDelayDesc": "去除握手等额外延迟",
"tcpConcurrent": "TCP并发",
"tcpConcurrentDesc": "开启后允许tcp并发",
"tcpConcurrentDesc": "开启后允许TCP并发",
"geodataLoader": "Geo低内存模式",
"geodataLoaderDesc": "开启将使用Geo低内存加载器",
"requests": "请求",
Expand All @@ -188,7 +187,7 @@
"connectionsDesc": "查看当前连接",
"nullRequestsDesc": "暂无请求",
"nullConnectionsDesc": "暂无连接",
"intranetIp": "内网 IP",
"intranetIP": "内网 IP",
"view": "查看",
"cut": "剪切",
"copy": "复制",
Expand Down
Loading

0 comments on commit 5e3b0e4

Please sign in to comment.