mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-11-23 19:49:05 +08:00
remove menu from desktop home page
This commit is contained in:
parent
0df6517adb
commit
e0d759c3bb
@ -1,29 +1,6 @@
|
||||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at
|
||||
# https://dart-lang.github.io/linter/lints/index.html.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
non_constant_identifier_names: false
|
||||
sort_child_properties_last: false
|
||||
|
@ -1,3 +1,5 @@
|
||||
// main window right pane
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
|
@ -5,29 +5,14 @@ import 'package:flutter/material.dart' hide MenuItem;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hbb/common.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/connection_page.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart'
|
||||
as mod_menu;
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:flutter_hbb/models/server_model.dart';
|
||||
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:tray_manager/tray_manager.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../../common/widgets/dialog.dart';
|
||||
|
||||
class _MenubarTheme {
|
||||
static const Color commonColor = MyTheme.accent;
|
||||
// kMinInteractiveDimension
|
||||
static const double height = 25.0;
|
||||
static const double dividerHeight = 12.0;
|
||||
}
|
||||
|
||||
class DesktopHomePage extends StatefulWidget {
|
||||
const DesktopHomePage({Key? key}) : super(key: key);
|
||||
|
||||
@ -66,19 +51,19 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
super.build(context);
|
||||
return Row(
|
||||
children: [
|
||||
buildServerInfo(context),
|
||||
buildLeftPane(context),
|
||||
const VerticalDivider(
|
||||
width: 1,
|
||||
thickness: 1,
|
||||
),
|
||||
Expanded(
|
||||
child: buildServerBoard(context),
|
||||
child: buildRightPane(context),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
buildServerInfo(BuildContext context) {
|
||||
buildLeftPane(BuildContext context) {
|
||||
return ChangeNotifierProvider.value(
|
||||
value: gFFI.serverModel,
|
||||
child: Container(
|
||||
@ -95,7 +80,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
);
|
||||
}
|
||||
|
||||
buildServerBoard(BuildContext context) {
|
||||
buildRightPane(BuildContext context) {
|
||||
return Container(
|
||||
color: MyTheme.color(context).grayBg,
|
||||
child: ConnectionPage(),
|
||||
@ -167,93 +152,9 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
}
|
||||
|
||||
Widget buildPopupMenu(BuildContext context) {
|
||||
var position;
|
||||
RxBool hover = false.obs;
|
||||
return InkWell(
|
||||
onTapDown: (detail) {
|
||||
final x = detail.globalPosition.dx;
|
||||
final y = detail.globalPosition.dy;
|
||||
position = RelativeRect.fromLTRB(x, y, x, y);
|
||||
},
|
||||
onTap: () async {
|
||||
final userName = await gFFI.userModel.getUserName();
|
||||
final enabledInput = await bind.mainGetOption(key: 'enable-audio');
|
||||
final defaultInput = await gFFI.getDefaultAudioInput();
|
||||
var menu = <PopupMenuEntry>[
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable Keyboard/Mouse"),
|
||||
'enable-keyboard',
|
||||
),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable Clipboard"),
|
||||
'enable-clipboard',
|
||||
),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable File Transfer"),
|
||||
'enable-file-transfer',
|
||||
),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable TCP Tunneling"),
|
||||
'enable-tunnel',
|
||||
),
|
||||
genAudioInputPopupMenuItem(enabledInput != "N", defaultInput),
|
||||
PopupMenuDivider(),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("ID/Relay Server")),
|
||||
value: 'custom-server',
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("IP Whitelisting")),
|
||||
value: 'whitelist',
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("Socks5 Proxy")),
|
||||
value: 'socks5-proxy',
|
||||
),
|
||||
PopupMenuDivider(),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Enable Service"),
|
||||
'stop-service',
|
||||
),
|
||||
// TODO: direct server
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Always connected via relay"),
|
||||
'allow-always-relay',
|
||||
),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Start ID/relay service"),
|
||||
'stop-rendezvous-service',
|
||||
),
|
||||
PopupMenuDivider(),
|
||||
userName.isEmpty
|
||||
? PopupMenuItem(
|
||||
child: Text(translate("Login")),
|
||||
value: 'login',
|
||||
)
|
||||
: PopupMenuItem(
|
||||
child: Text("${translate("Logout")} $userName"),
|
||||
value: 'logout',
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("Change ID")),
|
||||
value: 'change-id',
|
||||
),
|
||||
PopupMenuDivider(),
|
||||
await genEnablePopupMenuItem(
|
||||
translate("Dark Theme"),
|
||||
'allow-darktheme',
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Text(translate("About")),
|
||||
value: 'about',
|
||||
),
|
||||
];
|
||||
final v =
|
||||
await showMenu(context: context, position: position, items: menu);
|
||||
if (v != null) {
|
||||
onSelectMenu(v);
|
||||
}
|
||||
},
|
||||
onTap: () async {},
|
||||
child: Obx(
|
||||
() => CircleAvatar(
|
||||
radius: 15,
|
||||
@ -276,6 +177,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
buildPasswordBoard(BuildContext context) {
|
||||
final model = gFFI.serverModel;
|
||||
RxBool refreshHover = false.obs;
|
||||
RxBool editHover = false.obs;
|
||||
return Container(
|
||||
margin: EdgeInsets.only(left: 20.0, right: 16, top: 13, bottom: 13),
|
||||
child: Row(
|
||||
@ -334,7 +236,19 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
onTap: () => bind.mainUpdateTemporaryPassword(),
|
||||
onHover: (value) => refreshHover.value = value,
|
||||
),
|
||||
const _PasswordPopupMenu(),
|
||||
InkWell(
|
||||
child: Obx(
|
||||
() => Icon(
|
||||
Icons.edit,
|
||||
color: editHover.value
|
||||
? MyTheme.color(context).text
|
||||
: Color(0xFFDDDDDD),
|
||||
size: 22,
|
||||
).marginOnly(right: 8, bottom: 2),
|
||||
),
|
||||
onTap: () => {},
|
||||
onHover: (value) => editHover.value = value,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@ -408,236 +322,6 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
windowManager.removeListener(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void changeTheme(String choice) async {
|
||||
if (choice == "Y") {
|
||||
Get.changeTheme(MyTheme.darkTheme);
|
||||
} else {
|
||||
Get.changeTheme(MyTheme.lightTheme);
|
||||
}
|
||||
Get.find<SharedPreferences>().setString("darkTheme", choice);
|
||||
Get.forceAppUpdate();
|
||||
}
|
||||
|
||||
void onSelectMenu(String key) async {
|
||||
if (key.startsWith('enable-')) {
|
||||
final option = await bind.mainGetOption(key: key);
|
||||
bind.mainSetOption(key: key, value: option == "N" ? "" : "N");
|
||||
} else if (key.startsWith('allow-')) {
|
||||
final option = await bind.mainGetOption(key: key);
|
||||
final choice = option == "Y" ? "" : "Y";
|
||||
bind.mainSetOption(key: key, value: choice);
|
||||
if (key == "allow-darktheme") changeTheme(choice);
|
||||
} else if (key == "stop-service") {
|
||||
final option = await bind.mainGetOption(key: key);
|
||||
bind.mainSetOption(key: key, value: option == "Y" ? "" : "Y");
|
||||
} else if (key == "change-id") {
|
||||
changeIdDialog();
|
||||
} else if (key == "custom-server") {
|
||||
changeServer();
|
||||
} else if (key == "whitelist") {
|
||||
changeWhiteList();
|
||||
} else if (key == "socks5-proxy") {
|
||||
changeSocks5Proxy();
|
||||
} else if (key == "about") {
|
||||
about();
|
||||
} else if (key == "logout") {
|
||||
logOut();
|
||||
} else if (key == "login") {
|
||||
login();
|
||||
}
|
||||
}
|
||||
|
||||
Future<PopupMenuItem<String>> genEnablePopupMenuItem(
|
||||
String label, String key) async {
|
||||
final v = await bind.mainGetOption(key: key);
|
||||
bool enable;
|
||||
if (key == "stop-service") {
|
||||
enable = v != "Y";
|
||||
} else if (key.startsWith("allow-")) {
|
||||
enable = v == "Y";
|
||||
} else {
|
||||
enable = v != "N";
|
||||
}
|
||||
|
||||
return PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.check,
|
||||
color: enable ? null : MyTheme.accent.withAlpha(00)),
|
||||
Text(
|
||||
label,
|
||||
style: genTextStyle(enable),
|
||||
),
|
||||
],
|
||||
),
|
||||
value: key,
|
||||
);
|
||||
}
|
||||
|
||||
TextStyle genTextStyle(bool isPositive) {
|
||||
return isPositive
|
||||
? TextStyle()
|
||||
: TextStyle(
|
||||
color: Colors.redAccent, decoration: TextDecoration.lineThrough);
|
||||
}
|
||||
|
||||
PopupMenuItem<String> genAudioInputPopupMenuItem(
|
||||
bool enableInput, String defaultAudioInput) {
|
||||
final defaultInput = defaultAudioInput.obs;
|
||||
final enabled = enableInput.obs;
|
||||
|
||||
return PopupMenuItem(
|
||||
child: FutureBuilder<List<String>>(
|
||||
future: gFFI.getAudioInputs(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final inputs = snapshot.data!.toList();
|
||||
if (Platform.isWindows) {
|
||||
inputs.insert(0, translate("System Sound"));
|
||||
}
|
||||
var inputList = inputs
|
||||
.map((e) => PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Obx(() => Offstage(
|
||||
offstage: defaultInput.value != e,
|
||||
child: Icon(Icons.check))),
|
||||
Expanded(
|
||||
child: Tooltip(
|
||||
message: e,
|
||||
child: Text(
|
||||
"$e",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
))),
|
||||
],
|
||||
),
|
||||
value: e,
|
||||
))
|
||||
.toList();
|
||||
inputList.insert(
|
||||
0,
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
children: [
|
||||
Obx(() => Offstage(
|
||||
offstage: enabled.value, child: Icon(Icons.check))),
|
||||
Expanded(child: Text(translate("Mute"))),
|
||||
],
|
||||
),
|
||||
value: "Mute",
|
||||
));
|
||||
return PopupMenuButton<String>(
|
||||
padding: EdgeInsets.zero,
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(translate("Audio Input"))),
|
||||
itemBuilder: (context) => inputList,
|
||||
onSelected: (dev) async {
|
||||
if (dev == "Mute") {
|
||||
await bind.mainSetOption(
|
||||
key: 'enable-audio', value: enabled.value ? '' : 'N');
|
||||
enabled.value =
|
||||
await bind.mainGetOption(key: 'enable-audio') != 'N';
|
||||
} else if (dev != await gFFI.getDefaultAudioInput()) {
|
||||
gFFI.setDefaultAudioInput(dev);
|
||||
defaultInput.value = dev;
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return Text("...");
|
||||
}
|
||||
},
|
||||
),
|
||||
value: 'audio-input',
|
||||
);
|
||||
}
|
||||
|
||||
void about() async {
|
||||
final appName = await bind.mainGetAppName();
|
||||
final license = await bind.mainGetLicense();
|
||||
final version = await bind.mainGetVersion();
|
||||
const linkStyle = TextStyle(decoration: TextDecoration.underline);
|
||||
gFFI.dialogManager.show((setState, close) {
|
||||
return CustomAlertDialog(
|
||||
title: Text("About $appName"),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 500),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 8.0,
|
||||
),
|
||||
Text("Version: $version").marginSymmetric(vertical: 4.0),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
launchUrlString("https://rustdesk.com/privacy");
|
||||
},
|
||||
child: const Text(
|
||||
"Privacy Statement",
|
||||
style: linkStyle,
|
||||
).marginSymmetric(vertical: 4.0)),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
launchUrlString("https://rustdesk.com");
|
||||
},
|
||||
child: const Text(
|
||||
"Website",
|
||||
style: linkStyle,
|
||||
).marginSymmetric(vertical: 4.0)),
|
||||
Container(
|
||||
decoration: const BoxDecoration(color: Color(0xFF2c8cff)),
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 24, horizontal: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Copyright © 2022 Purslane Ltd.\n$license",
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
const Text(
|
||||
"Made with heart in this chaotic world!",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.white),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
).marginSymmetric(vertical: 4.0)
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: close, child: Text(translate("OK"))),
|
||||
],
|
||||
onSubmit: close,
|
||||
onCancel: close,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void login() {
|
||||
loginDialog().then((success) {
|
||||
if (success) {
|
||||
// refresh frame
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void logOut() {
|
||||
gFFI.userModel.logOut().then((_) => {setState(() {})});
|
||||
}
|
||||
}
|
||||
|
||||
/// common login dialog for desktop
|
||||
@ -874,120 +558,3 @@ void setPasswordDialog() async {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
class _PasswordPopupMenu extends StatefulWidget {
|
||||
const _PasswordPopupMenu({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<_PasswordPopupMenu> createState() => _PasswordPopupMenuState();
|
||||
}
|
||||
|
||||
class _PasswordPopupMenuState extends State<_PasswordPopupMenu> {
|
||||
final RxBool _tempEnabled = true.obs;
|
||||
final RxBool _permEnabled = true.obs;
|
||||
|
||||
List<MenuEntryBase<String>> _buildMenus() {
|
||||
return <MenuEntryBase<String>>[
|
||||
MenuEntryRadios<String>(
|
||||
text: translate('Password type'),
|
||||
optionsGetter: () => [
|
||||
MenuEntryRadioOption(
|
||||
text: translate('Use temporary password'),
|
||||
value: kUseTemporaryPassword),
|
||||
MenuEntryRadioOption(
|
||||
text: translate('Use permanent password'),
|
||||
value: kUsePermanentPassword),
|
||||
MenuEntryRadioOption(
|
||||
text: translate('Use both passwords'),
|
||||
value: kUseBothPasswords),
|
||||
],
|
||||
curOptionGetter: () async {
|
||||
return gFFI.serverModel.verificationMethod;
|
||||
},
|
||||
optionSetter: (String oldValue, String newValue) async {
|
||||
await bind.mainSetOption(
|
||||
key: "verification-method", value: newValue);
|
||||
await gFFI.serverModel.updatePasswordModel();
|
||||
setState(() {
|
||||
_tempEnabled.value =
|
||||
gFFI.serverModel.verificationMethod != kUsePermanentPassword;
|
||||
_permEnabled.value =
|
||||
gFFI.serverModel.verificationMethod != kUseTemporaryPassword;
|
||||
});
|
||||
}),
|
||||
MenuEntryDivider(),
|
||||
MenuEntryButton<String>(
|
||||
enabled: _permEnabled,
|
||||
childBuilder: (TextStyle? style) => Text(
|
||||
translate('Set permanent password'),
|
||||
style: style,
|
||||
),
|
||||
proc: () {
|
||||
setPasswordDialog();
|
||||
},
|
||||
dismissOnClicked: true,
|
||||
),
|
||||
MenuEntrySubMenu(
|
||||
enabled: _tempEnabled,
|
||||
text: translate('Set temporary password length'),
|
||||
entries: [
|
||||
MenuEntryRadios<String>(
|
||||
enabled: _tempEnabled,
|
||||
text: translate(''),
|
||||
optionsGetter: () => [
|
||||
MenuEntryRadioOption(
|
||||
text: translate('6'),
|
||||
value: '6',
|
||||
enabled: _tempEnabled,
|
||||
),
|
||||
MenuEntryRadioOption(
|
||||
text: translate('8'),
|
||||
value: '8',
|
||||
enabled: _tempEnabled,
|
||||
),
|
||||
MenuEntryRadioOption(
|
||||
text: translate('10'),
|
||||
value: '10',
|
||||
enabled: _tempEnabled,
|
||||
),
|
||||
],
|
||||
curOptionGetter: () async {
|
||||
return gFFI.serverModel.temporaryPasswordLength;
|
||||
},
|
||||
optionSetter: (String oldValue, String newValue) async {
|
||||
if (oldValue != newValue) {
|
||||
await gFFI.serverModel.setTemporaryPasswordLength(newValue);
|
||||
await gFFI.serverModel.updatePasswordModel();
|
||||
}
|
||||
}),
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final editHover = false.obs;
|
||||
return mod_menu.PopupMenuButton(
|
||||
padding: EdgeInsets.zero,
|
||||
onHover: (v) => editHover.value = v,
|
||||
tooltip: translate(''),
|
||||
position: mod_menu.PopupMenuPosition.overSide,
|
||||
itemBuilder: (BuildContext context) => _buildMenus()
|
||||
.map((entry) => entry.build(
|
||||
context,
|
||||
const MenuConfig(
|
||||
commonColor: _MenubarTheme.commonColor,
|
||||
height: _MenubarTheme.height,
|
||||
dividerHeight: _MenubarTheme.dividerHeight,
|
||||
)))
|
||||
.expand((i) => i)
|
||||
.toList(),
|
||||
child: Obx(() => Icon(Icons.edit,
|
||||
size: 22,
|
||||
color: editHover.value
|
||||
? MyTheme.color(context).text
|
||||
: const Color(0xFFDDDDDD))
|
||||
.marginOnly(bottom: 2)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ packages:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -161,7 +161,7 @@ packages:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.0"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -367,6 +367,13 @@ packages:
|
||||
url: "https://github.com/Kingtous/rustdesk_flutter_custom_cursor"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
flutter_improved_scrolling:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_improved_scrolling
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.3"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -374,6 +381,11 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_parsed_text:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -478,7 +490,7 @@ packages:
|
||||
name: icons_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.0.4"
|
||||
image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -576,7 +588,7 @@ packages:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
version: "0.1.4"
|
||||
menu_base:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -590,7 +602,7 @@ packages:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.7.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -667,7 +679,7 @@ packages:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
version: "1.8.1"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -1,30 +0,0 @@
|
||||
// This is a basic Flutter widget test.
|
||||
//
|
||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||
// utility that Flutter provides. For example, you can send tap and scroll
|
||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:flutter_hbb/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(App());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
|
||||
// Tap the '+' icon and trigger a frame.
|
||||
await tester.tap(find.byIcon(Icons.add));
|
||||
await tester.pump();
|
||||
|
||||
// Verify that our counter has incremented.
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user