mirror of
https://github.com/foss42/apidash.git
synced 2025-06-02 07:46:10 +08:00
Merge branch 'main' into resolve-issue-env-field
This commit is contained in:
@ -124,6 +124,9 @@ const kP8CollectionPane = EdgeInsets.only(
|
|||||||
const kPt8 = EdgeInsets.only(
|
const kPt8 = EdgeInsets.only(
|
||||||
top: 8,
|
top: 8,
|
||||||
);
|
);
|
||||||
|
const kPt20 = EdgeInsets.only(
|
||||||
|
top: 20,
|
||||||
|
);
|
||||||
const kPt28 = EdgeInsets.only(
|
const kPt28 = EdgeInsets.only(
|
||||||
top: 28,
|
top: 28,
|
||||||
);
|
);
|
||||||
|
99
lib/screens/common_widgets/button_navbar.dart
Normal file
99
lib/screens/common_widgets/button_navbar.dart
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:apidash/providers/providers.dart';
|
||||||
|
|
||||||
|
class NavbarButton extends ConsumerWidget {
|
||||||
|
const NavbarButton({
|
||||||
|
super.key,
|
||||||
|
required this.railIdx,
|
||||||
|
this.buttonIdx,
|
||||||
|
required this.selectedIcon,
|
||||||
|
required this.icon,
|
||||||
|
required this.label,
|
||||||
|
this.showLabel = true,
|
||||||
|
this.isCompact = false,
|
||||||
|
this.onTap,
|
||||||
|
});
|
||||||
|
final int railIdx;
|
||||||
|
final int? buttonIdx;
|
||||||
|
final IconData selectedIcon;
|
||||||
|
final IconData icon;
|
||||||
|
final String label;
|
||||||
|
final bool showLabel;
|
||||||
|
final Function()? onTap;
|
||||||
|
final bool isCompact;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final bool isSelected = railIdx == buttonIdx;
|
||||||
|
final Size size = isCompact ? const Size(56, 32) : const Size(65, 32);
|
||||||
|
return MouseRegion(
|
||||||
|
cursor: SystemMouseCursors.click,
|
||||||
|
child: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
onTap: isSelected
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
if (buttonIdx != null) {
|
||||||
|
ref.read(navRailIndexStateProvider.notifier).state =
|
||||||
|
buttonIdx!;
|
||||||
|
if (railIdx > 1 && buttonIdx! <= 1) {
|
||||||
|
ref.read(leftDrawerStateProvider.notifier).state = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onTap?.call();
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
style: isSelected
|
||||||
|
? TextButton.styleFrom(
|
||||||
|
fixedSize: size,
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
)
|
||||||
|
: TextButton.styleFrom(
|
||||||
|
fixedSize: size,
|
||||||
|
),
|
||||||
|
onPressed: isSelected
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
if (buttonIdx != null) {
|
||||||
|
ref.read(navRailIndexStateProvider.notifier).state =
|
||||||
|
buttonIdx!;
|
||||||
|
if (railIdx > 1 && buttonIdx! <= 1) {
|
||||||
|
ref.read(leftDrawerStateProvider.notifier).state =
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onTap?.call();
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
isSelected ? selectedIcon : icon,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
showLabel ? const SizedBox(height: 4) : const SizedBox.shrink(),
|
||||||
|
showLabel
|
||||||
|
? Text(
|
||||||
|
label,
|
||||||
|
style: Theme.of(context).textTheme.labelSmall!.copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: isSelected
|
||||||
|
? Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface
|
||||||
|
.withOpacity(0.65),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
export 'button_navbar.dart';
|
||||||
export 'editor_title.dart';
|
export 'editor_title.dart';
|
||||||
export 'editor_title_actions.dart';
|
export 'editor_title_actions.dart';
|
||||||
export 'envfield_url.dart';
|
export 'envfield_url.dart';
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:apidash/providers/providers.dart';
|
import 'package:apidash/providers/providers.dart';
|
||||||
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'common_widgets/common_widgets.dart';
|
||||||
import 'envvar/environment_page.dart';
|
import 'envvar/environment_page.dart';
|
||||||
import 'home_page/home_page.dart';
|
import 'home_page/home_page.dart';
|
||||||
import 'intro_page.dart';
|
|
||||||
import 'settings_page.dart';
|
import 'settings_page.dart';
|
||||||
|
|
||||||
class Dashboard extends ConsumerWidget {
|
class Dashboard extends ConsumerWidget {
|
||||||
@ -52,6 +53,19 @@ class Dashboard extends ConsumerWidget {
|
|||||||
'Variables',
|
'Variables',
|
||||||
style: Theme.of(context).textTheme.labelSmall,
|
style: Theme.of(context).textTheme.labelSmall,
|
||||||
),
|
),
|
||||||
|
kVSpacer10,
|
||||||
|
// IconButton(
|
||||||
|
// isSelected: railIdx == 2,
|
||||||
|
// onPressed: () {
|
||||||
|
// ref.read(navRailIndexStateProvider.notifier).state = 2;
|
||||||
|
// },
|
||||||
|
// icon: const Icon(Icons.history_outlined),
|
||||||
|
// selectedIcon: const Icon(Icons.history),
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// 'History',
|
||||||
|
// style: Theme.of(context).textTheme.labelSmall,
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -60,30 +74,34 @@ class Dashboard extends ConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 16.0),
|
padding: const EdgeInsets.only(bottom: 16.0),
|
||||||
child: bottomButton(context, ref, railIdx, 2,
|
child: NavbarButton(
|
||||||
Icons.help, Icons.help_outline),
|
railIdx: railIdx,
|
||||||
|
selectedIcon: Icons.help,
|
||||||
|
icon: Icons.help_outline,
|
||||||
|
label: 'About',
|
||||||
|
showLabel: false,
|
||||||
|
isCompact: true,
|
||||||
|
onTap: () {
|
||||||
|
showAboutAppDialog(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 16.0),
|
padding: const EdgeInsets.only(bottom: 16.0),
|
||||||
child: bottomButton(context, ref, railIdx, 3,
|
child: NavbarButton(
|
||||||
Icons.settings, Icons.settings_outlined),
|
railIdx: railIdx,
|
||||||
|
buttonIdx: 2,
|
||||||
|
selectedIcon: Icons.settings,
|
||||||
|
icon: Icons.settings_outlined,
|
||||||
|
label: 'Settings',
|
||||||
|
showLabel: false,
|
||||||
|
isCompact: true,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
// destinations: const <NavigationRailDestination>[
|
|
||||||
// // NavigationRailDestination(
|
|
||||||
// // icon: Icon(Icons.home_outlined),
|
|
||||||
// // selectedIcon: Icon(Icons.home),
|
|
||||||
// // label: Text('Home'),
|
|
||||||
// // ),
|
|
||||||
// NavigationRailDestination(
|
|
||||||
// icon: Icon(Icons.auto_awesome_mosaic_outlined),
|
|
||||||
// selectedIcon: Icon(Icons.auto_awesome_mosaic),
|
|
||||||
// label: Text('Requests'),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
),
|
),
|
||||||
VerticalDivider(
|
VerticalDivider(
|
||||||
thickness: 1,
|
thickness: 1,
|
||||||
@ -99,7 +117,6 @@ class Dashboard extends ConsumerWidget {
|
|||||||
EnvironmentPage(
|
EnvironmentPage(
|
||||||
scaffoldKey: mobileScaffoldKey,
|
scaffoldKey: mobileScaffoldKey,
|
||||||
),
|
),
|
||||||
const IntroPage(),
|
|
||||||
const SettingsPage(),
|
const SettingsPage(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -109,31 +126,4 @@ class Dashboard extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextButton bottomButton(
|
|
||||||
BuildContext context,
|
|
||||||
WidgetRef ref,
|
|
||||||
int railIdx,
|
|
||||||
int buttonIdx,
|
|
||||||
IconData selectedIcon,
|
|
||||||
IconData icon,
|
|
||||||
) {
|
|
||||||
bool isSelected = railIdx == buttonIdx;
|
|
||||||
return TextButton(
|
|
||||||
style: isSelected
|
|
||||||
? TextButton.styleFrom(
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
onPressed: isSelected
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
ref.read(navRailIndexStateProvider.notifier).state = buttonIdx;
|
|
||||||
},
|
|
||||||
child: Icon(
|
|
||||||
isSelected ? selectedIcon : icon,
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:apidash/widgets/widgets.dart';
|
|
||||||
|
|
||||||
class IntroPage extends StatelessWidget {
|
|
||||||
const IntroPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const IntroMessage();
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||||
import 'package:apidash/extensions/extensions.dart';
|
import 'package:apidash/extensions/extensions.dart';
|
||||||
import 'package:apidash/providers/providers.dart';
|
import 'package:apidash/providers/providers.dart';
|
||||||
import '../intro_page.dart';
|
|
||||||
import '../settings_page.dart';
|
import '../settings_page.dart';
|
||||||
import 'navbar.dart';
|
import 'navbar.dart';
|
||||||
import 'requests_page/requests_page.dart';
|
import 'requests_page/requests_page.dart';
|
||||||
@ -73,12 +72,13 @@ class PageBranch extends ConsumerWidget {
|
|||||||
return EnvironmentPage(
|
return EnvironmentPage(
|
||||||
scaffoldKey: scaffoldKey,
|
scaffoldKey: scaffoldKey,
|
||||||
);
|
);
|
||||||
|
// case 2:
|
||||||
|
// // TODO: Implement history page
|
||||||
|
// return const PageBase(
|
||||||
|
// title: 'History',
|
||||||
|
// scaffoldBody: SizedBox(),
|
||||||
|
// );
|
||||||
case 2:
|
case 2:
|
||||||
return const PageBase(
|
|
||||||
title: 'About',
|
|
||||||
scaffoldBody: IntroPage(),
|
|
||||||
);
|
|
||||||
case 3:
|
|
||||||
return const PageBase(
|
return const PageBase(
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
scaffoldBody: SettingsPage(),
|
scaffoldBody: SettingsPage(),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:apidash/providers/providers.dart';
|
import 'package:apidash/providers/providers.dart';
|
||||||
|
import '../common_widgets/common_widgets.dart';
|
||||||
|
|
||||||
class BottomNavBar extends ConsumerWidget {
|
class BottomNavBar extends ConsumerWidget {
|
||||||
const BottomNavBar({super.key});
|
const BottomNavBar({super.key});
|
||||||
@ -30,39 +31,39 @@ class BottomNavBar extends ConsumerWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: customNavigationDestination(context, ref, railIdx, 0,
|
child: NavbarButton(
|
||||||
Icons.dashboard, Icons.dashboard_outlined, 'Requests'),
|
railIdx: railIdx,
|
||||||
),
|
buttonIdx: 0,
|
||||||
Expanded(
|
selectedIcon: Icons.dashboard,
|
||||||
child: customNavigationDestination(
|
icon: Icons.dashboard_outlined,
|
||||||
context,
|
label: 'Requests',
|
||||||
ref,
|
|
||||||
railIdx,
|
|
||||||
1,
|
|
||||||
Icons.laptop_windows,
|
|
||||||
Icons.laptop_windows_outlined,
|
|
||||||
'Variables'),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: customNavigationDestination(
|
|
||||||
context,
|
|
||||||
ref,
|
|
||||||
railIdx,
|
|
||||||
2,
|
|
||||||
Icons.help,
|
|
||||||
Icons.help_outline,
|
|
||||||
'About',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: customNavigationDestination(
|
child: NavbarButton(
|
||||||
context,
|
railIdx: railIdx,
|
||||||
ref,
|
buttonIdx: 1,
|
||||||
railIdx,
|
selectedIcon: Icons.laptop_windows,
|
||||||
3,
|
icon: Icons.laptop_windows_outlined,
|
||||||
Icons.settings,
|
label: 'Variables',
|
||||||
Icons.settings_outlined,
|
),
|
||||||
'Settings',
|
),
|
||||||
|
// Expanded(
|
||||||
|
// child: NavbarButton(
|
||||||
|
// railIdx: railIdx,
|
||||||
|
// buttonIdx: 2,
|
||||||
|
// selectedIcon: Icons.history,
|
||||||
|
// icon: Icons.history_outlined,
|
||||||
|
// label: 'History',
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
Expanded(
|
||||||
|
child: NavbarButton(
|
||||||
|
railIdx: railIdx,
|
||||||
|
buttonIdx: 2,
|
||||||
|
selectedIcon: Icons.settings,
|
||||||
|
icon: Icons.settings_outlined,
|
||||||
|
label: 'Settings',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -73,82 +74,3 @@ class BottomNavBar extends ConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget customNavigationDestination(
|
|
||||||
BuildContext context,
|
|
||||||
WidgetRef ref,
|
|
||||||
int railIdx,
|
|
||||||
int buttonIdx,
|
|
||||||
IconData selectedIcon,
|
|
||||||
IconData icon,
|
|
||||||
String label, {
|
|
||||||
bool showLabel = true,
|
|
||||||
Function()? onTap,
|
|
||||||
}) {
|
|
||||||
bool isSelected = railIdx == buttonIdx;
|
|
||||||
return MouseRegion(
|
|
||||||
cursor: SystemMouseCursors.click,
|
|
||||||
child: GestureDetector(
|
|
||||||
behavior: HitTestBehavior.translucent,
|
|
||||||
onTap: isSelected
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
ref.read(navRailIndexStateProvider.notifier).state = buttonIdx;
|
|
||||||
if (railIdx > 1 && buttonIdx <= 1) {
|
|
||||||
ref.read(leftDrawerStateProvider.notifier).state = false;
|
|
||||||
}
|
|
||||||
onTap?.call();
|
|
||||||
},
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Ink(
|
|
||||||
width: 65,
|
|
||||||
height: 32,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: isSelected
|
|
||||||
? Theme.of(context).colorScheme.secondaryContainer
|
|
||||||
: Colors.transparent,
|
|
||||||
borderRadius: BorderRadius.circular(30),
|
|
||||||
),
|
|
||||||
child: InkWell(
|
|
||||||
borderRadius: BorderRadius.circular(30),
|
|
||||||
onTap: isSelected
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
ref.read(navRailIndexStateProvider.notifier).state =
|
|
||||||
buttonIdx;
|
|
||||||
if (railIdx > 1 && buttonIdx <= 1) {
|
|
||||||
ref.read(leftDrawerStateProvider.notifier).state =
|
|
||||||
false;
|
|
||||||
}
|
|
||||||
onTap?.call();
|
|
||||||
},
|
|
||||||
child: Icon(
|
|
||||||
isSelected ? selectedIcon : icon,
|
|
||||||
color: isSelected
|
|
||||||
? Theme.of(context).colorScheme.onSecondaryContainer
|
|
||||||
: Theme.of(context).colorScheme.onSurface.withOpacity(0.65),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
showLabel ? const SizedBox(height: 4) : const SizedBox.shrink(),
|
|
||||||
showLabel
|
|
||||||
? Text(
|
|
||||||
label,
|
|
||||||
style: Theme.of(context).textTheme.labelSmall!.copyWith(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
color: isSelected
|
|
||||||
? Theme.of(context).colorScheme.onSecondaryContainer
|
|
||||||
: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onSurface
|
|
||||||
.withOpacity(0.65),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const SizedBox.shrink(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -37,10 +37,8 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
padding: kPh20,
|
|
||||||
children: [
|
children: [
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
hoverColor: kColorTransparent,
|
hoverColor: kColorTransparent,
|
||||||
title: const Text('Switch Theme Mode'),
|
title: const Text('Switch Theme Mode'),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
@ -51,7 +49,6 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
hoverColor: kColorTransparent,
|
hoverColor: kColorTransparent,
|
||||||
title: const Text('Collection Pane Scrollbar Visiblity'),
|
title: const Text('Collection Pane Scrollbar Visiblity'),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
@ -64,7 +61,6 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
contentPadding: kPb10,
|
|
||||||
hoverColor: kColorTransparent,
|
hoverColor: kColorTransparent,
|
||||||
title: const Text('Default URI Scheme'),
|
title: const Text('Default URI Scheme'),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
@ -109,7 +105,6 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
contentPadding: kPb10,
|
|
||||||
hoverColor: kColorTransparent,
|
hoverColor: kColorTransparent,
|
||||||
title: const Text('Default Code Generator'),
|
title: const Text('Default Code Generator'),
|
||||||
trailing: Container(
|
trailing: Container(
|
||||||
@ -151,7 +146,6 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
CheckboxListTile(
|
CheckboxListTile(
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
title: const Text("Save Responses"),
|
title: const Text("Save Responses"),
|
||||||
subtitle:
|
subtitle:
|
||||||
const Text("Save disk space by not storing API responses"),
|
const Text("Save disk space by not storing API responses"),
|
||||||
@ -163,7 +157,6 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
CheckboxListTile(
|
CheckboxListTile(
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
title: const Text("Show Save Alert on App Close"),
|
title: const Text("Show Save Alert on App Close"),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
"Show a confirmation dialog to save workspace when the user closes the app"),
|
"Show a confirmation dialog to save workspace when the user closes the app"),
|
||||||
@ -175,7 +168,6 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
hoverColor: kColorTransparent,
|
hoverColor: kColorTransparent,
|
||||||
title: const Text('Export Data'),
|
title: const Text('Export Data'),
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
@ -195,7 +187,6 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
hoverColor: kColorTransparent,
|
hoverColor: kColorTransparent,
|
||||||
title: const Text('Clear Data'),
|
title: const Text('Clear Data'),
|
||||||
subtitle: const Text('Delete all requests data from the disk'),
|
subtitle: const Text('Delete all requests data from the disk'),
|
||||||
@ -250,6 +241,15 @@ class SettingsPage extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('About'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'Release Details, Support Channel, Report Bug / Request New Feature'),
|
||||||
|
onTap: () {
|
||||||
|
showAboutAppDialog(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
kVSpacer20,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
29
lib/widgets/dialog_about.dart
Normal file
29
lib/widgets/dialog_about.dart
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
|
|
||||||
|
showAboutAppDialog(
|
||||||
|
BuildContext context,
|
||||||
|
) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
contentPadding: kPt20 + kPh20 + kPb10,
|
||||||
|
content: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
constraints: const BoxConstraints(maxWidth: 540, maxHeight: 544),
|
||||||
|
child: const IntroMessage(),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text("Close"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -4,7 +4,6 @@ import 'package:package_info_plus/package_info_plus.dart';
|
|||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
import 'markdown.dart';
|
import 'markdown.dart';
|
||||||
import 'error_message.dart';
|
import 'error_message.dart';
|
||||||
import 'package:apidash/extensions/extensions.dart';
|
|
||||||
|
|
||||||
class IntroMessage extends StatelessWidget {
|
class IntroMessage extends StatelessWidget {
|
||||||
const IntroMessage({
|
const IntroMessage({
|
||||||
@ -38,7 +37,7 @@ class IntroMessage extends StatelessWidget {
|
|||||||
|
|
||||||
return CustomMarkdown(
|
return CustomMarkdown(
|
||||||
data: text,
|
data: text,
|
||||||
padding: !context.isMediumWindow ? kPh60 : kPh20,
|
padding: EdgeInsets.zero,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
@ -19,8 +19,8 @@ class DashboardSplitView extends StatefulWidget {
|
|||||||
class DashboardSplitViewState extends State<DashboardSplitView> {
|
class DashboardSplitViewState extends State<DashboardSplitView> {
|
||||||
final MultiSplitViewController _controller = MultiSplitViewController(
|
final MultiSplitViewController _controller = MultiSplitViewController(
|
||||||
areas: [
|
areas: [
|
||||||
Area(id: "sidebar", size: 250, min: 200),
|
Area(id: "sidebar", min: 220, size: 250, max: 350),
|
||||||
Area(id: "main", min: 0.7),
|
Area(id: "main", min: 400),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -44,6 +44,8 @@ class DashboardSplitViewState extends State<DashboardSplitView> {
|
|||||||
),
|
),
|
||||||
child: MultiSplitView(
|
child: MultiSplitView(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
sizeOverflowPolicy: SizeOverflowPolicy.shrinkFirst,
|
||||||
|
sizeUnderflowPolicy: SizeUnderflowPolicy.stretchLast,
|
||||||
builder: (context, area) {
|
builder: (context, area) {
|
||||||
return switch (area.id) {
|
return switch (area.id) {
|
||||||
"sidebar" => widget.sidebarWidget,
|
"sidebar" => widget.sidebarWidget,
|
||||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:multi_split_view/multi_split_view.dart';
|
import 'package:multi_split_view/multi_split_view.dart';
|
||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class EqualSplitView extends StatefulWidget {
|
class EqualSplitView extends StatelessWidget {
|
||||||
const EqualSplitView({
|
const EqualSplitView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.leftWidget,
|
required this.leftWidget,
|
||||||
@ -12,17 +12,17 @@ class EqualSplitView extends StatefulWidget {
|
|||||||
final Widget leftWidget;
|
final Widget leftWidget;
|
||||||
final Widget rightWidget;
|
final Widget rightWidget;
|
||||||
|
|
||||||
@override
|
getMinFractionWidth(double width) {
|
||||||
State<EqualSplitView> createState() => _EqualSplitViewState();
|
if (width < 900) {
|
||||||
|
return 0.9;
|
||||||
|
} else if (width < 1000) {
|
||||||
|
return 0.7;
|
||||||
|
} else if (width < 1200) {
|
||||||
|
return 0.5;
|
||||||
|
} else {
|
||||||
|
return 0.4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EqualSplitViewState extends State<EqualSplitView> {
|
|
||||||
final MultiSplitViewController _controller = MultiSplitViewController(
|
|
||||||
areas: [
|
|
||||||
Area(id: "left", min: kMinRequestEditorDetailsCardPaneSize),
|
|
||||||
Area(id: "right", min: kMinRequestEditorDetailsCardPaneSize),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -37,22 +37,26 @@ class _EqualSplitViewState extends State<EqualSplitView> {
|
|||||||
animationEnabled: false,
|
animationEnabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: MultiSplitView(
|
child: LayoutBuilder(
|
||||||
controller: _controller,
|
builder: (context, constraints) {
|
||||||
|
final minWidth = getMinFractionWidth(constraints.maxWidth);
|
||||||
|
return MultiSplitView(
|
||||||
|
controller: MultiSplitViewController(
|
||||||
|
areas: [
|
||||||
|
Area(id: "left", flex: 1, min: minWidth),
|
||||||
|
Area(id: "right", flex: 1, min: minWidth),
|
||||||
|
],
|
||||||
|
),
|
||||||
builder: (context, area) {
|
builder: (context, area) {
|
||||||
return switch (area.id) {
|
return switch (area.id) {
|
||||||
"left" => widget.leftWidget,
|
"left" => leftWidget,
|
||||||
"right" => widget.rightWidget,
|
"right" => rightWidget,
|
||||||
_ => Container(),
|
_ => Container(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@ export 'card_sidebar_request.dart';
|
|||||||
export 'checkbox.dart';
|
export 'checkbox.dart';
|
||||||
export 'code_previewer.dart';
|
export 'code_previewer.dart';
|
||||||
export 'codegen_previewer.dart';
|
export 'codegen_previewer.dart';
|
||||||
export 'dialogs.dart';
|
export 'dialog_about.dart';
|
||||||
|
export 'dialog_rename.dart';
|
||||||
export 'dropdown_codegen.dart';
|
export 'dropdown_codegen.dart';
|
||||||
export 'dropdown_content_type.dart';
|
export 'dropdown_content_type.dart';
|
||||||
export 'dropdown_formdata.dart';
|
export 'dropdown_formdata.dart';
|
||||||
|
@ -853,10 +853,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: multi_split_view
|
name: multi_split_view
|
||||||
sha256: "2ef6a7ff9d0957bf559075d2703507ea898c8b70e37ff5ac3636298370513b7a"
|
sha256: "1ee1974d9aae6bdc08e2abdead6066c914cefe4b0c5999cac1a2e4722fcf33ba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "3.2.2"
|
||||||
multi_trigger_autocomplete:
|
multi_trigger_autocomplete:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -10,7 +10,7 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
multi_split_view: ^3.2.1
|
multi_split_view: ^3.2.2
|
||||||
url_launcher: ^6.2.5
|
url_launcher: ^6.2.5
|
||||||
flutter_riverpod: ^2.5.1
|
flutter_riverpod: ^2.5.1
|
||||||
riverpod: ^2.5.1
|
riverpod: ^2.5.1
|
||||||
|
@ -11,7 +11,6 @@ import 'package:apidash/screens/home_page/editor_pane/editor_default.dart';
|
|||||||
import 'package:apidash/screens/home_page/editor_pane/editor_pane.dart';
|
import 'package:apidash/screens/home_page/editor_pane/editor_pane.dart';
|
||||||
import 'package:apidash/screens/home_page/editor_pane/url_card.dart';
|
import 'package:apidash/screens/home_page/editor_pane/url_card.dart';
|
||||||
import 'package:apidash/screens/home_page/home_page.dart';
|
import 'package:apidash/screens/home_page/home_page.dart';
|
||||||
import 'package:apidash/screens/intro_page.dart';
|
|
||||||
import 'package:apidash/screens/settings_page.dart';
|
import 'package:apidash/screens/settings_page.dart';
|
||||||
import 'package:apidash/services/hive_services.dart';
|
import 'package:apidash/services/hive_services.dart';
|
||||||
import 'package:apidash/widgets/widgets.dart';
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
@ -58,7 +57,6 @@ void main() {
|
|||||||
// Verify that the HomePage is displayed initially
|
// Verify that the HomePage is displayed initially
|
||||||
expect(find.byType(HomePage), findsOneWidget);
|
expect(find.byType(HomePage), findsOneWidget);
|
||||||
expect(find.byType(EnvironmentPage), findsNothing);
|
expect(find.byType(EnvironmentPage), findsNothing);
|
||||||
expect(find.byType(IntroPage), findsNothing);
|
|
||||||
expect(find.byType(SettingsPage), findsNothing);
|
expect(find.byType(SettingsPage), findsNothing);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -79,12 +77,11 @@ void main() {
|
|||||||
// Verify that the EnvironmentPage is displayed
|
// Verify that the EnvironmentPage is displayed
|
||||||
expect(find.byType(HomePage), findsNothing);
|
expect(find.byType(HomePage), findsNothing);
|
||||||
expect(find.byType(EnvironmentPage), findsOneWidget);
|
expect(find.byType(EnvironmentPage), findsOneWidget);
|
||||||
expect(find.byType(IntroPage), findsNothing);
|
|
||||||
expect(find.byType(SettingsPage), findsNothing);
|
expect(find.byType(SettingsPage), findsNothing);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
"Dashboard should display IntroPage when navRailIndexStateProvider is 2",
|
"Dashboard should display SettingsPage when navRailIndexStateProvider is 2",
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
@ -99,33 +96,9 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify that the IntroPage is displayed
|
|
||||||
expect(find.byType(HomePage), findsNothing);
|
|
||||||
expect(find.byType(EnvironmentPage), findsNothing);
|
|
||||||
expect(find.byType(IntroPage), findsOneWidget);
|
|
||||||
expect(find.byType(SettingsPage), findsNothing);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets(
|
|
||||||
"Dashboard should display SettingsPage when navRailIndexStateProvider is 3",
|
|
||||||
(WidgetTester tester) async {
|
|
||||||
await tester.pumpWidget(
|
|
||||||
ProviderScope(
|
|
||||||
overrides: [
|
|
||||||
navRailIndexStateProvider.overrideWith((ref) => 3),
|
|
||||||
],
|
|
||||||
child: const Portal(
|
|
||||||
child: MaterialApp(
|
|
||||||
home: Dashboard(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify that the SettingsPage is displayed
|
// Verify that the SettingsPage is displayed
|
||||||
expect(find.byType(HomePage), findsNothing);
|
expect(find.byType(HomePage), findsNothing);
|
||||||
expect(find.byType(EnvironmentPage), findsNothing);
|
expect(find.byType(EnvironmentPage), findsNothing);
|
||||||
expect(find.byType(IntroPage), findsNothing);
|
|
||||||
expect(find.byType(SettingsPage), findsOneWidget);
|
expect(find.byType(SettingsPage), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -142,8 +115,8 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Tap on the Intro icon
|
// Tap on the Settings icon
|
||||||
await tester.tap(find.byIcon(Icons.help_outline));
|
await tester.tap(find.byIcon(Icons.settings_outlined));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
// Verify that the navRailIndexStateProvider is updated
|
// Verify that the navRailIndexStateProvider is updated
|
||||||
@ -184,11 +157,10 @@ void main() {
|
|||||||
// Verify that the navRailIndexStateProvider still has the updated value
|
// Verify that the navRailIndexStateProvider still has the updated value
|
||||||
final dashboard = tester.element(find.byType(Dashboard));
|
final dashboard = tester.element(find.byType(Dashboard));
|
||||||
final container = ProviderScope.containerOf(dashboard);
|
final container = ProviderScope.containerOf(dashboard);
|
||||||
expect(container.read(navRailIndexStateProvider), 3);
|
expect(container.read(navRailIndexStateProvider), 2);
|
||||||
|
|
||||||
// Verify that the SettingsPage is still displayed after the rebuild
|
// Verify that the SettingsPage is still displayed after the rebuild
|
||||||
expect(find.byType(SettingsPage), findsOneWidget);
|
expect(find.byType(SettingsPage), findsOneWidget);
|
||||||
expect(find.byType(IntroPage), findsNothing);
|
|
||||||
expect(find.byType(HomePage), findsNothing);
|
expect(find.byType(HomePage), findsNothing);
|
||||||
expect(find.byType(EnvironmentPage), findsNothing);
|
expect(find.byType(EnvironmentPage), findsNothing);
|
||||||
});
|
});
|
||||||
@ -219,17 +191,8 @@ void main() {
|
|||||||
// Verify that the selected icon is the filled version (selectedIcon)
|
// Verify that the selected icon is the filled version (selectedIcon)
|
||||||
expect(find.byIcon(Icons.computer_rounded), findsOneWidget);
|
expect(find.byIcon(Icons.computer_rounded), findsOneWidget);
|
||||||
|
|
||||||
// Go to IntroPage
|
|
||||||
container.read(navRailIndexStateProvider.notifier).state = 2;
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Verify that the IntroPage is displayed
|
|
||||||
expect(find.byType(IntroPage), findsOneWidget);
|
|
||||||
// Verify that the selected icon is the filled version (selectedIcon)
|
|
||||||
expect(find.byIcon(Icons.help), findsOneWidget);
|
|
||||||
|
|
||||||
// Go to SettingsPage
|
// Go to SettingsPage
|
||||||
container.read(navRailIndexStateProvider.notifier).state = 3;
|
container.read(navRailIndexStateProvider.notifier).state = 2;
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
// Verify that the SettingsPage is displayed
|
// Verify that the SettingsPage is displayed
|
||||||
|
Reference in New Issue
Block a user