Adapt layout for wide screens and tablets
- Switch navigation breakpoint from orientation to width (≥600dp): NavigationRail shown on tablets in portrait and phones in landscape - Chat bubble max-width capped at 480dp (prevents 640dp+ bubbles on tablets) - Chat input maxLines reduced to 2 when width ≥600dp - Task edit form centered and constrained to 600dp max-width on tablets Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -144,6 +144,51 @@ class _Shell extends ConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final location = GoRouterState.of(context).matchedLocation;
|
final location = GoRouterState.of(context).matchedLocation;
|
||||||
final index = _tabIndex(location);
|
final index = _tabIndex(location);
|
||||||
|
// Use NavigationRail whenever the screen is wide enough — covers both
|
||||||
|
// phone landscape and tablets in either orientation (600 dp breakpoint).
|
||||||
|
final isWide = MediaQuery.of(context).size.width >= 600;
|
||||||
|
|
||||||
|
if (isWide) {
|
||||||
|
return Scaffold(
|
||||||
|
body: SafeArea(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const _QuickCaptureBar(),
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
NavigationRail(
|
||||||
|
selectedIndex: index,
|
||||||
|
onDestinationSelected: (i) => context.go(_tabs[i]),
|
||||||
|
labelType: NavigationRailLabelType.all,
|
||||||
|
destinations: const [
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: Icon(Icons.note_outlined),
|
||||||
|
selectedIcon: Icon(Icons.note),
|
||||||
|
label: Text('Notes'),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: Icon(Icons.check_box_outlined),
|
||||||
|
selectedIcon: Icon(Icons.check_box),
|
||||||
|
label: Text('Tasks'),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: Icon(Icons.chat_bubble_outline),
|
||||||
|
selectedIcon: Icon(Icons.chat_bubble),
|
||||||
|
label: Text('Chat'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const VerticalDivider(width: 1),
|
||||||
|
Expanded(child: child),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Column(
|
body: Column(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math' show min;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@@ -122,7 +124,8 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
|||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding: EdgeInsets.symmetric(
|
||||||
horizontal: 12, vertical: 10),
|
horizontal: 12, vertical: 10),
|
||||||
),
|
),
|
||||||
maxLines: 4,
|
maxLines:
|
||||||
|
MediaQuery.of(context).size.width >= 600 ? 2 : 4,
|
||||||
minLines: 1,
|
minLines: 1,
|
||||||
textInputAction: TextInputAction.newline,
|
textInputAction: TextInputAction.newline,
|
||||||
enabled: !isStreaming,
|
enabled: !isStreaming,
|
||||||
@@ -163,7 +166,7 @@ class _MessageBubble extends StatelessWidget {
|
|||||||
alignment: isUser ? Alignment.centerRight : Alignment.centerLeft,
|
alignment: isUser ? Alignment.centerRight : Alignment.centerLeft,
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxWidth: MediaQuery.of(context).size.width * 0.8,
|
maxWidth: min(MediaQuery.of(context).size.width * 0.8, 480),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.symmetric(vertical: 4),
|
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
|||||||
@@ -147,10 +147,14 @@ class _TaskEditScreenState extends ConsumerState<TaskEditScreen> {
|
|||||||
),
|
),
|
||||||
body: snapshot.connectionState == ConnectionState.waiting
|
body: snapshot.connectionState == ConnectionState.waiting
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: Form(
|
: Align(
|
||||||
key: _formKey,
|
alignment: Alignment.topCenter,
|
||||||
child: ListView(
|
child: ConstrainedBox(
|
||||||
padding: const EdgeInsets.all(16),
|
constraints: const BoxConstraints(maxWidth: 600),
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: ListView(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
children: [
|
children: [
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _titleController,
|
controller: _titleController,
|
||||||
@@ -215,6 +219,8 @@ class _TaskEditScreenState extends ConsumerState<TaskEditScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user