wip: desktop responsiveness

This commit is contained in:
DenserMeerkat
2024-06-09 18:51:13 +05:30
parent a49bcec641
commit b0c4f7145b
17 changed files with 299 additions and 257 deletions

View File

@ -6,7 +6,6 @@ import 'package:window_manager/window_manager.dart' hide WindowCaption;
import 'widgets/widgets.dart' show WindowCaption;
import 'providers/providers.dart';
import 'screens/screens.dart';
import 'extensions/extensions.dart';
import 'consts.dart';
class App extends ConsumerStatefulWidget {
@ -125,24 +124,23 @@ class DashApp extends ConsumerWidget {
visualDensity: VisualDensity.adaptivePlatformDensity,
),
themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light,
home: kIsMobile
? context.isLargeWidth
? const Dashboard()
: const MobileDashboard()
: Stack(
children: [
kIsLinux ? const Dashboard() : const App(),
if (kIsWindows)
SizedBox(
height: 29,
child: WindowCaption(
backgroundColor: Colors.transparent,
brightness:
isDarkMode ? Brightness.dark : Brightness.light,
),
),
],
home: Stack(
children: [
context.isMediumWindow
? const MobileDashboard()
: !kIsLinux && !kIsMobile
? const App()
: const Dashboard(),
if (kIsWindows)
SizedBox(
height: 29,
child: WindowCaption(
backgroundColor: Colors.transparent,
brightness: isDarkMode ? Brightness.dark : Brightness.light,
),
),
],
),
);
}
}

View File

@ -35,11 +35,14 @@ final kColorLightDanger = Colors.red.withOpacity(0.9);
const kColorDarkDanger = Color(0xffcf6679);
const kWindowTitle = "API Dash";
const kMinWindowSize = Size(900, 600);
const kMinWindowSize = Size(320, 640);
const kMinInitialWindowWidth = 1200.0;
const kMinInitialWindowHeight = 800.0;
const kMinRequestEditorDetailsCardPaneSize = 300.0;
const kLargeMobileWidth = 600.0;
const kCompactWindowWidth = 600.0;
const kMediumWindowWidth = 840.0;
const kExpandedWindowWidth = 1200.0;
const kLargeWindowWidth = 1600.0;
const kColorSchemeSeed = Colors.blue;
final kFontFamily = GoogleFonts.openSans().fontFamily;
@ -106,6 +109,8 @@ const kP8CollectionPane = EdgeInsets.only(
//right: 4.0,
// bottom: 8.0,
);
const kPt28 = EdgeInsets.only(top: 28);
const kPt32 = EdgeInsets.only(top: 32);
const kPb10 = EdgeInsets.only(
bottom: 10,
);

View File

@ -2,9 +2,17 @@ import 'package:apidash/consts.dart';
import 'package:flutter/material.dart';
extension MediaQueryExtension on BuildContext {
bool get isLargeWidth =>
MediaQuery.of(this).size.width > kMinWindowSize.width;
bool get isCompactWindow =>
MediaQuery.of(this).size.width < kCompactWindowWidth;
bool get isMobile =>
kIsMobile && MediaQuery.of(this).size.width < kMinWindowSize.width;
bool get isMediumWindow =>
MediaQuery.of(this).size.width < kMediumWindowWidth;
bool get isExpandedWindow =>
MediaQuery.of(this).size.width < kExpandedWindowWidth;
bool get isLargeWindow => MediaQuery.of(this).size.width < kLargeWindowWidth;
bool get isExtraLargeWindow =>
MediaQuery.of(this).size.width > kLargeWindowWidth;
}

View File

@ -150,7 +150,7 @@ class _RequestListState extends ConsumerState<RequestList> {
radius: const Radius.circular(12),
child: filterQuery.isEmpty
? ReorderableListView.builder(
padding: context.isMobile
padding: context.isMediumWindow
? EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom,
right: 8,
@ -198,7 +198,7 @@ class _RequestListState extends ConsumerState<RequestList> {
},
)
: ListView(
padding: kIsMobile
padding: context.isMediumWindow
? EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom,
right: 8,

View File

@ -12,7 +12,7 @@ class RequestEditor extends StatelessWidget {
@override
Widget build(BuildContext context) {
return context.isMobile
return context.isMediumWindow
? const Padding(
padding: kPb10,
child: Column(

View File

@ -21,9 +21,9 @@ class EditorPaneRequestURLCard extends StatelessWidget {
child: Padding(
padding: EdgeInsets.symmetric(
vertical: 5,
horizontal: !context.isMobile ? 20 : 6,
horizontal: !context.isMediumWindow ? 20 : 6,
),
child: context.isMobile
child: context.isMediumWindow
? const Row(
children: [
DropdownButtonHTTPMethod(),

View File

@ -4,7 +4,8 @@ import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:inner_drawer/inner_drawer.dart';
import 'package:flex_color_scheme/flex_color_scheme.dart';
import '../../providers/providers.dart';
import 'package:apidash/extensions/extensions.dart';
import 'package:apidash/providers/providers.dart';
import 'navbar.dart';
import 'widgets/left_drawer.dart';
import 'requests_page.dart';
@ -44,7 +45,6 @@ class _MobileDashboardState extends ConsumerState<MobileDashboard> {
) {
final GlobalKey<InnerDrawerState> innerDrawerKey =
ref.watch(mobileDrawerKeyProvider);
final isLargeMobile = MediaQuery.sizeOf(context).width > kLargeMobileWidth;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: FlexColorScheme.themedSystemNavigationBar(
context,
@ -59,7 +59,7 @@ class _MobileDashboardState extends ConsumerState<MobileDashboard> {
swipe: true,
swipeChild: true,
onTapClose: true,
offset: isLargeMobile
offset: !context.isCompactWindow
? const IDOffset.only(left: 0.1, right: 1)
: const IDOffset.only(left: 0.7, right: 1),
boxShadow: [
@ -72,8 +72,8 @@ class _MobileDashboardState extends ConsumerState<MobileDashboard> {
colorTransitionChild: Colors.transparent,
colorTransitionScaffold: Colors.transparent,
rightAnimationType: InnerDrawerAnimation.linear,
backgroundDecoration:
BoxDecoration(color: Theme.of(context).colorScheme.surface),
backgroundDecoration: BoxDecoration(
color: Theme.of(context).colorScheme.onInverseSurface),
onDragUpdate: (value, direction) {
drawerDirection.value = direction;
if (value > 0.98 && direction == InnerDrawerDirection.start) {
@ -105,6 +105,7 @@ class _MobileDashboardState extends ConsumerState<MobileDashboard> {
borderRadius:
const BorderRadius.only(topLeft: Radius.circular(8)),
child: SafeArea(
minimum: kIsWindows || kIsMacOS ? kPt28 : EdgeInsets.zero,
bottom: false,
child: RequestsPage(
innerDrawerKey: innerDrawerKey,
@ -113,7 +114,7 @@ class _MobileDashboardState extends ConsumerState<MobileDashboard> {
),
),
),
if (!isLargeMobile)
if (context.isCompactWindow)
AnimatedPositioned(
bottom: isLeftDrawerOpen
? 0

View File

@ -1,7 +1,8 @@
import 'package:apidash/providers/ui_providers.dart';
import 'package:apidash/screens/mobile/widgets/page_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:apidash/extensions/context_extensions.dart';
import 'package:apidash/providers/ui_providers.dart';
import 'package:apidash/screens/mobile/widgets/page_base.dart';
import '../settings_page.dart';
import '../intro_page.dart';
@ -183,67 +184,76 @@ Widget customNavigationDestination(
Function()? onTap,
}) {
bool isSelected = railIdx == buttonIdx;
return Tooltip(
message: label,
triggerMode: TooltipTriggerMode.longPress,
verticalOffset: 42,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: isSelected
? null
: () {
if (!isNavigator) {
ref.read(navRailIndexStateProvider.notifier).state = buttonIdx;
}
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
: () {
if (!isNavigator) {
ref.read(navRailIndexStateProvider.notifier).state =
buttonIdx;
}
onTap?.call();
},
child: Icon(
isSelected ? selectedIcon : icon,
return TooltipVisibility(
visible: context.isCompactWindow,
child: Tooltip(
message: label,
triggerMode: TooltipTriggerMode.longPress,
verticalOffset: 42,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: isSelected
? null
: () {
if (!isNavigator) {
ref.read(navRailIndexStateProvider.notifier).state =
buttonIdx;
}
onTap?.call();
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Ink(
width: 65,
height: 32,
decoration: BoxDecoration(
color: isSelected
? Theme.of(context).colorScheme.onSecondaryContainer
: Theme.of(context).colorScheme.onSurface.withOpacity(0.65),
? Theme.of(context).colorScheme.secondaryContainer
: Colors.transparent,
borderRadius: BorderRadius.circular(30),
),
child: InkWell(
borderRadius: BorderRadius.circular(30),
onTap: isSelected
? null
: () {
if (!isNavigator) {
ref.read(navRailIndexStateProvider.notifier).state =
buttonIdx;
}
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(),
],
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(),
],
),
),
),
);

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:apidash/consts.dart';
import '../home_page/editor_pane/details_card/response_pane.dart';
class ResponseDrawer extends StatelessWidget {
@ -6,27 +7,31 @@ class ResponseDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.surface,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
return Container(
padding: kIsWindows || kIsMacOS ? kPt28 : EdgeInsets.zero,
color: Theme.of(context).colorScheme.surface,
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.surface,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_rounded),
onPressed: () {
Navigator.of(context).pop();
},
),
scrolledUnderElevation: 0,
centerTitle: true,
title: const Text("Response"),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_rounded),
onPressed: () {
Navigator.of(context).pop();
},
body: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom,
),
child: const ResponsePane(),
),
scrolledUnderElevation: 0,
centerTitle: true,
title: const Text("Response"),
),
body: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom,
),
child: const ResponsePane(),
),
);
}

View File

@ -1,4 +1,5 @@
import 'package:apidash/consts.dart';
import 'package:apidash/extensions/extensions.dart';
import 'package:apidash/screens/mobile/navbar.dart';
import 'package:flutter/material.dart';
@ -8,9 +9,9 @@ class LeftDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isLargeMobile = MediaQuery.sizeOf(context).width > kLargeMobileWidth;
return Container(
padding: EdgeInsets.only(top: MediaQuery.paddingOf(context).top),
padding: EdgeInsets.only(top: MediaQuery.paddingOf(context).top) +
(kIsWindows || kIsMacOS ? kPt28 : EdgeInsets.zero),
color: Theme.of(context).colorScheme.onInverseSurface,
child: Drawer(
backgroundColor: Colors.transparent,
@ -20,7 +21,7 @@ class LeftDrawer extends StatelessWidget {
child: Container(
padding: EdgeInsets.only(
left: MediaQuery.paddingOf(context).left,
bottom: isLargeMobile
bottom: !context.isCompactWindow
? MediaQuery.paddingOf(context).bottom
: 70 + MediaQuery.paddingOf(context).bottom),
clipBehavior: Clip.hardEdge,
@ -29,7 +30,7 @@ class LeftDrawer extends StatelessWidget {
borderRadius:
const BorderRadius.only(topRight: Radius.circular(8)),
),
child: isLargeMobile
child: !context.isCompactWindow
? Row(
children: [
const NavRail(),

View File

@ -1,26 +1,48 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:apidash/consts.dart';
import 'package:apidash/providers/providers.dart';
import 'package:apidash/widgets/window_caption.dart';
class PageBase extends StatelessWidget {
class PageBase extends ConsumerWidget {
final String title;
final Widget scaffoldBody;
const PageBase({super.key, required this.title, required this.scaffoldBody});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
primary: true,
title: Text(title),
centerTitle: true,
),
body: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom,
Widget build(BuildContext context, WidgetRef ref) {
final isDarkMode =
ref.watch(settingsProvider.select((value) => value.isDark));
return Stack(
children: [
Container(
padding: kIsWindows || kIsMacOS ? kPt28 : EdgeInsets.zero,
color: Theme.of(context).colorScheme.surface,
child: Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
primary: true,
title: Text(title),
centerTitle: true,
),
body: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom,
),
child: scaffoldBody,
),
),
),
child: scaffoldBody,
),
if (kIsWindows)
SizedBox(
height: 29,
child: WindowCaption(
backgroundColor: Colors.transparent,
brightness: isDarkMode ? Brightness.dark : Brightness.light,
),
),
],
);
}
}

View File

@ -17,7 +17,7 @@ class SettingsPage extends ConsumerWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
!context.isMobile
!context.isMediumWindow
? Padding(
padding: kPh20t40,
child: kIsDesktop

View File

@ -30,7 +30,7 @@ class DropdownButtonHttpMethod extends StatelessWidget {
return DropdownMenuItem<HTTPVerb>(
value: value,
child: Padding(
padding: EdgeInsets.only(left: context.isMobile ? 8 : 16),
padding: EdgeInsets.only(left: context.isMediumWindow ? 8 : 16),
child: Text(
value.name.toUpperCase(),
style: kCodeStyle.copyWith(

View File

@ -38,7 +38,7 @@ class IntroMessage extends StatelessWidget {
return CustomMarkdown(
data: text,
padding: !context.isMobile ? kPh60 : kPh20,
padding: !context.isMediumWindow ? kPh60 : kPh20,
);
}
return const Center(child: CircularProgressIndicator());

View File

@ -48,7 +48,7 @@ class _RequestPaneState extends State<RequestPane>
}
return Column(
children: [
context.isMobile
context.isMediumWindow
? const SizedBox.shrink()
: Padding(
padding: kP8,

View File

@ -14,7 +14,7 @@ class TabLabel extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedBox(
height: context.isMobile ? kMobileTabHeight : kTabHeight,
height: context.isMediumWindow ? kMobileTabHeight : kTabHeight,
child: Stack(
children: [
Center(