Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions client/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -911,10 +911,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
url: "https://pub.dev"
source: hosted
version: "0.12.18"
version: "0.12.19"
material_color_utilities:
dependency: transitive
description:
Expand Down Expand Up @@ -1628,10 +1628,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
url: "https://pub.dev"
source: hosted
version: "0.7.9"
version: "0.7.10"
torch_light:
dependency: transitive
description:
Expand Down
26 changes: 6 additions & 20 deletions packages/flet/lib/src/controls/navigation_drawer.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:flet/src/extensions/control.dart';
import 'package:flutter/material.dart';

import '../models/control.dart';
import '../utils/borders.dart';
import '../utils/colors.dart';
import '../utils/edge_insets.dart';
import '../utils/icons.dart';
import '../utils/numbers.dart';
import 'base_controls.dart';
import 'control_widget.dart';
Expand Down Expand Up @@ -36,7 +36,6 @@ class _NavigationDrawerControlState extends State<NavigationDrawerControl> {
debugPrint("NavigationDrawerControl build: ${widget.control.id}");

var selectedIndex = widget.control.getInt("selected_index", 0)!;

if (_selectedIndex != selectedIndex) {
_selectedIndex = selectedIndex;
}
Expand All @@ -49,31 +48,18 @@ class _NavigationDrawerControlState extends State<NavigationDrawerControl> {
backgroundColor: widget.control.getColor("bgcolor", context),
selectedIndex: _selectedIndex,
shadowColor: widget.control.getColor("shadow_color", context),
tilePadding: parseEdgeInsets(widget.control.get("tile_padding"),
const EdgeInsets.symmetric(horizontal: 12.0))!,
tilePadding: widget.control.getEdgeInsets(
"tile_padding", const EdgeInsets.symmetric(horizontal: 12.0))!,
onDestinationSelected: _destinationChanged,
children: widget.control.children("controls").map((dest) {
dest.notifyParent = true;
if (dest.type == "NavigationDrawerDestination") {
var icon = dest.get("icon");
var selectedIcon = dest.get("selected_icon");

return NavigationDrawerDestination(
enabled: !dest.disabled,
label: dest.buildTextOrWidget("label") ?? const Text(""),
backgroundColor: dest.getColor("bgcolor", context),
icon: icon is Control
? ControlWidget(
control: icon,
)
: Icon(parseIconData(icon, widget.control.backend)),
label: Text(dest.getString("label", "")!),
selectedIcon: selectedIcon is Control
? ControlWidget(
control: selectedIcon,
)
: selectedIcon is int
? Icon(parseIconData(selectedIcon, widget.control.backend))
: null,
icon: dest.buildIconOrWidget("icon", required: true)!,
selectedIcon: dest.buildIconOrWidget("selected_icon"),
);
} else {
return ControlWidget(control: dest);
Expand Down
21 changes: 16 additions & 5 deletions packages/flet/lib/src/extensions/control.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,15 @@ extension WidgetFromControl on Control {
return ControlWidget(key: key, control: c);
}

Widget? buildIconOrWidget(String propertyName,
{bool visibleOnly = true,
bool notifyParent = false,
Key? key,
Color? color}) {
Widget? buildIconOrWidget(
String propertyName, {
bool visibleOnly = true,
bool notifyParent = false,
Key? key,
Color? color,
bool required = false,
Widget? errorWidget,
}) {
var icon = get(propertyName);
if (icon is Control) {
Control? c;
Expand All @@ -54,6 +58,13 @@ extension WidgetFromControl on Control {
// Icon values are stored as raw integers (set_id << 16 | index) in this codebase.
return Icon(getIconData(propertyName), color: color);
}

if (required) {
return errorWidget ??
ErrorControl("Error displaying $type",
description: "$propertyName must be specified");
}

return null;
}

Expand Down
22 changes: 10 additions & 12 deletions packages/flet/lib/src/utils/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -385,18 +385,14 @@ TabBarThemeData? parseTabBarTheme(Map<dynamic, dynamic>? value, ThemeData theme,

VisualDensity? parseVisualDensity(String? density,
[VisualDensity? defaultValue]) {
switch (density?.toLowerCase()) {
case "adaptiveplatformdensity":
return VisualDensity.adaptivePlatformDensity;
case "comfortable":
return VisualDensity.comfortable;
case "compact":
return VisualDensity.compact;
case "standard":
return VisualDensity.standard;
default:
return defaultValue;
}
final visualDensityMap = <String, VisualDensity>{
"adaptiveplatformdensity": VisualDensity.adaptivePlatformDensity,
"comfortable": VisualDensity.comfortable,
"compact": VisualDensity.compact,
"standard": VisualDensity.standard,
};

return visualDensityMap[density?.toLowerCase()] ?? defaultValue;
}

PageTransitionsTheme? parsePageTransitions(Map<dynamic, dynamic>? value,
Expand Down Expand Up @@ -1042,6 +1038,8 @@ NavigationDrawerThemeData? parseNavigationDrawerTheme(
tileHeight: parseDouble(value["tile_height"]),
labelTextStyle: parseWidgetStateTextStyle(value["label_text_style"], theme),
indicatorShape: parseShape(value["indicator_shape"], theme),
iconTheme: getWidgetStateProperty<IconThemeData?>(
value["icon_theme"], (jv) => parseIconTheme(jv, theme)),
);
}

Expand Down
1 change: 1 addition & 0 deletions sdk/python/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ tasks:
aliases:
- docs
cmds:
- cd ../../website && yarn install --immutable
- cd ../../website && yarn start

docs-coverage:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import flet as ft

DESTINATIONS = [
("Messages", ft.Icons.WIDGETS_OUTLINED, ft.Icons.WIDGETS),
("Profile", ft.Icons.FORMAT_PAINT_OUTLINED, ft.Icons.FORMAT_PAINT),
("Settings", ft.Icons.SETTINGS_OUTLINED, ft.Icons.SETTINGS),
]


def main(page: ft.Page):
page.theme_mode = ft.ThemeMode.LIGHT
page.padding = 0

screen_index = 0

def build_page_index_text() -> ft.Text:
return ft.Text(f"Page Index = {screen_index}", size=24)

def set_screen(index: int):
nonlocal screen_index
screen_index = index
render()

def build_navigation_bar() -> ft.NavigationBar:
def handle_nav_bar_change(e: ft.Event[ft.NavigationBar]):
set_screen(e.control.selected_index)

return ft.NavigationBar(
selected_index=screen_index,
on_change=handle_nav_bar_change,
destinations=[
ft.NavigationBarDestination(
label=label,
icon=icon,
selected_icon=selected_icon,
)
for label, icon, selected_icon in DESTINATIONS
],
)

def build_navigation_rail() -> ft.NavigationRail:
def handle_nav_rail_change(e: ft.Event[ft.NavigationRail]):
if e.control.selected_index is not None:
set_screen(e.control.selected_index)

return ft.NavigationRail(
min_width=50,
selected_index=screen_index,
use_indicator=True,
on_change=handle_nav_rail_change,
destinations=[
ft.NavigationRailDestination(
label=label,
icon=icon,
selected_icon=selected_icon,
)
for label, icon, selected_icon in DESTINATIONS
],
)

def build_end_drawer() -> ft.NavigationDrawer:
async def handle_drawer_change(e: ft.Event[ft.NavigationDrawer]):
set_screen(e.control.selected_index)
await page.close_end_drawer()

return ft.NavigationDrawer(
selected_index=screen_index,
on_change=handle_drawer_change,
controls=[
ft.Container(
padding=ft.Padding.only(left=28, top=16, right=16, bottom=10),
content=ft.Text(
"Header", theme_style=ft.TextThemeStyle.TITLE_SMALL
),
),
*[
ft.NavigationDrawerDestination(
label=label,
icon=icon,
selected_icon=selected_icon,
)
for label, icon, selected_icon in DESTINATIONS
],
],
)

def build_bottom_bar_layout() -> ft.SafeArea:
return ft.SafeArea(
expand=True,
content=ft.Container(
expand=True,
alignment=ft.Alignment.CENTER,
content=build_page_index_text(),
),
)

def build_drawer_layout() -> ft.SafeArea:
async def open_drawer(e: ft.Event[ft.Button]):
await page.show_end_drawer()

return ft.SafeArea(
expand=True,
avoid_intrusions_top=False,
avoid_intrusions_bottom=False,
content=ft.Row(
expand=True,
controls=[
ft.Container(
padding=ft.Padding.symmetric(horizontal=5),
content=build_navigation_rail(),
),
ft.VerticalDivider(thickness=1, width=1),
ft.Column(
expand=True,
alignment=ft.MainAxisAlignment.SPACE_EVENLY,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[
build_page_index_text(),
ft.Button("Open Drawer", on_click=open_drawer),
],
),
],
),
)

def render():
page.clean()
if (page.width or page.window.width) >= 450: # wide layout
page.navigation_bar = None
page.end_drawer = build_end_drawer()
page.add(build_drawer_layout())
else: # narrow layout
page.end_drawer = None
page.navigation_bar = build_navigation_bar()
page.add(build_bottom_bar_layout())
page.update()

page.on_resize = lambda e: render()
render()


if __name__ == "__main__":
ft.run(main)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[project]
name = "navigation-drawer-adaptive-navigation"
version = "1.0.0"
description = "Demonstrates adaptive navigation with NavigationBar on narrow layouts and NavigationRail plus NavigationDrawer on wide layouts."
requires-python = ">=3.10"
keywords = ["navigation drawer", "navigation rail", "navigation bar", "adaptive navigation", "responsive"]
authors = [{ name = "Flet team", email = "hello@flet.dev" }]
dependencies = ["flet"]

[dependency-groups]
dev = ["flet-cli", "flet-desktop", "flet-web"]

[tool.flet.gallery]
categories = ["Navigation/NavigationDrawer"]

[tool.flet.metadata]
title = "Adaptive Navigation"
controls = ["NavigationDrawer", "NavigationDrawerDestination", "NavigationRail", "NavigationRailDestination", "NavigationBar", "NavigationBarDestination", "Button", "SafeArea", "Container", "Row", "Column", "VerticalDivider", "Text", "Page"]
layout_pattern = "adaptive-navigation"
complexity = "intermediate"
features = ["responsive layout", "adaptive navigation", "end drawer", "navigation rail", "navigation bar"]

[tool.flet]
org = "dev.flet"
company = "Flet"
copyright = "Copyright (C) 2023-2026 by Flet"
Loading
Loading