|
|
… |
4 unchanged lines |
| 5 |
5 |
|
import androidx.compose.material.icons.filled.Book |
| 6 |
6 |
|
import androidx.compose.material.icons.filled.Dashboard |
| 7 |
7 |
|
import androidx.compose.material.icons.filled.Inbox |
|
8 |
+ |
import androidx.compose.material.icons.filled.Search |
| 8 |
9 |
|
import androidx.compose.material.icons.filled.ViewKanban |
| 9 |
10 |
|
import androidx.compose.material.icons.outlined.AccountCircle |
| 10 |
11 |
|
import androidx.compose.material.icons.outlined.Book |
| 11 |
12 |
|
import androidx.compose.material.icons.outlined.Dashboard |
| 12 |
13 |
|
import androidx.compose.material.icons.outlined.Inbox |
|
14 |
+ |
import androidx.compose.material.icons.outlined.Search |
| 13 |
15 |
|
import androidx.compose.material.icons.outlined.ViewKanban |
| 14 |
16 |
|
import androidx.compose.material3.Badge |
| 15 |
17 |
|
import androidx.compose.material3.BadgedBox |
| 16 |
18 |
|
import androidx.compose.material3.Icon |
| 17 |
19 |
|
import androidx.compose.material3.Text |
|
20 |
+ |
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo |
| 18 |
21 |
|
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold |
| 19 |
22 |
|
import androidx.compose.runtime.Composable |
| 20 |
23 |
|
import androidx.compose.runtime.LaunchedEffect |
|
|
… |
14 unchanged lines |
| 35 |
38 |
|
import androidx.navigation.compose.currentBackStackEntryAsState |
| 36 |
39 |
|
import androidx.navigation.compose.rememberNavController |
| 37 |
40 |
|
import androidx.navigation.toRoute |
|
41 |
+ |
import androidx.window.core.layout.WindowSizeClass |
| 38 |
42 |
|
import io.oxygenhub.android.api.HubApi |
| 39 |
43 |
|
import io.oxygenhub.android.auth.Session |
| 40 |
44 |
|
import io.oxygenhub.android.ui.account.AccountScreen |
|
|
… |
79 unchanged lines |
| 120 |
124 |
|
|
| 121 |
125 |
|
@Serializable data class JobLogRoute(val owner: String, val name: String, val number: Long, val job: String) |
| 122 |
126 |
|
|
| 123 |
|
- |
enum class TopLevel(val label: String, val icon: ImageVector, val selectedIcon: ImageVector, val route: Any, val routeClass: KClass<*>) { |
|
127 |
+ |
/** |
|
128 |
+ |
* Where the bar or rail goes. [wide] ones show only when there is room (the |
|
129 |
+ |
* unfolded Fold, a tablet: #14); on a phone the bar keeps its four and they |
|
130 |
+ |
* are reached from the dashboard. |
|
131 |
+ |
*/ |
|
132 |
+ |
enum class TopLevel( |
|
133 |
+ |
val label: String, |
|
134 |
+ |
val icon: ImageVector, |
|
135 |
+ |
val selectedIcon: ImageVector, |
|
136 |
+ |
val route: Any, |
|
137 |
+ |
val routeClass: KClass<*>, |
|
138 |
+ |
val wide: Boolean = false, |
|
139 |
+ |
) { |
| 124 |
140 |
|
Dashboard("Dashboard", Icons.Outlined.Dashboard, Icons.Filled.Dashboard, DashboardRoute, DashboardRoute::class), |
| 125 |
141 |
|
Repositories("Repositories", Icons.Outlined.Book, Icons.Filled.Book, RepositoriesRoute, RepositoriesRoute::class), |
| 126 |
|
- |
Projects("Projects", Icons.Outlined.ViewKanban, Icons.Filled.ViewKanban, ProjectsRoute, ProjectsRoute::class), |
|
142 |
+ |
Projects("Projects", Icons.Outlined.ViewKanban, Icons.Filled.ViewKanban, ProjectsRoute, ProjectsRoute::class, wide = true), |
|
143 |
+ |
Search("Search", Icons.Outlined.Search, Icons.Filled.Search, SearchRoute, SearchRoute::class, wide = true), |
| 127 |
144 |
|
Inbox("Inbox", Icons.Outlined.Inbox, Icons.Filled.Inbox, InboxRoute, InboxRoute::class), |
| 128 |
145 |
|
Account("Account", Icons.Outlined.AccountCircle, Icons.Filled.AccountCircle, AccountRoute, AccountRoute::class), |
| 129 |
146 |
|
} |
|
|
… |
25 unchanged lines |
| 155 |
172 |
|
val entry by nav.currentBackStackEntryAsState() |
| 156 |
173 |
|
val destination = entry?.destination |
| 157 |
174 |
|
|
|
175 |
+ |
val roomy = currentWindowAdaptiveInfo().windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) |
| 158 |
176 |
|
NavigationSuiteScaffold( |
| 159 |
177 |
|
navigationSuiteItems = { |
| 160 |
|
- |
TopLevel.entries.forEach { top -> |
|
178 |
+ |
TopLevel.entries.filter { roomy || !it.wide }.forEach { top -> |
| 161 |
179 |
|
val selected = destination?.hierarchy?.any { it.hasRoute(top.routeClass) } == true |
| 162 |
180 |
|
item( |
| 163 |
181 |
|
selected = selected, |
|
|
… |
25 unchanged lines |
| 189 |
207 |
|
onInbox = { nav.goTo(TopLevel.Inbox) }, |
| 190 |
208 |
|
onOpenProposal = { nav.navigate(ProposalRoute(it.owner, it.name, it.number)) }, |
| 191 |
209 |
|
onSearch = { nav.navigate(SearchRoute) }, |
|
210 |
+ |
onProjects = if (roomy) null else { { nav.navigate(ProjectsRoute) } }, |
| 192 |
211 |
|
) |
| 193 |
212 |
|
} |
| 194 |
213 |
|
composable<SearchRoute> { |
|
|
… |
136 unchanged lines |