2026-06-15 07:23:54 +00:00
<!doctype html>
< html lang = "en" class = "no-js" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width,initial-scale=1" >
< meta name = "description" content = "Documentation for the open source MeshCore firmware" >
< link rel = "canonical" href = "https://meshcore-dev.github.io/meshcore/design/nearby_redesign/" >
< link rel = "prev" href = "../../terminal_chat_cli/" >
2026-06-29 16:02:00 +00:00
< link rel = "next" href = "../solo_ui_framework/" >
2026-06-15 07:23:54 +00:00
< link rel = "icon" href = "../../assets/images/favicon.png" >
2026-07-18 08:11:35 +00:00
< meta name = "generator" content = "mkdocs-1.6.1, mkdocs-material-9.7.7" >
2026-06-15 07:23:54 +00:00
< title > Nearby Nodes — analiza i propozycja uporządkowania - MeshCore Docs</ title >
2026-07-18 08:11:35 +00:00
< link rel = "stylesheet" href = "../../assets/stylesheets/main.ec1eaa64.min.css" >
2026-06-15 07:23:54 +00:00
< link rel = "preconnect" href = "https://fonts.gstatic.com" crossorigin >
< link rel = "stylesheet" href = "https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback" >
< style >: root { --md-text-font : "Roboto" ; --md-code-font : "Roboto Mono" }</ style >
< link rel = "stylesheet" href = "../../_stylesheets/extra.css" >
< script > __md_scope = new URL ( "../.." , location ), __md_hash = e =>[... e ]. reduce ((( e , _ )=>( e << 5 ) - e + _ . charCodeAt ( 0 )), 0 ), __md_get = ( e , _ = localStorage , t = __md_scope )=> JSON . parse ( _ . getItem ( t . pathname + "." + e )), __md_set = ( e , _ , t = localStorage , a = __md_scope )=>{ try { t . setItem ( a . pathname + "." + e , JSON . stringify ( _ ))} catch ( e ){}}</ script >
</ head >
< body dir = "ltr" >
< input class = "md-toggle" data-md-toggle = "drawer" type = "checkbox" id = "__drawer" autocomplete = "off" >
< input class = "md-toggle" data-md-toggle = "search" type = "checkbox" id = "__search" autocomplete = "off" >
< label class = "md-overlay" for = "__drawer" ></ label >
< div data-md-component = "skip" >
< a href = "#nearby-nodes-analiza-i-propozycja-uporzadkowania" class = "md-skip" >
Skip to content
</ a >
</ div >
< div data-md-component = "announce" >
</ div >
< header class = "md-header md-header--shadow" data-md-component = "header" >
< nav class = "md-header__inner md-grid" aria-label = "Header" >
< a href = "../.." title = "MeshCore Docs" class = "md-header__button md-logo" aria-label = "MeshCore Docs" data-md-component = "logo" >
< img src = "../../_assets/meshcore.svg" alt = "logo" >
</ a >
< label class = "md-header__button md-icon" for = "__drawer" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" >< path d = "M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z" /></ svg >
</ label >
< div class = "md-header__title" data-md-component = "header-title" >
< div class = "md-header__ellipsis" >
< div class = "md-header__topic" >
< span class = "md-ellipsis" >
MeshCore Docs
</ span >
</ div >
< div class = "md-header__topic" data-md-component = "header-topic" >
< span class = "md-ellipsis" >
Nearby Nodes — analiza i propozycja uporządkowania
</ span >
</ div >
</ div >
</ div >
< script > var palette = __md_get ( "__palette" ); if ( palette && palette . color ){ if ( "(prefers-color-scheme)" === palette . color . media ){ var media = matchMedia ( "(prefers-color-scheme: light)" ), input = document . querySelector ( media . matches ? "[data-md-color-media='(prefers-color-scheme: light)']" : "[data-md-color-media='(prefers-color-scheme: dark)']" ); palette . color . media = input . getAttribute ( "data-md-color-media" ), palette . color . scheme = input . getAttribute ( "data-md-color-scheme" ), palette . color . primary = input . getAttribute ( "data-md-color-primary" ), palette . color . accent = input . getAttribute ( "data-md-color-accent" )} for ( var [ key , value ] of Object . entries ( palette . color )) document . body . setAttribute ( "data-md-color-" + key , value )}</ script >
< label class = "md-header__button md-icon" for = "__search" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" >< path d = "M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5" /></ svg >
</ label >
< div class = "md-search" data-md-component = "search" role = "dialog" >
< label class = "md-search__overlay" for = "__search" ></ label >
< div class = "md-search__inner" role = "search" >
< form class = "md-search__form" name = "search" >
< input type = "text" class = "md-search__input" name = "query" aria-label = "Search" placeholder = "Search" autocapitalize = "off" autocorrect = "off" autocomplete = "off" spellcheck = "false" data-md-component = "search-query" required >
< label class = "md-search__icon md-icon" for = "__search" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" >< path d = "M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5" /></ svg >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" >< path d = "M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z" /></ svg >
</ label >
< nav class = "md-search__options" aria-label = "Search" >
< button type = "reset" class = "md-search__icon md-icon" title = "Clear" aria-label = "Clear" tabindex = "-1" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" >< path d = "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" /></ svg >
</ button >
</ nav >
< div class = "md-search__suggest" data-md-component = "search-suggest" ></ div >
</ form >
< div class = "md-search__output" >
< div class = "md-search__scrollwrap" tabindex = "0" data-md-scrollfix >
< div class = "md-search-result" data-md-component = "search-result" >
< div class = "md-search-result__meta" >
Initializing search
</ div >
< ol class = "md-search-result__list" role = "presentation" ></ ol >
</ div >
</ div >
</ div >
</ div >
</ div >
< div class = "md-header__source" >
< a href = "https://github.com/meshcore-dev/meshcore/" title = "Go to repository" class = "md-source" data-md-component = "source" >
< div class = "md-source__icon md-icon" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 448 512" > <!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--> < path d = "M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4" /></ svg >
</ div >
< div class = "md-source__repository" >
meshcore-dev/meshcore
</ div >
</ a >
</ div >
</ nav >
</ header >
< div class = "md-container" data-md-component = "container" >
< main class = "md-main" data-md-component = "main" >
< div class = "md-main__inner md-grid" >
< div class = "md-sidebar md-sidebar--primary" data-md-component = "sidebar" data-md-type = "navigation" >
< div class = "md-sidebar__scrollwrap" >
< div class = "md-sidebar__inner" >
< nav class = "md-nav md-nav--primary" aria-label = "Navigation" data-md-level = "0" >
< label class = "md-nav__title" for = "__drawer" >
< a href = "../.." title = "MeshCore Docs" class = "md-nav__button md-logo" aria-label = "MeshCore Docs" data-md-component = "logo" >
< img src = "../../_assets/meshcore.svg" alt = "logo" >
</ a >
MeshCore Docs
</ label >
< div class = "md-nav__source" >
< a href = "https://github.com/meshcore-dev/meshcore/" title = "Go to repository" class = "md-source" data-md-component = "source" >
< div class = "md-source__icon md-icon" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 448 512" > <!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--> < path d = "M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4" /></ svg >
</ div >
< div class = "md-source__repository" >
meshcore-dev/meshcore
</ div >
</ a >
</ div >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "../.." class = "md-nav__link" >
< span class = "md-ellipsis" >
Introduction
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../cli_commands/" class = "md-nav__link" >
< span class = "md-ellipsis" >
CLI Commands
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../companion_protocol/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Companion Protocol
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../docs/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Local Documentation
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../faq/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Frequently Asked Questions
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../kiss_modem_protocol/" class = "md-nav__link" >
< span class = "md-ellipsis" >
MeshCore KISS Modem Protocol
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../nrf52_power_management/" class = "md-nav__link" >
< span class = "md-ellipsis" >
nRF52 Power Management
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../number_allocations/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Number Allocations
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../packet_format/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Packet Format
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../payloads/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Payload Format
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../qr_codes/" class = "md-nav__link" >
< span class = "md-ellipsis" >
QR Codes
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../stats_binary_frames/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Stats Binary Frame Structures
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "../../terminal_chat_cli/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Terminal Chat CLI
</ span >
</ a >
</ li >
< li class = "md-nav__item md-nav__item--active md-nav__item--nested" >
< input class = "md-nav__toggle md-toggle " type = "checkbox" id = "__nav_14" checked >
< label class = "md-nav__link" for = "__nav_14" id = "__nav_14_label" tabindex = "0" >
< span class = "md-ellipsis" >
Design
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< nav class = "md-nav" data-md-level = "1" aria-labelledby = "__nav_14_label" aria-expanded = "true" >
< label class = "md-nav__title" for = "__nav_14" >
< span class = "md-nav__icon md-icon" ></ span >
Design
</ label >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item md-nav__item--active" >
< input class = "md-nav__toggle md-toggle" type = "checkbox" id = "__toc" >
< label class = "md-nav__link md-nav__link--active" for = "__toc" >
< span class = "md-ellipsis" >
Nearby Nodes — analiza i propozycja uporządkowania
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< a href = "./" class = "md-nav__link md-nav__link--active" >
< span class = "md-ellipsis" >
Nearby Nodes — analiza i propozycja uporządkowania
</ span >
</ a >
< nav class = "md-nav md-nav--secondary" aria-label = "Table of contents" >
< label class = "md-nav__title" for = "__toc" >
< span class = "md-nav__icon md-icon" ></ span >
Table of contents
</ label >
< ul class = "md-nav__list" data-md-component = "toc" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "#1-jak-narzedzie-jest-zbudowane-dzisiaj" class = "md-nav__link" >
< span class = "md-ellipsis" >
1. Jak narzędzie jest zbudowane dzisiaj
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#2-co-konkretnie-jest-nieuporzadkowane" class = "md-nav__link" >
< span class = "md-ellipsis" >
2. Co konkretnie jest nieuporządkowane
</ span >
</ a >
< nav class = "md-nav" aria-label = "2. Co konkretnie jest nieuporządkowane" >
< ul class = "md-nav__list" >
< li class = "md-nav__item" >
< a href = "#21-jeden-cykl-filtra-miesza-trzy-rozne-osie" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.1 Jeden cykl filtra miesza trzy różne osie
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#22-te-same-akcje-rozne-menu-w-zaleznosci-od-miejsca" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.2 Te same akcje, różne menu w zależności od miejsca
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#23-hold-enter-znaczy-co-innego-na-kazdym-ekranie" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.3 „Hold Enter” znaczy co innego na każdym ekranie
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#24-_ping_menu-to-bespoke-widget" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.4 _ping_menu to bespoke widget
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#25-duplikacja-listdetailping" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.5 Duplikacja list/detail/ping
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item" >
< a href = "#3-propozycja-uporzadkowania" class = "md-nav__link" >
< span class = "md-ellipsis" >
3. Propozycja uporządkowania
</ span >
</ a >
< nav class = "md-nav" aria-label = "3. Propozycja uporządkowania" >
< ul class = "md-nav__list" >
< li class = "md-nav__item" >
< a href = "#31-rozdziel-filtr-od-sortowania" class = "md-nav__link" >
< span class = "md-ellipsis" >
3.1 Rozdziel filtr od sortowania
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#32-jedno-spojne-menu-akcji-hold-enter-wszedzie" class = "md-nav__link" >
< span class = "md-ellipsis" >
3.2 Jedno spójne menu akcji (Hold Enter wszędzie)
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#33-jedna-lista-dwa-zroda-zapisane-skan-na-zywo" class = "md-nav__link" >
< span class = "md-ellipsis" >
3.3 Jedna lista, dwa źródła (Zapisane / Skan na żywo)
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item" >
< a href = "#4-proponowany-zakres-etapami" class = "md-nav__link" >
< span class = "md-ellipsis" >
4. Proponowany zakres (etapami)
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#5-decyzje-zatwierdzone-2026-06-14" class = "md-nav__link" >
< span class = "md-ellipsis" >
5. Decyzje (zatwierdzone 2026-06-14)
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
2026-06-29 16:02:00 +00:00
< li class = "md-nav__item" >
< a href = "../solo_ui_framework/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Solo UI framework — a guide for adding features
</ span >
</ a >
</ li >
2026-06-15 07:23:54 +00:00
< li class = "md-nav__item" >
< a href = "../trail_redesign/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Trail (Tools › Trail) — analiza i propozycja uporządkowania
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item md-nav__item--nested" >
< input class = "md-nav__toggle md-toggle " type = "checkbox" id = "__nav_15" >
< label class = "md-nav__link" for = "__nav_15" id = "__nav_15_label" tabindex = "0" >
< span class = "md-ellipsis" >
Solo features
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< nav class = "md-nav" data-md-level = "1" aria-labelledby = "__nav_15_label" aria-expanded = "false" >
< label class = "md-nav__title" for = "__nav_15" >
< span class = "md-nav__icon md-icon" ></ span >
Solo features
</ label >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item md-nav__item--nested" >
< input class = "md-nav__toggle md-toggle " type = "checkbox" id = "__nav_15_1" >
< label class = "md-nav__link" for = "__nav_15_1" id = "__nav_15_1_label" tabindex = "0" >
< span class = "md-ellipsis" >
Clock screen
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< nav class = "md-nav" data-md-level = "2" aria-labelledby = "__nav_15_1_label" aria-expanded = "false" >
< label class = "md-nav__title" for = "__nav_15_1" >
< span class = "md-nav__icon md-icon" ></ span >
Clock screen
</ label >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "../../solo_features/clock_screen/clock_screen/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Clock screen
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item md-nav__item--nested" >
< input class = "md-nav__toggle md-toggle " type = "checkbox" id = "__nav_15_2" >
< label class = "md-nav__link" for = "__nav_15_2" id = "__nav_15_2_label" tabindex = "0" >
< span class = "md-ellipsis" >
Favourites dial
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< nav class = "md-nav" data-md-level = "2" aria-labelledby = "__nav_15_2_label" aria-expanded = "false" >
< label class = "md-nav__title" for = "__nav_15_2" >
< span class = "md-nav__icon md-icon" ></ span >
Favourites dial
</ label >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "../../solo_features/favourites_dial/favourites_dial/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Favourites dial
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item md-nav__item--nested" >
< input class = "md-nav__toggle md-toggle " type = "checkbox" id = "__nav_15_3" >
< label class = "md-nav__link" for = "__nav_15_3" id = "__nav_15_3_label" tabindex = "0" >
< span class = "md-ellipsis" >
Message screen
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< nav class = "md-nav" data-md-level = "2" aria-labelledby = "__nav_15_3_label" aria-expanded = "false" >
< label class = "md-nav__title" for = "__nav_15_3" >
< span class = "md-nav__icon md-icon" ></ span >
Message screen
</ label >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "../../solo_features/message_screen/message_screen/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Message screen
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item md-nav__item--nested" >
< input class = "md-nav__toggle md-toggle " type = "checkbox" id = "__nav_15_4" >
< label class = "md-nav__link" for = "__nav_15_4" id = "__nav_15_4_label" tabindex = "0" >
< span class = "md-ellipsis" >
Screen lock
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< nav class = "md-nav" data-md-level = "2" aria-labelledby = "__nav_15_4_label" aria-expanded = "false" >
< label class = "md-nav__title" for = "__nav_15_4" >
< span class = "md-nav__icon md-icon" ></ span >
Screen lock
</ label >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "../../solo_features/screen_lock/screen_lock/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Screen lock
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item md-nav__item--nested" >
< input class = "md-nav__toggle md-toggle " type = "checkbox" id = "__nav_15_5" >
< label class = "md-nav__link" for = "__nav_15_5" id = "__nav_15_5_label" tabindex = "0" >
< span class = "md-ellipsis" >
Settings screen
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< nav class = "md-nav" data-md-level = "2" aria-labelledby = "__nav_15_5_label" aria-expanded = "false" >
< label class = "md-nav__title" for = "__nav_15_5" >
< span class = "md-nav__icon md-icon" ></ span >
Settings screen
</ label >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "../../solo_features/settings_screen/settings_screen/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Settings screen
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item md-nav__item--nested" >
< input class = "md-nav__toggle md-toggle " type = "checkbox" id = "__nav_15_6" >
< label class = "md-nav__link" for = "__nav_15_6" id = "__nav_15_6_label" tabindex = "0" >
< span class = "md-ellipsis" >
Tools screen
</ span >
< span class = "md-nav__icon md-icon" ></ span >
</ label >
< nav class = "md-nav" data-md-level = "2" aria-labelledby = "__nav_15_6_label" aria-expanded = "false" >
< label class = "md-nav__title" for = "__nav_15_6" >
< span class = "md-nav__icon md-icon" ></ span >
Tools screen
</ label >
< ul class = "md-nav__list" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "../../solo_features/tools_screen/tools_screen/" class = "md-nav__link" >
< span class = "md-ellipsis" >
Tools screen
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
</ ul >
</ nav >
</ li >
</ ul >
</ nav >
</ div >
</ div >
</ div >
< div class = "md-sidebar md-sidebar--secondary" data-md-component = "sidebar" data-md-type = "toc" >
< div class = "md-sidebar__scrollwrap" >
< div class = "md-sidebar__inner" >
< nav class = "md-nav md-nav--secondary" aria-label = "Table of contents" >
< label class = "md-nav__title" for = "__toc" >
< span class = "md-nav__icon md-icon" ></ span >
Table of contents
</ label >
< ul class = "md-nav__list" data-md-component = "toc" data-md-scrollfix >
< li class = "md-nav__item" >
< a href = "#1-jak-narzedzie-jest-zbudowane-dzisiaj" class = "md-nav__link" >
< span class = "md-ellipsis" >
1. Jak narzędzie jest zbudowane dzisiaj
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#2-co-konkretnie-jest-nieuporzadkowane" class = "md-nav__link" >
< span class = "md-ellipsis" >
2. Co konkretnie jest nieuporządkowane
</ span >
</ a >
< nav class = "md-nav" aria-label = "2. Co konkretnie jest nieuporządkowane" >
< ul class = "md-nav__list" >
< li class = "md-nav__item" >
< a href = "#21-jeden-cykl-filtra-miesza-trzy-rozne-osie" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.1 Jeden cykl filtra miesza trzy różne osie
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#22-te-same-akcje-rozne-menu-w-zaleznosci-od-miejsca" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.2 Te same akcje, różne menu w zależności od miejsca
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#23-hold-enter-znaczy-co-innego-na-kazdym-ekranie" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.3 „Hold Enter” znaczy co innego na każdym ekranie
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#24-_ping_menu-to-bespoke-widget" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.4 _ping_menu to bespoke widget
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#25-duplikacja-listdetailping" class = "md-nav__link" >
< span class = "md-ellipsis" >
2.5 Duplikacja list/detail/ping
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item" >
< a href = "#3-propozycja-uporzadkowania" class = "md-nav__link" >
< span class = "md-ellipsis" >
3. Propozycja uporządkowania
</ span >
</ a >
< nav class = "md-nav" aria-label = "3. Propozycja uporządkowania" >
< ul class = "md-nav__list" >
< li class = "md-nav__item" >
< a href = "#31-rozdziel-filtr-od-sortowania" class = "md-nav__link" >
< span class = "md-ellipsis" >
3.1 Rozdziel filtr od sortowania
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#32-jedno-spojne-menu-akcji-hold-enter-wszedzie" class = "md-nav__link" >
< span class = "md-ellipsis" >
3.2 Jedno spójne menu akcji (Hold Enter wszędzie)
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#33-jedna-lista-dwa-zroda-zapisane-skan-na-zywo" class = "md-nav__link" >
< span class = "md-ellipsis" >
3.3 Jedna lista, dwa źródła (Zapisane / Skan na żywo)
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ li >
< li class = "md-nav__item" >
< a href = "#4-proponowany-zakres-etapami" class = "md-nav__link" >
< span class = "md-ellipsis" >
4. Proponowany zakres (etapami)
</ span >
</ a >
</ li >
< li class = "md-nav__item" >
< a href = "#5-decyzje-zatwierdzone-2026-06-14" class = "md-nav__link" >
< span class = "md-ellipsis" >
5. Decyzje (zatwierdzone 2026-06-14)
</ span >
</ a >
</ li >
</ ul >
</ nav >
</ div >
</ div >
</ div >
< div class = "md-content" data-md-component = "content" >
< article class = "md-content__inner md-typeset" >
< a href = "https://github.com/meshcore-dev/meshcore/edit/main/docs/design/nearby_redesign.md" title = "Edit this page" class = "md-content__button md-icon" rel = "edit" >
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 24 24" >< path d = "M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4zm10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z" /></ svg >
</ a >
< h1 id = "nearby-nodes-analiza-i-propozycja-uporzadkowania" > Nearby Nodes — analiza i propozycja uporządkowania</ h1 >
< blockquote >
2026-06-15 07:51:36 +00:00
< p > Branch: < code > refactor/nearby-nodes</ code > (zmergowany do < code > main</ code > )
2026-06-15 07:23:54 +00:00
Plik źródłowy: < a href = "../../examples/companion_radio/ui-new/NearbyScreen.h" > NearbyScreen.h</ a >
2026-06-15 07:51:36 +00:00
Status: < strong > zaimplementowane</ strong > — dokument zachowany jako zapis analizy/decyzji.</ p >
< p >< strong > Odchylenia od propozycji (stan faktyczny):</ strong >
- Akcji < strong > Filter…</ strong > w menu nie ma — duplikowała cykl < code > LEFT/RIGHT</ code > po typie, więc
filtr został wyłącznie na liście (sekcja 3.1 zakładała Filter… też w menu).
- < strong > Sort</ strong > nie jest togglem przez Enter, lecz zmienia się < strong > in-place przez
< code > LEFT/RIGHT</ code > na podświetlonym wierszu</ strong > w popupie (wzorzec ustawień Trail),
a wiersz pojawia się tylko dla źródła Zapisane (skan nie ma dystansu).
- Filtr i sort < strong > utrzymują się</ strong > między wejściami na ekran (nie są resetowane).</ p >
2026-06-15 07:23:54 +00:00
</ blockquote >
< hr />
< h2 id = "1-jak-narzedzie-jest-zbudowane-dzisiaj" > 1. Jak narzędzie jest zbudowane dzisiaj</ h2 >
< p > Ekran łączy w sobie < strong > trzy osobne tryby</ strong > o własnych listach, widokach
szczegółów i popupach:</ p >
< pre >< code > NearbyScreen
├── LIST (kontakty zapisane w mesh) ← tryb domyślny
│ ├── filtr cyklowany LEFT/RIGHT (7 stanów)
│ ├── DETAIL (Enter) → Lat/Lon/Dist/Type/Seen
│ │ └── _opts popup (Hold Enter): Navigate / Ping / Save waypoint
│ │ └── _ping_menu popup
│ ├── NAV view (pełnoekranowa nawigacja)
│ └── _ctx_menu popup (Hold Enter): Discover / Navigate / Save waypoint
│
└── DISCOVER (skan na żywo NODE_DISCOVER_REQ) ← osobny pod-ekran
├── lista wyników (karty 2-liniowe)
│ Hold Enter = ponowny skan (brak menu!)
└── DETAIL (Enter) → pubkey / RSSI / SNR / status
└── _ping_menu popup (Hold Enter = od razu ping, bez Options)
</ code ></ pre >
< p > Stan ekranu trzyma < strong > 15+ pól</ strong > (< code > _detail</ code > , < code > _nav</ code > , < code > _discover_mode</ code > ,
< code > _ddetail</ code > , < code > _pinging</ code > , < code > _filter</ code > , dwa komplety < code > _sel/_scroll</ code > , trzy
bufory wyników ping…) i < strong > trzy</ strong > instancje < code > PopupMenu</ code > (< code > _ctx_menu</ code > ,
< code > _opts</ code > , < code > _ping_menu</ code > ).</ p >
< hr />
< h2 id = "2-co-konkretnie-jest-nieuporzadkowane" > 2. Co konkretnie jest nieuporządkowane</ h2 >
< h3 id = "21-jeden-cykl-filtra-miesza-trzy-rozne-osie" > 2.1 Jeden cykl filtra miesza trzy różne osie</ h3 >
< p >< code > LEFT/RIGHT</ code > przewija 7 stanów:</ p >
< pre >< code > Fav · ALL · Comp · Rpt · Room · Snsr · TIME
</ code ></ pre >
< p > Ale to nie jest jedna oś — to < strong > trzy</ strong > wciśnięte w jeden liniowy cykl:</ p >
< table >
< thead >
< tr >
< th > Stan</ th >
< th > Czym naprawdę jest</ th >
</ tr >
</ thead >
< tbody >
< tr >
< td >< code > Fav</ code ></ td >
< td > filtr < strong > ulubionych</ strong > (flaga < code > ci.flags & 1</ code > )</ td >
</ tr >
< tr >
< td >< code > ALL/Comp/Rpt/Room/Snsr</ code ></ td >
< td > filtr < strong > po typie</ strong > węzła</ td >
</ tr >
< tr >
< td >< code > TIME</ code ></ td >
< td >< strong > sortowanie</ strong > (po < code > lastmod</ code > zamiast po dystansie)</ td >
</ tr >
</ tbody >
</ table >
< p > Konsekwencje:
- użytkownik „scrolluje po kategoriach” na ślepo — nie widzi wszystkich
naraz, musi cyklować, by trafić w to, czego szuka;
- < strong > kombinacje są niemożliwe</ strong > : nie da się zobaczyć „ulubionych
repeaterów posortowanych po dystansie" ani „repeaterów posortowanych
po czasie” — model wymusza dokładnie jeden stan z siedmiu;
- < code > TIME</ code > jako „filtr" jest mylące — zmienia kolejność, nie zawartość;
- etykieta w nagłówku (< code > NEARBY[TIME]</ code > ) nie mówi, że to sort.</ p >
< h3 id = "22-te-same-akcje-rozne-menu-w-zaleznosci-od-miejsca" > 2.2 Te same akcje, różne menu w zależności od miejsca</ h3 >
< table >
< thead >
< tr >
< th > Akcja</ th >
< th style = "text-align: center;" > Lista (< code > _ctx_menu</ code > )</ th >
< th style = "text-align: center;" > Detail kontaktu (< code > _opts</ code > )</ th >
< th style = "text-align: center;" > Detail discover</ th >
</ tr >
</ thead >
< tbody >
< tr >
< td > Navigate</ td >
< td style = "text-align: center;" > ✓</ td >
< td style = "text-align: center;" > ✓</ td >
< td style = "text-align: center;" > —</ td >
</ tr >
< tr >
< td > Save waypoint</ td >
< td style = "text-align: center;" > ✓</ td >
< td style = "text-align: center;" > ✓</ td >
< td style = "text-align: center;" > —</ td >
</ tr >
< tr >
< td > Ping</ td >
< td style = "text-align: center;" > —</ td >
< td style = "text-align: center;" > ✓</ td >
< td style = "text-align: center;" > ✓</ td >
</ tr >
< tr >
< td > Discover</ td >
< td style = "text-align: center;" > ✓</ td >
< td style = "text-align: center;" > —</ td >
< td style = "text-align: center;" > —</ td >
</ tr >
</ tbody >
</ table >
< p > Ten sam węzeł oferuje inny zestaw akcji w zależności od tego, gdzie na
niego patrzysz. Ping jest osiągalny tylko ze szczegółów, Discover tylko
z listy.</ p >
< h3 id = "23-hold-enter-znaczy-co-innego-na-kazdym-ekranie" > 2.3 „Hold Enter” znaczy co innego na każdym ekranie</ h3 >
< table >
< thead >
< tr >
< th > Ekran</ th >
< th > Hold Enter (< code > KEY_CONTEXT_MENU</ code > )</ th >
</ tr >
</ thead >
< tbody >
< tr >
< td > Lista nearby</ td >
< td > otwiera menu kontekstowe</ td >
</ tr >
< tr >
< td > Detail kontaktu</ td >
< td > otwiera menu Options</ td >
</ tr >
< tr >
< td > Lista discover</ td >
< td >< strong > ponowny skan</ strong > (żadnego menu)</ td >
</ tr >
< tr >
< td > Detail discover</ td >
< td >< strong > od razu Ping</ strong > (pomija Options)</ td >
</ tr >
</ tbody >
</ table >
< p > Brak spójnego modelu „przytrzymaj = menu akcji”.</ p >
< h3 id = "24-_ping_menu-to-bespoke-widget" > 2.4 < code > _ping_menu</ code > to bespoke widget</ h3 >
< p > W przeciwieństwie do reszty popupów, ping-menu:
- ma wiersze tylko-do-odczytu (RTT / SNR), więc połyka < code > UP/DOWN</ code > ;
- przebudowuje się w trakcie (< code > rebuildPingMenu</ code > ) gdy przychodzą wyniki;
- zostaje otwarte po < code > SELECTED</ code > (reszta popupów się zamyka);
- ma własny < code > handlePingMenuInput</ code > z trybem < code > allow_enter_to_open</ code > .</ p >
< p > To działa, ale jest to czwarty, niestandardowy wzorzec interakcji w
jednym narzędziu.</ p >
< h3 id = "25-duplikacja-listdetailping" > 2.5 Duplikacja list/detail/ping</ h3 >
< p >< code > renderDiscover</ code > /< code > handleInputDiscover</ code > /< code > renderDiscoverDetail</ code > to niemal
równoległa kopia logiki listy i szczegółów nearby (osobne < code > _dsel</ code > ,
< code > _dscroll</ code > , < code > _d_visible</ code > , własne rysowanie kart). Discover i Nearby
robią to samo — pokazują listę węzłów z możliwością wejścia w szczegóły
i pingowania — ale dwoma osobnymi ścieżkami kodu.</ p >
< hr />
< h2 id = "3-propozycja-uporzadkowania" > 3. Propozycja uporządkowania</ h2 >
< p > Trzy zasady przewodnie: < strong > (a) jedno menu akcji wszędzie</ strong > , < strong > (b) filtr
i sortowanie jako osobne, jawne osie</ strong > , < strong > (c) jeden wzorzec listy</ strong > .</ p >
< h3 id = "31-rozdziel-filtr-od-sortowania" > 3.1 Rozdziel filtr od sortowania</ h3 >
< p > Zamiast jednego cyklu 7-stanowego — dwie niezależne osie wybierane z
menu (nie przez ślepe cyklowanie):</ p >
< p >< strong > Filtr</ strong > (oś „co pokazujemy") i < strong > sort</ strong > (oś „w jakiej kolejności") są
od siebie niezależne i < strong > łączą się dowolnie</ strong > :</ p >
< pre >< code > FILTR (jedna oś — typ węzła, z Ulubionymi) SORT (przełącznik)
• Wszystkie • Dystans (domyślnie)
• Ulubione • Ostatnio słyszane
• Companion
• Repeater
• Room
• Sensor
</ code ></ pre >
< p >< strong > Sterowanie (zatwierdzone):</ strong >
- < code > LEFT/RIGHT</ code > = szybki cykl < strong > tylko po filtrze-typie</ strong > (jedna spójna oś,
znany gest; bez „TIME" zanieczyszczającego cykl);
- < strong > Sort</ strong > = przełącznik w menu akcji (< code > Dystans ↔ Ostatnio słyszane</ code > ),
trzymany niezależnie od filtra;
- < strong > Filter…</ strong > dostępny też w menu akcji (odkrywalność — cała lista
widoczna naraz, nie tylko cyklowanie).</ p >
< p > Dzięki temu „ulubione repeatery po dystansie" staje się możliwe, a w
nagłówku widać oba wymiary, np. < code > NEARBY · Rpt · ↓dist</ code > .</ p >
< h3 id = "32-jedno-spojne-menu-akcji-hold-enter-wszedzie" > 3.2 Jedno spójne menu akcji (Hold Enter wszędzie)</ h3 >
< p > Jeden < code > PopupMenu</ code > (zamiast < code > _ctx_menu</ code > + < code > _opts</ code > ), pozycje zależne od
kontekstu, ale < strong > kolejność i nazwy stałe</ strong > :</ p >
< pre >< code > Hold Enter → Options
• Navigate (gdy węzeł ma GPS)
• Ping (gdy znamy pubkey)
• Save waypoint (gdy węzeł ma GPS)
──────────────
• Filter… (podmenu z 3.1)
• Sort… (toggle z 3.1)
• Discover scan (uruchamia skan na żywo = przełącza źródło)
</ code ></ pre >
< p > To samo menu na liście i w szczegółach, w obu źródłach (Zapisane /
Skan). Pozycje niedostępne są pomijane (jak już teraz robi < code > has_node</ code > ),
ale nigdy nie zmieniają kolejności ani nazw. „Hold Enter = menu akcji" —
bez wyjątków. Ping zawsze przez Options (znika „od razu Ping" z detalu
Discover); rescan to pozycja menu, nie ukryty Hold Enter.</ p >
< h3 id = "33-jedna-lista-dwa-zroda-zapisane-skan-na-zywo" > 3.3 Jedna lista, dwa źródła (Zapisane / Skan na żywo)</ h3 >
< p >< strong > Zatwierdzone:</ strong > zamiast osobnego pod-ekranu Discover — < strong > jeden
komponent</ strong > listy/szczegółów/menu/ping napędzany przełącznikiem
< strong > źródła</ strong > :</ p >
< ul >
< li > ta sama nawigacja, to samo menu akcji, ten sam wzorzec szczegółów i
pingu (znika duplikacja < code > renderDiscover*</ code > , niespójne Hold Enter i
połowa pól stanu);</ li >
< li > różni się tylko < strong > prawa kolumna</ strong > wiersza i pola w detalu:</ li >
< li > źródło < strong > Zapisane</ strong > → dystans / azymut / lastmod (jak dziś),</ li >
< li > źródło < strong > Skan na żywo</ strong > → RSSI / SNR (dane z < code > DiscoverResult</ code > ).</ li >
</ ul >
< p > To nie jest dosłowne zlanie dwóch list w jedną tablicę (dane mają różny
kształt — kontakt ma GPS, wynik skanu ma sygnał), tylko < strong > jedna ścieżka
interakcji nad dwoma źródłami</ strong > . Wybór źródła = „Discover scan" w menu
(uruchamia < code > NODE_DISCOVER_REQ</ code > i przełącza widok na wyniki) oraz powrót
do Zapisanych przez Cancel.</ p >
< hr />
< h2 id = "4-proponowany-zakres-etapami" > 4. Proponowany zakres (etapami)</ h2 >
< table >
< thead >
< tr >
< th > Etap</ th >
< th > Zmiana</ th >
< th style = "text-align: center;" > Ryzyko</ th >
</ tr >
</ thead >
< tbody >
< tr >
< td > 1</ td >
< td > Rozdziel sort od filtra: < code > TIME</ code > znika z cyklu; < code > LEFT/RIGHT</ code > cyklują tylko typ+Fav; sort jako stan + toggle</ td >
< td style = "text-align: center;" > niskie</ td >
</ tr >
< tr >
< td > 2</ td >
< td > Scal < code > _ctx_menu</ code > i < code > _opts</ code > w jedno menu akcji o stałej kolejności; dodaj Filter…/Sort…</ td >
< td style = "text-align: center;" > niskie</ td >
</ tr >
< tr >
< td > 3</ td >
< td > Ujednolić Hold Enter w Discover (menu zamiast bezpośredniego rescan/ping; Ping zawsze przez Options)</ td >
< td style = "text-align: center;" > średnie</ td >
</ tr >
< tr >
< td > 4</ td >
< td > Scal listę Discover z listą Nearby w jeden komponent z przełącznikiem źródła</ td >
< td style = "text-align: center;" > wyższe</ td >
</ tr >
</ tbody >
</ table >
< p > Kolejność implementacji: 1 → 2 → 3 → 4. Etapy 1– 2 dają największą
poprawę „uporządkowania" przy najmniejszym ryzyku; 3– 4 domykają
spójność (jedna lista, jedno menu wszędzie).</ p >
< hr />
< h2 id = "5-decyzje-zatwierdzone-2026-06-14" > 5. Decyzje (zatwierdzone 2026-06-14)</ h2 >
< ol >
< li >< strong > Filtr i sort — pełne rozdzielenie osi.</ strong > < code > LEFT/RIGHT</ code > = szybki cykl
filtra-typu; Sort jako toggle w menu; Filter… też w menu dla
odkrywalności. (Nie chowamy wszystkiego do menu — zachowujemy szybki
gest.)</ li >
< li >< strong > Discover — jedna lista, dwa źródła.</ strong > Wspólny komponent
interakcji; różni się tylko prawa kolumna/pola detalu (dystans vs
sygnał).</ li >
</ ol >
</ article >
</ div >
< script > var target = document . getElementById ( location . hash . slice ( 1 )); target && target . name && ( target . checked = target . name . startsWith ( "__tabbed_" ))</ script >
</ div >
</ main >
< footer class = "md-footer" >
< div class = "md-footer-meta md-typeset" >
< div class = "md-footer-meta__inner md-grid" >
< div class = "md-copyright" >
Made with
< a href = "https://squidfunk.github.io/mkdocs-material/" target = "_blank" rel = "noopener" >
Material for MkDocs
</ a >
</ div >
</ div >
</ div >
</ footer >
</ div >
< div class = "md-dialog" data-md-component = "dialog" >
< div class = "md-dialog__inner md-typeset" ></ div >
</ div >
< script id = "__config" type = "application/json" >{ "annotate" : null , "base" : "../.." , "features" : [ "content.action.edit" , "content.code.copy" , "search.highlight" , "search.suggest" ], "search" : "../../assets/javascripts/workers/search.2c215733.min.js" , "tags" : null , "translations" : { "clipboard.copied" : "Copied to clipboard" , "clipboard.copy" : "Copy to clipboard" , "search.result.more.one" : "1 more on this page" , "search.result.more.other" : "# more on this page" , "search.result.none" : "No matching documents" , "search.result.one" : "1 matching document" , "search.result.other" : "# matching documents" , "search.result.placeholder" : "Type to start searching" , "search.result.term.missing" : "Missing" , "select.version" : "Select version" }, "version" : null }</ script >
2026-07-18 08:11:35 +00:00
< script src = "../../assets/javascripts/bundle.d7400e89.min.js" ></ script >
2026-06-15 07:23:54 +00:00
</ body >
</ html >