mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
fix & opt
fix: cant ping when launch page is ping fix: button text color not primaryColor opt: getting primaryColor
This commit is contained in:
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -5,5 +5,8 @@
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/.fvm": true
|
||||
}
|
||||
},
|
||||
"git.ignoredRepositories": [
|
||||
".fvm"
|
||||
],
|
||||
}
|
||||
@@ -356,7 +356,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 205;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -364,7 +364,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.201;
|
||||
MARKETING_VERSION = 1.0.205;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -486,7 +486,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 205;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -494,7 +494,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.201;
|
||||
MARKETING_VERSION = 1.0.205;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -510,7 +510,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 201;
|
||||
CURRENT_PROJECT_VERSION = 205;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
@@ -518,7 +518,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.201;
|
||||
MARKETING_VERSION = 1.0.205;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
||||
92
lib/app.dart
92
lib/app.dart
@@ -1,13 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:toolbox/core/extension/colorx.dart';
|
||||
import 'package:toolbox/data/res/build_data.dart';
|
||||
import 'package:toolbox/data/store/setting.dart';
|
||||
import 'package:toolbox/generated/l10n.dart';
|
||||
import 'package:toolbox/locator.dart';
|
||||
import 'package:toolbox/view/page/home.dart';
|
||||
|
||||
import '/core/extension/colorx.dart';
|
||||
import 'core/utils/ui.dart';
|
||||
import 'data/res/build_data.dart';
|
||||
import 'data/res/color.dart';
|
||||
import 'data/store/setting.dart';
|
||||
import 'generated/l10n.dart';
|
||||
import 'locator.dart';
|
||||
import 'view/page/home.dart';
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
@@ -17,12 +18,31 @@ class MyApp extends StatelessWidget {
|
||||
setTransparentNavigationBar(context);
|
||||
return ValueListenableBuilder<int>(
|
||||
valueListenable: locator<SettingStore>().primaryColor.listenable(),
|
||||
builder: (_, value, __) {
|
||||
final primaryColor = Color(value);
|
||||
builder: (_, colorValue, __) {
|
||||
primaryColor = Color(colorValue);
|
||||
|
||||
final textStyle = TextStyle(color: primaryColor);
|
||||
final materialColor = primaryColor.materialStateColor;
|
||||
final materialColorAlpha =
|
||||
primaryColor.withOpacity(0.7).materialStateColor;
|
||||
final fabTheme =
|
||||
FloatingActionButtonThemeData(backgroundColor: primaryColor);
|
||||
final switchTheme = SwitchThemeData(
|
||||
thumbColor: materialColor,
|
||||
trackColor: materialColorAlpha,
|
||||
);
|
||||
final appBarTheme = AppBarTheme(backgroundColor: primaryColor);
|
||||
final iconTheme = IconThemeData(color: primaryColor);
|
||||
final inputDecorationTheme = InputDecorationTheme(
|
||||
labelStyle: textStyle,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: primaryColor),
|
||||
),
|
||||
);
|
||||
final radioTheme = RadioThemeData(
|
||||
fillColor: materialColor,
|
||||
);
|
||||
|
||||
return MaterialApp(
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
@@ -31,50 +51,30 @@ class MyApp extends StatelessWidget {
|
||||
supportedLocales: S.delegate.supportedLocales,
|
||||
title: BuildData.name,
|
||||
theme: ThemeData(
|
||||
useMaterial3: false,
|
||||
primaryColor: primaryColor,
|
||||
appBarTheme: AppBarTheme(backgroundColor: primaryColor),
|
||||
floatingActionButtonTheme:
|
||||
FloatingActionButtonThemeData(backgroundColor: primaryColor),
|
||||
iconTheme: IconThemeData(color: primaryColor),
|
||||
primaryIconTheme: IconThemeData(color: primaryColor),
|
||||
switchTheme: SwitchThemeData(
|
||||
thumbColor: materialColor,
|
||||
trackColor: materialColorAlpha,
|
||||
),
|
||||
buttonTheme: ButtonThemeData(splashColor: primaryColor),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
labelStyle: textStyle,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: primaryColor),
|
||||
),
|
||||
),
|
||||
radioTheme: RadioThemeData(
|
||||
fillColor: materialColor,
|
||||
),
|
||||
primarySwatch: primaryColor.materialColor,
|
||||
appBarTheme: appBarTheme,
|
||||
floatingActionButtonTheme: fabTheme,
|
||||
iconTheme: iconTheme,
|
||||
primaryIconTheme: iconTheme,
|
||||
switchTheme: switchTheme,
|
||||
inputDecorationTheme: inputDecorationTheme,
|
||||
radioTheme: radioTheme,
|
||||
),
|
||||
darkTheme: ThemeData.dark().copyWith(
|
||||
useMaterial3: false,
|
||||
primaryColor: primaryColor,
|
||||
floatingActionButtonTheme:
|
||||
FloatingActionButtonThemeData(backgroundColor: primaryColor),
|
||||
iconTheme: IconThemeData(color: primaryColor),
|
||||
primaryIconTheme: IconThemeData(color: primaryColor),
|
||||
switchTheme: SwitchThemeData(
|
||||
thumbColor: materialColor,
|
||||
trackColor: materialColorAlpha,
|
||||
),
|
||||
buttonTheme: ButtonThemeData(splashColor: primaryColor),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
labelStyle: textStyle,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: primaryColor),
|
||||
),
|
||||
),
|
||||
radioTheme: RadioThemeData(
|
||||
fillColor: materialColor,
|
||||
),
|
||||
floatingActionButtonTheme: fabTheme,
|
||||
iconTheme: iconTheme,
|
||||
primaryIconTheme: iconTheme,
|
||||
switchTheme: switchTheme,
|
||||
inputDecorationTheme: inputDecorationTheme,
|
||||
radioTheme: radioTheme,
|
||||
),
|
||||
home: MyHomePage(primaryColor: primaryColor),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,17 @@ extension ColorX on Color {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
MaterialColor get materialColor => MaterialColor(value, {
|
||||
50: withOpacity(0.05),
|
||||
100: withOpacity(0.1),
|
||||
200: withOpacity(0.2),
|
||||
300: withOpacity(0.3),
|
||||
400: withOpacity(0.4),
|
||||
500: withOpacity(0.5),
|
||||
600: withOpacity(0.6),
|
||||
700: withOpacity(0.7),
|
||||
800: withOpacity(0.8),
|
||||
900: withOpacity(0.9),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,10 +56,17 @@ Future<void> doUpdate(BuildContext context, {bool force = false}) async {
|
||||
final s = S.of(context);
|
||||
|
||||
if (update.min > BuildData.build) {
|
||||
showRoundDialog(context, s.attention, Text(s.updateTipTooLow(newest)), [
|
||||
showRoundDialog(
|
||||
context,
|
||||
s.attention,
|
||||
Text(s.updateTipTooLow(newest)),
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => _doUpdate(update, context, s), child: Text(s.ok))
|
||||
]);
|
||||
onPressed: () => _doUpdate(update, context, s),
|
||||
child: Text(s.ok),
|
||||
)
|
||||
],
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -73,14 +80,19 @@ Future<void> doUpdate(BuildContext context, {bool force = false}) async {
|
||||
|
||||
Future<void> _doUpdate(AppUpdate update, BuildContext context, S s) async {
|
||||
if (Platform.isAndroid) {
|
||||
await RUpgrade.upgrade(update.android,
|
||||
fileName: update.android.split('/').last, isAutoRequestInstall: true);
|
||||
await RUpgrade.upgrade(
|
||||
update.android,
|
||||
fileName: update.android.split('/').last,
|
||||
isAutoRequestInstall: true,
|
||||
);
|
||||
} else if (Platform.isIOS) {
|
||||
await RUpgrade.upgradeFromAppStore('1586449703');
|
||||
} else {
|
||||
showRoundDialog(context, s.attention, Text(s.platformNotSupportUpdate), [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(), child: Text(s.ok))
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(s.ok),
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
15
lib/data/model/app/dynamic_color.dart
Normal file
15
lib/data/model/app/dynamic_color.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../../../core/utils/ui.dart';
|
||||
|
||||
class DynamicColor {
|
||||
/// 白天模式显示的颜色
|
||||
Color light;
|
||||
|
||||
/// 暗黑模式显示的颜色
|
||||
Color dark;
|
||||
|
||||
DynamicColor(this.light, this.dark);
|
||||
|
||||
Color resolve(BuildContext context) => isDarkMode(context) ? dark : light;
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
class BuildData {
|
||||
static const String name = "ServerBox";
|
||||
static const int build = 203;
|
||||
static const int build = 205;
|
||||
static const String engine =
|
||||
"Flutter 3.7.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision b06b8b2710 (8 days ago) • 2023-01-23 16:55:55 -0800\nEngine • revision b24591ed32\nTools • Dart 2.19.0 • DevTools 2.20.1\n";
|
||||
static const String buildAt = "2023-02-01 12:58:12.944187";
|
||||
static const int modifications = 13;
|
||||
static const String buildAt = "2023-02-01 14:57:28.662965";
|
||||
static const int modifications = 5;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:toolbox/data/store/setting.dart';
|
||||
import 'package:toolbox/locator.dart';
|
||||
|
||||
import '../../core/utils/ui.dart';
|
||||
import '../model/app/dynamic_color.dart';
|
||||
|
||||
class DynamicColor {
|
||||
/// 白天模式显示的颜色
|
||||
Color light;
|
||||
Color primaryColor = Color(locator<SettingStore>().primaryColor.fetch()!);
|
||||
|
||||
/// 暗黑模式显示的颜色
|
||||
Color dark;
|
||||
|
||||
DynamicColor(this.light, this.dark);
|
||||
|
||||
resolve(BuildContext context) => isDarkMode(context) ? dark : light;
|
||||
}
|
||||
|
||||
final mainColor = DynamicColor(Colors.black87, Colors.white70);
|
||||
final contentColor = DynamicColor(Colors.black87, Colors.white70);
|
||||
final bgColor = DynamicColor(Colors.white, Colors.black);
|
||||
final progressColor = DynamicColor(Colors.grey.shade100, Colors.white10);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:toolbox/data/provider/app.dart';
|
||||
import 'package:toolbox/data/provider/pkg.dart';
|
||||
import 'package:toolbox/data/provider/debug.dart';
|
||||
import 'package:toolbox/data/provider/docker.dart';
|
||||
import 'package:toolbox/data/provider/private_key.dart';
|
||||
import 'package:toolbox/data/provider/server.dart';
|
||||
import 'package:toolbox/data/provider/sftp_download.dart';
|
||||
import 'package:toolbox/data/provider/snippet.dart';
|
||||
import 'package:toolbox/data/service/app.dart';
|
||||
import 'package:toolbox/data/store/docker.dart';
|
||||
import 'package:toolbox/data/store/private_key.dart';
|
||||
import 'package:toolbox/data/store/server.dart';
|
||||
import 'package:toolbox/data/store/setting.dart';
|
||||
import 'package:toolbox/data/store/snippet.dart';
|
||||
|
||||
import 'data/provider/app.dart';
|
||||
import 'data/provider/debug.dart';
|
||||
import 'data/provider/docker.dart';
|
||||
import 'data/provider/pkg.dart';
|
||||
import 'data/provider/private_key.dart';
|
||||
import 'data/provider/server.dart';
|
||||
import 'data/provider/sftp_download.dart';
|
||||
import 'data/provider/snippet.dart';
|
||||
import 'data/provider/virtual_keyboard.dart';
|
||||
import 'data/service/app.dart';
|
||||
import 'data/store/docker.dart';
|
||||
import 'data/store/private_key.dart';
|
||||
import 'data/store/server.dart';
|
||||
import 'data/store/setting.dart';
|
||||
import 'data/store/snippet.dart';
|
||||
|
||||
GetIt locator = GetIt.instance;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:toolbox/data/res/color.dart';
|
||||
|
||||
import '../../core/extension/colorx.dart';
|
||||
import '../../core/utils/ui.dart';
|
||||
@@ -15,7 +16,6 @@ import '../../data/store/setting.dart';
|
||||
import '../../data/store/snippet.dart';
|
||||
import '../../generated/l10n.dart';
|
||||
import '../../locator.dart';
|
||||
import '../widget/primary_color.dart';
|
||||
|
||||
const backupFormatVersion = 1;
|
||||
|
||||
@@ -68,14 +68,12 @@ class BackupPage extends StatelessWidget {
|
||||
|
||||
Widget _buildCard(String text, IconData icon, MediaQueryData media,
|
||||
FutureOr Function() onTap) {
|
||||
return PrimaryColor(
|
||||
builder: ((context, pColor) {
|
||||
final textColor = pColor.isBrightColor ? Colors.black : Colors.white;
|
||||
final textColor = primaryColor.isBrightColor ? Colors.black : Colors.white;
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(37), color: pColor),
|
||||
borderRadius: BorderRadius.circular(37), color: primaryColor),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
|
||||
child: Row(
|
||||
@@ -93,8 +91,6 @@ class BackupPage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showExportDialog(BuildContext context, S s) async {
|
||||
|
||||
@@ -4,9 +4,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../../core/utils/ui.dart';
|
||||
import '../../data/res/color.dart';
|
||||
import '../../generated/l10n.dart';
|
||||
import '../widget/input_field.dart';
|
||||
import '../widget/primary_color.dart';
|
||||
import '../widget/round_rect_card.dart';
|
||||
|
||||
class ConvertPage extends StatefulWidget {
|
||||
@@ -105,7 +105,6 @@ class _ConvertPageState extends State<ConvertPage>
|
||||
'URL $encode',
|
||||
'URL $decode'
|
||||
];
|
||||
return PrimaryColor(builder: (context, primaryColor) {
|
||||
return RoundRectCard(
|
||||
ExpansionTile(
|
||||
tilePadding: const EdgeInsets.only(left: 7, right: 27),
|
||||
@@ -113,26 +112,21 @@ class _ConvertPageState extends State<ConvertPage>
|
||||
title: Row(
|
||||
children: [
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
foregroundColor: MaterialStateProperty.all(primaryColor)),
|
||||
child: Icon(Icons.change_circle, semanticLabel: _s.upsideDown),
|
||||
onPressed: () {
|
||||
final temp = _textEditingController.text;
|
||||
_textEditingController.text =
|
||||
_textEditingControllerResult.text;
|
||||
_textEditingController.text = _textEditingControllerResult.text;
|
||||
_textEditingControllerResult.text = temp;
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
foregroundColor: MaterialStateProperty.all(primaryColor),
|
||||
),
|
||||
child: Icon(Icons.copy, semanticLabel: _s.copy),
|
||||
onPressed: () => Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: _textEditingControllerResult.text == ''
|
||||
? ' '
|
||||
: _textEditingControllerResult.text),
|
||||
: _textEditingControllerResult.text,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
@@ -150,7 +144,8 @@ class _ConvertPageState extends State<ConvertPage>
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: primaryColor),
|
||||
color: primaryColor,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_s.currentMode,
|
||||
@@ -176,7 +171,6 @@ class _ConvertPageState extends State<ConvertPage>
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildResult() {
|
||||
|
||||
@@ -190,7 +190,9 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
||||
if (_textController.text == '') {
|
||||
showRoundDialog(context, _s.attention, Text(_s.fieldMustNotEmpty), [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(), child: Text(_s.ok)),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(_s.ok),
|
||||
),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import '../../core/analysis.dart';
|
||||
import '../../core/route.dart';
|
||||
import '../../core/update.dart';
|
||||
import '../../core/utils/ui.dart';
|
||||
import '../../data/model/app/dynamic_color.dart';
|
||||
import '../../data/model/app/navigation_item.dart';
|
||||
import '../../data/provider/server.dart';
|
||||
import '../../data/res/build_data.dart';
|
||||
@@ -28,6 +29,9 @@ import 'setting.dart';
|
||||
import 'sftp/downloaded.dart';
|
||||
import 'snippet/list.dart';
|
||||
|
||||
final _bottomItemOverlayColor =
|
||||
DynamicColor(Colors.black.withOpacity(0.07), Colors.white12);
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({Key? key, required this.primaryColor}) : super(key: key);
|
||||
final Color primaryColor;
|
||||
@@ -112,7 +116,7 @@ class _MyHomePageState extends State<MyHomePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItem(int idx, NavigationItem item, bool isSelected) {
|
||||
Widget _buildBottomItem(int idx, NavigationItem item, bool isSelected) {
|
||||
final width = _width / tabItems.length;
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 377),
|
||||
@@ -121,9 +125,7 @@ class _MyHomePageState extends State<MyHomePage>
|
||||
width: isSelected ? width : width - 17,
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? isDarkMode(context)
|
||||
? Colors.white12
|
||||
: Colors.black.withOpacity(0.07)
|
||||
? _bottomItemOverlayColor.resolve(context)
|
||||
: Colors.transparent,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(50),
|
||||
@@ -156,7 +158,8 @@ class _MyHomePageState extends State<MyHomePage>
|
||||
children: tabItems.map(
|
||||
(item) {
|
||||
int itemIndex = tabItems.indexOf(item);
|
||||
return _buildItem(itemIndex, item, _selectIndex == itemIndex);
|
||||
return _buildBottomItem(
|
||||
itemIndex, item, _selectIndex == itemIndex,);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
@@ -179,7 +182,6 @@ class _MyHomePageState extends State<MyHomePage>
|
||||
),
|
||||
child: Text(
|
||||
'${BuildData.name}\n$_versionStr',
|
||||
style: TextStyle(color: widget.primaryColor),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
@@ -225,11 +227,6 @@ class _MyHomePageState extends State<MyHomePage>
|
||||
_s.feedback,
|
||||
Text(_s.feedbackOnGithub),
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Clipboard.setData(
|
||||
const ClipboardData(text: issueUrl)),
|
||||
child: Text(_s.copy),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => openUrl(issueUrl),
|
||||
child: Text(_s.feedback),
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:after_layout/after_layout.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../core/extension/uint8list.dart';
|
||||
import '../../core/utils/ui.dart';
|
||||
import '../../data/model/server/ping_result.dart';
|
||||
import '../../data/provider/server.dart';
|
||||
import '../../data/res/color.dart';
|
||||
import '../../data/res/font_style.dart';
|
||||
import '../../generated/l10n.dart';
|
||||
import '../../locator.dart';
|
||||
import '../widget/input_field.dart';
|
||||
import '../widget/primary_color.dart';
|
||||
import '../widget/round_rect_card.dart';
|
||||
|
||||
final doaminReg =
|
||||
@@ -25,7 +28,7 @@ class PingPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _PingPageState extends State<PingPage>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
with AutomaticKeepAliveClientMixin, AfterLayoutMixin {
|
||||
late TextEditingController _textEditingController;
|
||||
late MediaQueryData _media;
|
||||
final List<PingResult> _results = [];
|
||||
@@ -54,10 +57,13 @@ class _PingPageState extends State<PingPage>
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 13),
|
||||
buildInput(context, _textEditingController,
|
||||
buildInput(
|
||||
context,
|
||||
_textEditingController,
|
||||
hint: s.inputDomainHere,
|
||||
maxLines: 1,
|
||||
onSubmitted: (_) => doPing()),
|
||||
onSubmitted: (_) => doPing(),
|
||||
),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: _media.size.height * 0.6,
|
||||
@@ -67,7 +73,8 @@ class _PingPageState extends State<PingPage>
|
||||
itemBuilder: (context, index) {
|
||||
final result = _results[index];
|
||||
return _buildResultItem(result);
|
||||
}),
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -89,12 +96,9 @@ class _PingPageState extends State<PingPage>
|
||||
Widget _buildResultItem(PingResult result) {
|
||||
final unknown = s.unknown;
|
||||
final ms = s.ms;
|
||||
return PrimaryColor(
|
||||
builder: ((context, primaryColor) {
|
||||
return RoundRectCard(
|
||||
ListTile(
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
|
||||
title: Text(
|
||||
result.serverName,
|
||||
style: TextStyle(
|
||||
@@ -116,8 +120,6 @@ class _PingPageState extends State<PingPage>
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
String _buildPingSummary(PingResult result, String unknown, String ms) {
|
||||
@@ -169,4 +171,10 @@ class _PingPageState extends State<PingPage>
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
@override
|
||||
Future<FutureOr<void>> afterFirstLayout(BuildContext context) async {
|
||||
await _serverProvider.loadLocalData();
|
||||
await _serverProvider.refreshData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,9 @@ class _PkgManagePageState extends State<PkgManagePage>
|
||||
Text(_s.fieldMustNotEmpty),
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(), child: Text(_s.ok)),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(_s.ok),
|
||||
),
|
||||
],
|
||||
);
|
||||
return;
|
||||
@@ -112,7 +114,8 @@ class _PkgManagePageState extends State<PkgManagePage>
|
||||
child: Text(
|
||||
_s.ok,
|
||||
style: const TextStyle(color: Colors.red),
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
return _textController.text.trim();
|
||||
@@ -206,7 +209,8 @@ class _PkgManagePageState extends State<PkgManagePage>
|
||||
child: Text(_s.updateAll),
|
||||
onPressed: () {
|
||||
apt.upgrade();
|
||||
}),
|
||||
},
|
||||
),
|
||||
...apt.upgradeable!.map((e) => _buildUpdateItem(e, apt)).toList()
|
||||
]
|
||||
: [
|
||||
|
||||
@@ -48,8 +48,8 @@ class _PrivateKeyListState extends State<PrivateKeysListPage> {
|
||||
trailing: TextButton(
|
||||
onPressed: () => AppRoute(
|
||||
PrivateKeyEditPage(info: key.infos[idx]),
|
||||
'private key edit page')
|
||||
.go(context),
|
||||
'private key edit page',
|
||||
).go(context),
|
||||
child: Text(_s.edit),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -14,7 +14,6 @@ import '../../../data/res/sizedbox.dart';
|
||||
import '../../../data/store/setting.dart';
|
||||
import '../../../generated/l10n.dart';
|
||||
import '../../../locator.dart';
|
||||
import '../../widget/primary_color.dart';
|
||||
import '../../widget/round_rect_card.dart';
|
||||
|
||||
class ServerDetailPage extends StatefulWidget {
|
||||
@@ -174,14 +173,12 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
||||
Widget _buildProgress(double percent) {
|
||||
if (percent > 100) percent = 100;
|
||||
final percentWithinOne = percent / 100;
|
||||
return PrimaryColor(builder: (context, primaryColor) {
|
||||
return LinearProgressIndicator(
|
||||
value: percentWithinOne,
|
||||
minHeight: 7,
|
||||
backgroundColor: progressColor.resolve(context),
|
||||
color: primaryColor,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildUpTimeAndSys(ServerStatus ss) {
|
||||
|
||||
@@ -8,12 +8,12 @@ import '../../../data/model/server/private_key_info.dart';
|
||||
import '../../../data/model/server/server_private_info.dart';
|
||||
import '../../../data/provider/private_key.dart';
|
||||
import '../../../data/provider/server.dart';
|
||||
import '../../../data/res/color.dart';
|
||||
import '../../../data/res/font_style.dart';
|
||||
import '../../../data/store/private_key.dart';
|
||||
import '../../../generated/l10n.dart';
|
||||
import '../../../locator.dart';
|
||||
import '../../widget/input_decoration.dart';
|
||||
import '../../widget/primary_color.dart';
|
||||
import '../private_key/edit.dart';
|
||||
|
||||
class ServerEditPage extends StatefulWidget {
|
||||
@@ -200,7 +200,6 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
||||
),
|
||||
),
|
||||
);
|
||||
return PrimaryColor(builder: ((context, primaryColor) {
|
||||
return ExpansionTile(
|
||||
textColor: primaryColor,
|
||||
iconColor: primaryColor,
|
||||
@@ -212,7 +211,6 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
||||
),
|
||||
children: tiles,
|
||||
);
|
||||
}));
|
||||
},
|
||||
)
|
||||
: const SizedBox()
|
||||
@@ -234,10 +232,12 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: Text(_s.ok)),
|
||||
child: Text(_s.ok),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: Text(_s.cancel))
|
||||
child: Text(_s.cancel),
|
||||
)
|
||||
],
|
||||
barrierDismiss: false,
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import '../../../data/model/server/server_private_info.dart';
|
||||
import '../../../data/model/server/server_status.dart';
|
||||
import '../../../data/provider/server.dart';
|
||||
import '../../../data/provider/snippet.dart';
|
||||
import '../../../data/res/color.dart';
|
||||
import '../../../data/res/font_style.dart';
|
||||
import '../../../data/res/menu.dart';
|
||||
import '../../../data/res/url.dart';
|
||||
@@ -19,7 +20,6 @@ import '../../../generated/l10n.dart';
|
||||
import '../../../locator.dart';
|
||||
import '../../widget/dropdown_menu.dart';
|
||||
import '../../widget/picker.dart';
|
||||
import '../../widget/primary_color.dart';
|
||||
import '../../widget/round_rect_card.dart';
|
||||
import '../../widget/url_text.dart';
|
||||
import '../docker.dart';
|
||||
@@ -162,7 +162,11 @@ class _ServerPageState extends State<ServerPage>
|
||||
? GestureDetector(
|
||||
onTap: () => showRoundDialog(
|
||||
context, _s.error, Text(ss.failedInfo ?? ''), []),
|
||||
child: Text(_s.clickSee, style: style, textScaleFactor: 1.0,))
|
||||
child: Text(
|
||||
_s.clickSee,
|
||||
style: style,
|
||||
textScaleFactor: 1.0,
|
||||
))
|
||||
: Text(topRightStr, style: style, textScaleFactor: 1.0),
|
||||
const SizedBox(width: 9),
|
||||
_buildSSHBtn(spi),
|
||||
@@ -352,16 +356,12 @@ class _ServerPageState extends State<ServerPage>
|
||||
child: Stack(
|
||||
children: [
|
||||
Center(
|
||||
child: PrimaryColor(
|
||||
builder: (context, primaryColor) {
|
||||
return CircleChart(
|
||||
child: CircleChart(
|
||||
progressColor: primaryColor,
|
||||
progressNumber: percent,
|
||||
maxNumber: 100,
|
||||
width: 53,
|
||||
height: 53,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
@@ -415,8 +415,7 @@ class _ServerPageState extends State<ServerPage>
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
final result =
|
||||
await locator<ServerProvider>().runSnippet(id, snippet);
|
||||
final result = await _serverProvider.runSnippet(id, snippet);
|
||||
showRoundDialog(
|
||||
context,
|
||||
_s.result,
|
||||
|
||||
@@ -7,12 +7,12 @@ import '../../core/utils/ui.dart';
|
||||
import '../../data/provider/app.dart';
|
||||
import '../../data/provider/server.dart';
|
||||
import '../../data/res/build_data.dart';
|
||||
import '../../data/res/color.dart';
|
||||
import '../../data/res/font_style.dart';
|
||||
import '../../data/res/tab.dart';
|
||||
import '../../data/store/setting.dart';
|
||||
import '../../generated/l10n.dart';
|
||||
import '../../locator.dart';
|
||||
import '../widget/primary_color.dart';
|
||||
import '../widget/round_rect_card.dart';
|
||||
|
||||
class SettingPage extends StatefulWidget {
|
||||
@@ -56,19 +56,15 @@ class _SettingPageState extends State<SettingPage> {
|
||||
appBar: AppBar(
|
||||
title: Text(_s.setting),
|
||||
),
|
||||
body: PrimaryColor(
|
||||
builder: (context, primaryColor) {
|
||||
return ListView(
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.all(17),
|
||||
children: [
|
||||
_buildAppColorPreview(primaryColor),
|
||||
_buildUpdateInterval(primaryColor),
|
||||
_buildAppColorPreview(),
|
||||
_buildUpdateInterval(),
|
||||
_buildCheckUpdate(),
|
||||
_buildLaunchPage(primaryColor),
|
||||
_buildLaunchPage(),
|
||||
_buildDistLogoSwitch(),
|
||||
].map((e) => RoundRectCard(e)).toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -113,9 +109,9 @@ class _SettingPageState extends State<SettingPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUpdateInterval(Color priColor) {
|
||||
Widget _buildUpdateInterval() {
|
||||
return ExpansionTile(
|
||||
textColor: priColor,
|
||||
textColor: primaryColor,
|
||||
title: Text(
|
||||
_s.updateServerStatusInterval,
|
||||
style: textSize13,
|
||||
@@ -128,8 +124,8 @@ class _SettingPageState extends State<SettingPage> {
|
||||
trailing: Text('${_updateInterval.toInt()} ${_s.second}'),
|
||||
children: [
|
||||
Slider(
|
||||
thumbColor: priColor,
|
||||
activeColor: priColor.withOpacity(0.7),
|
||||
thumbColor: primaryColor,
|
||||
activeColor: primaryColor.withOpacity(0.7),
|
||||
min: 0,
|
||||
max: 10,
|
||||
value: _updateInterval,
|
||||
@@ -162,12 +158,12 @@ class _SettingPageState extends State<SettingPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAppColorPreview(Color priColor) {
|
||||
Widget _buildAppColorPreview() {
|
||||
return ExpansionTile(
|
||||
textColor: priColor,
|
||||
textColor: primaryColor,
|
||||
trailing: ClipOval(
|
||||
child: Container(
|
||||
color: priColor,
|
||||
color: primaryColor,
|
||||
height: 27,
|
||||
width: 27,
|
||||
),
|
||||
@@ -176,17 +172,18 @@ class _SettingPageState extends State<SettingPage> {
|
||||
_s.appPrimaryColor,
|
||||
style: textSize13,
|
||||
),
|
||||
children: [_buildAppColorPicker(priColor), _buildColorPickerConfirmBtn()],
|
||||
children: [_buildAppColorPicker(), _buildColorPickerConfirmBtn()],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAppColorPicker(Color selected) {
|
||||
Widget _buildAppColorPicker() {
|
||||
return MaterialColorPicker(
|
||||
shrinkWrap: true,
|
||||
onColorChange: (Color color) {
|
||||
_selectedColorValue = color.value;
|
||||
},
|
||||
selectedColor: selected);
|
||||
selectedColor: primaryColor,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildColorPickerConfirmBtn() {
|
||||
@@ -199,9 +196,10 @@ class _SettingPageState extends State<SettingPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLaunchPage(Color priColor) {
|
||||
Widget _buildLaunchPage() {
|
||||
return ExpansionTile(
|
||||
textColor: priColor,
|
||||
childrenPadding: const EdgeInsets.only(left: 17, right: 7),
|
||||
textColor: primaryColor,
|
||||
title: Text(
|
||||
_s.launchPage,
|
||||
style: textSize13,
|
||||
@@ -222,7 +220,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
tabTitleName(context, tabs.indexOf(e)),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: _theme.textTheme.bodyMedium!.color!.withAlpha(177)),
|
||||
color: _theme.textTheme.bodyMedium!.color!.withAlpha(177),),
|
||||
),
|
||||
trailing: _buildRadio(tabs.indexOf(e)),
|
||||
),
|
||||
|
||||
@@ -152,7 +152,8 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(_s.cancel)),
|
||||
child: Text(_s.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
file.deleteSync();
|
||||
@@ -177,7 +178,8 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: (() => Navigator.of(context).pop()),
|
||||
child: Text(_s.close))
|
||||
child: Text(_s.close),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -114,7 +114,8 @@ class _SFTPPageState extends State<SFTPPage> {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(_s.close))
|
||||
child: Text(_s.close),
|
||||
)
|
||||
],
|
||||
)),
|
||||
icon: const Icon(Icons.add),
|
||||
@@ -141,7 +142,8 @@ class _SFTPPageState extends State<SFTPPage> {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(_s.cancel))
|
||||
child: Text(_s.cancel),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
@@ -278,7 +280,8 @@ class _SFTPPageState extends State<SFTPPage> {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(_s.cancel))
|
||||
child: Text(_s.cancel),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -291,7 +294,8 @@ class _SFTPPageState extends State<SFTPPage> {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(_s.cancel)),
|
||||
child: Text(_s.cancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
@@ -329,7 +333,8 @@ class _SFTPPageState extends State<SFTPPage> {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Cancel')),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_status.client!.remove(file.filename);
|
||||
@@ -372,7 +377,8 @@ class _SFTPPageState extends State<SFTPPage> {
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text(_s.ok)),
|
||||
child: Text(_s.ok),
|
||||
),
|
||||
],
|
||||
);
|
||||
return;
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:toolbox/data/res/color.dart';
|
||||
import 'package:xterm/xterm.dart';
|
||||
|
||||
import '../../core/utils/ui.dart';
|
||||
@@ -15,7 +16,6 @@ import '../../data/provider/virtual_keyboard.dart';
|
||||
import '../../data/res/terminal_theme.dart';
|
||||
import '../../data/res/virtual_key.dart';
|
||||
import '../../locator.dart';
|
||||
import '../widget/primary_color.dart';
|
||||
|
||||
class SSHPage extends StatefulWidget {
|
||||
final ServerPrivateInfo spi;
|
||||
@@ -156,15 +156,13 @@ class _SSHPageState extends State<SSHPage> {
|
||||
color: isDark ? Colors.white : Colors.black,
|
||||
size: 17,
|
||||
)
|
||||
: PrimaryColor(builder: (context, color) {
|
||||
return Text(
|
||||
: Text(
|
||||
item.text,
|
||||
style: TextStyle(
|
||||
color: selected ? color : Colors.black,
|
||||
color: selected ? primaryColor : null,
|
||||
fontSize: 17,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../data/res/color.dart';
|
||||
import '../../data/res/menu.dart';
|
||||
import '../../generated/l10n.dart';
|
||||
import 'primary_color.dart';
|
||||
|
||||
class DropdownBtnItem {
|
||||
final String text;
|
||||
@@ -15,12 +15,10 @@ class DropdownBtnItem {
|
||||
|
||||
Widget build(S s) => Row(
|
||||
children: [
|
||||
PrimaryColor(builder: (context, primaryColor) {
|
||||
return Icon(
|
||||
Icon(
|
||||
icon,
|
||||
color: primaryColor,
|
||||
);
|
||||
}),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'primary_color.dart';
|
||||
import '../../data/res/color.dart';
|
||||
|
||||
InputDecoration buildDecoration(String label,
|
||||
{TextStyle? textStyle, IconData? icon, String? hint}) {
|
||||
@@ -8,11 +8,9 @@ InputDecoration buildDecoration(String label,
|
||||
labelText: label,
|
||||
labelStyle: textStyle,
|
||||
hintText: hint,
|
||||
icon: PrimaryColor(builder: (context, primaryColor) {
|
||||
return Icon(
|
||||
icon: Icon(
|
||||
icon,
|
||||
color: primaryColor,
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../data/store/setting.dart';
|
||||
import '../../locator.dart';
|
||||
|
||||
final _primaryColor = locator<SettingStore>().primaryColor.listenable();
|
||||
|
||||
class PrimaryColor extends StatelessWidget {
|
||||
final Widget Function(BuildContext context, Color primaryColor) builder;
|
||||
|
||||
const PrimaryColor({Key? key, required this.builder}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ValueListenableBuilder<int>(
|
||||
builder: (context, c, child) => builder(context, Color(c)),
|
||||
valueListenable: _primaryColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:toolbox/data/res/color.dart';
|
||||
|
||||
import '../../core/utils/ui.dart';
|
||||
|
||||
const regUrl =
|
||||
r"(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]*";
|
||||
final _reg = RegExp(
|
||||
r"(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]*");
|
||||
|
||||
const _textStyle = TextStyle();
|
||||
|
||||
class UrlText extends StatelessWidget {
|
||||
final String text;
|
||||
@@ -12,18 +15,17 @@ class UrlText extends StatelessWidget {
|
||||
final TextAlign? textAlign;
|
||||
final TextStyle style;
|
||||
|
||||
const UrlText(
|
||||
{Key? key,
|
||||
const UrlText({
|
||||
Key? key,
|
||||
required this.text,
|
||||
this.replace,
|
||||
this.textAlign,
|
||||
this.style = const TextStyle()})
|
||||
: super(key: key);
|
||||
this.style = _textStyle,
|
||||
}) : super(key: key);
|
||||
|
||||
List<InlineSpan> _getTextSpans(bool isDarkMode) {
|
||||
List<InlineSpan> _getTextSpans(Color c) {
|
||||
List<InlineSpan> widgets = <InlineSpan>[];
|
||||
final reg = RegExp(regUrl);
|
||||
Iterable<Match> matches = reg.allMatches(text);
|
||||
Iterable<Match> matches = _reg.allMatches(text);
|
||||
List<_ResultMatch> resultMatches = <_ResultMatch>[];
|
||||
int start = 0;
|
||||
|
||||
@@ -54,16 +56,22 @@ class UrlText extends StatelessWidget {
|
||||
|
||||
for (var result in resultMatches) {
|
||||
if (result.isUrl) {
|
||||
widgets.add(_LinkTextSpan(
|
||||
widgets.add(
|
||||
_LinkTextSpan(
|
||||
replace: replace ?? result.text,
|
||||
text: result.text,
|
||||
style: style.copyWith(color: Colors.blue)));
|
||||
style: style.copyWith(color: primaryColor),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
widgets.add(TextSpan(
|
||||
widgets.add(
|
||||
TextSpan(
|
||||
text: result.text,
|
||||
style: style.copyWith(
|
||||
color: isDarkMode ? Colors.white : Colors.black,
|
||||
)));
|
||||
color: c,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return widgets;
|
||||
@@ -73,7 +81,7 @@ class UrlText extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return RichText(
|
||||
textAlign: textAlign ?? TextAlign.start,
|
||||
text: TextSpan(children: _getTextSpans(isDarkMode(context))),
|
||||
text: TextSpan(children: _getTextSpans(contentColor.resolve(context))),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -86,7 +94,8 @@ class _LinkTextSpan extends TextSpan {
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
openUrl(text);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class _ResultMatch {
|
||||
|
||||
Reference in New Issue
Block a user