Skip to content

Commit

Permalink
[Calendar] Removes bottom nav bar
Browse files Browse the repository at this point in the history
This commit removes the bottom nav bar from all views and adds a new
floating action button to handle event creation.
To allow navigation between views without a bottom navbar, a
calendar icon has been added on the top right.

Co-authored-by: mup <34790144+murilopereirame@users.noreply.github.com>
  • Loading branch information
andrehgdias and murilopereirame committed Aug 16, 2024
1 parent 124c3c3 commit 1e7365c
Show file tree
Hide file tree
Showing 20 changed files with 230 additions and 644 deletions.
8 changes: 2 additions & 6 deletions src/calendar-app/calendar-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import { SettingsViewAttrs } from "../common/settings/Interfaces.js"
import { CalendarSearchView, CalendarSearchViewAttrs } from "./calendar/search/view/CalendarSearchView.js"
import { CalendarSettingsView } from "./calendar/settings/CalendarSettingsView.js"
import { CalendarSearchViewModel } from "./calendar/search/view/CalendarSearchViewModel.js"

import { AppType } from "../common/misc/ClientConstants.js"

assertMainOrNodeBoot()
Expand Down Expand Up @@ -132,7 +131,6 @@ import("../mail-app/translations/en.js")
}

styles.init(calendarLocator.themeController)
const { CalendarBottomNav } = await import("./gui/CalendarBottomNav.js")
const paths = applicationPaths({
login: makeViewResolver<LoginViewAttrs, LoginView, { makeViewModel: () => LoginViewModel }>(
{
Expand Down Expand Up @@ -221,7 +219,7 @@ import("../mail-app/translations/en.js")
calendar: makeViewResolver<
CalendarViewAttrs,
CalendarView,
{ drawerAttrsFactory: () => DrawerMenuAttrs; header: AppHeaderAttrs; calendarViewModel: CalendarViewModel; bottomNav: () => Children }
{ drawerAttrsFactory: () => DrawerMenuAttrs; header: AppHeaderAttrs; calendarViewModel: CalendarViewModel }
>(
{
prepareRoute: async (cache) => {
Expand All @@ -233,15 +231,13 @@ import("../mail-app/translations/en.js")
drawerAttrsFactory,
header: await calendarLocator.appHeaderAttrs(),
calendarViewModel: await calendarLocator.calendarViewModel(),
bottomNav: () => m(CalendarBottomNav),
},
}
},
prepareAttrs: ({ header, calendarViewModel, drawerAttrsFactory, bottomNav }) => ({
prepareAttrs: ({ header, calendarViewModel, drawerAttrsFactory }) => ({
drawerAttrs: drawerAttrsFactory(),
header,
calendarViewModel,
bottomNav,
}),
},
calendarLocator.logins,
Expand Down
128 changes: 74 additions & 54 deletions src/calendar-app/calendar/search/view/CalendarSearchView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { lang, TranslationKey } from "../../../../common/misc/LanguageViewModel.
import { BackgroundColumnLayout } from "../../../../common/gui/BackgroundColumnLayout.js"
import { theme } from "../../../../common/gui/theme.js"
import { DesktopListToolbar, DesktopViewerToolbar } from "../../../../common/gui/DesktopToolbars.js"
import { SearchListView, CalendarSearchListViewAttrs } from "./SearchListView.js"
import { CalendarSearchListViewAttrs, SearchListView } from "./SearchListView.js"
import { isSameId } from "../../../../common/api/common/utils/EntityUtils.js"
import { keyManager, Shortcut } from "../../../../common/misc/KeyManager.js"
import { EnterMultiselectIconButton } from "../../../../common/gui/EnterMultiselectIconButton.js"
Expand Down Expand Up @@ -50,15 +50,18 @@ import { MultiselectMode } from "../../../../common/gui/base/List.js"
import { ClickHandler } from "../../../../common/gui/base/GuiUtils.js"
import { showProgressDialog } from "../../../../common/gui/dialogs/ProgressDialog.js"
import { CalendarOperation } from "../../gui/eventeditor-model/CalendarEventModel.js"
import { getEventWithDefaultTimes } from "../../../../common/api/common/utils/CommonCalendarUtils.js"
import { getEventWithDefaultTimes, setNextHalfHour } from "../../../../common/api/common/utils/CommonCalendarUtils.js"
import { showNewCalendarEventEditDialog } from "../../gui/eventeditor-view/CalendarEventEditDialog.js"
import { getSharedGroupName } from "../../../../common/sharing/GroupUtils.js"
import { CalendarInfo } from "../../model/CalendarModel.js"
import { Checkbox, CheckboxAttrs } from "../../../../common/gui/base/Checkbox.js"
import { MobileActionAttrs, MobileActionBar } from "../../../../common/gui/MobileActionBar.js"
import { assertMainOrNode } from "../../../../common/api/common/Env.js"
import { CalendarBottomNav } from "../../../gui/CalendarBottomNav.js"
import { assertMainOrNode, isApp } from "../../../../common/api/common/Env.js"
import { calendarLocator } from "../../../calendarLocator.js"
import { client } from "../../../../common/misc/ClientDetector.js"
import { FloatingActionButton } from "../../../gui/FloatingActionButton.js"
import { CALENDAR_PREFIX } from "../../../../common/misc/RouteChange.js"
import { ButtonColor } from "../../../../common/gui/base/Button.js"

assertMainOrNode()

Expand Down Expand Up @@ -137,6 +140,7 @@ export class CalendarSearchView extends BaseTopLevelView implements TopLevelView
desktopToolbar: () => m(DesktopListToolbar, [m(".button-height")]),
mobileHeader: () => this.renderMobileListHeader(vnode.attrs.header),
columnLayout: this.getResultColumnLayout(),
floatingActionButton: this.renderFab.bind(this),
})
},
},
Expand All @@ -160,6 +164,19 @@ export class CalendarSearchView extends BaseTopLevelView implements TopLevelView
this.viewSlider = new ViewSlider([this.folderColumn, this.resultListColumn, this.resultDetailsColumn])
}

private renderFab(): Children {
if (client.isCalendarApp()) {
return m(FloatingActionButton, {
icon: Icons.Add,
title: "newEvent_action",
colors: ButtonColor.Fab,
action: () => this.createNewEventDialog(),
})
}

return null
}

private getResultColumnLayout() {
return m(SearchListView, {
listModel: this.searchViewModel.listModel,
Expand Down Expand Up @@ -196,14 +213,6 @@ export class CalendarSearchView extends BaseTopLevelView implements TopLevelView
private renderMobileListActionsHeader(header: AppHeaderAttrs) {
const rightActions = []

rightActions.push(
m(EnterMultiselectIconButton, {
clickAction: () => {
this.searchViewModel.listModel?.enterMultiselect()
},
}),
)

if (styles.isSingleColumnLayout()) {
rightActions.push(this.renderHeaderRightView())
}
Expand Down Expand Up @@ -259,6 +268,7 @@ export class CalendarSearchView extends BaseTopLevelView implements TopLevelView
: !this.getSanitizedPreviewData(selectedEvent).isLoaded()
? null
: this.renderEventDetails(selectedEvent),
floatingActionButton: this.renderFab.bind(this),
})
}

Expand All @@ -281,48 +291,49 @@ export class CalendarSearchView extends BaseTopLevelView implements TopLevelView
)
}

private renderBottomNav() {
if (!styles.isSingleColumnLayout()) return m(CalendarBottomNav)
private renderSearchResultActions() {
if (this.viewSlider.focusedColumn !== this.resultDetailsColumn) return null

const isInMultiselect = this.searchViewModel.listModel?.state.inMultiselect ?? false

if (this.viewSlider.focusedColumn === this.resultDetailsColumn) {
const selectedEvent = this.searchViewModel.getSelectedEvents()[0]
if (!selectedEvent) {
this.viewSlider.focus(this.resultListColumn)
return m(MobileActionBar, { actions: [] })
const selectedEvent = this.searchViewModel.getSelectedEvents()[0]
if (!selectedEvent) {
this.viewSlider.focus(this.resultListColumn)
return m(MobileActionBar, { actions: [] })
}
const previewModel = this.getSanitizedPreviewData(selectedEvent).getSync()
const actions: Array<MobileActionAttrs> = []
if (previewModel) {
if (previewModel.canSendUpdates) {
actions.push({
icon: BootIcons.Mail,
title: "sendUpdates_label",
action: () => handleSendUpdatesClick(previewModel),
})
}
const previewModel = this.getSanitizedPreviewData(selectedEvent).getSync()
const actions: Array<MobileActionAttrs> = []
if (previewModel) {
if (previewModel.canSendUpdates) {
actions.push({
icon: BootIcons.Mail,
title: "sendUpdates_label",
action: () => handleSendUpdatesClick(previewModel),
})
}
if (previewModel.canEdit) {
actions.push({
icon: Icons.Edit,
title: "edit_action",
action: (ev: MouseEvent, receiver: HTMLElement) => handleEventEditButtonClick(previewModel, ev, receiver),
})
}
if (previewModel.canDelete) {
actions.push({
icon: Icons.Trash,
title: "delete_action",
action: (ev: MouseEvent, receiver: HTMLElement) => handleEventDeleteButtonClick(previewModel, ev, receiver),
})
}
} else {
this.getSanitizedPreviewData(selectedEvent).load()
if (previewModel.canEdit) {
actions.push({
icon: Icons.Edit,
title: "edit_action",
action: (ev: MouseEvent, receiver: HTMLElement) => handleEventEditButtonClick(previewModel, ev, receiver),
})
}
if (previewModel.canDelete) {
actions.push({
icon: Icons.Trash,
title: "delete_action",
action: (ev: MouseEvent, receiver: HTMLElement) => handleEventDeleteButtonClick(previewModel, ev, receiver),
})
}
return m(MobileActionBar, { actions })
} else {
this.getSanitizedPreviewData(selectedEvent).load()
}

return m(CalendarBottomNav)
return actions.map((action) =>
m(IconButton, {
title: action.title,
icon: action.icon,
click: action.action,
}),
)
}

private searchBarPlaceholder() {
Expand All @@ -340,14 +351,24 @@ export class CalendarSearchView extends BaseTopLevelView implements TopLevelView
}

private renderHeaderRightView(): Children {
const restriction = this.searchViewModel.getRestriction()

if (styles.isUsingBottomNavigation()) {
if (styles.isUsingBottomNavigation() && !client.isCalendarApp()) {
return m(IconButton, {
click: () => this.createNewEventDialog(),
title: "newEvent_action",
icon: Icons.Add,
})
} else if (client.isCalendarApp()) {
return m.fragment({}, [
this.renderSearchResultActions(),
m(NavButton, {
label: "calendar_label",
hideLabel: true,
icon: () => BootIcons.Calendar,
href: CALENDAR_PREFIX,
centred: true,
fillSpaceAround: false,
}),
])
}
}

Expand Down Expand Up @@ -434,7 +455,7 @@ export class CalendarSearchView extends BaseTopLevelView implements TopLevelView
}

private async createNewEventDialog(): Promise<void> {
const dateToUse = this.searchViewModel.startDate ?? new Date()
const dateToUse = this.searchViewModel.startDate ? setNextHalfHour(new Date(this.searchViewModel.startDate)) : setNextHalfHour(new Date())

// Disallow creation of events when there is no existing calendar
const lazyCalendarInfo = this.searchViewModel.getLazyCalendarInfos()
Expand Down Expand Up @@ -520,7 +541,6 @@ export class CalendarSearchView extends BaseTopLevelView implements TopLevelView
}),
...attrs.header,
}),
bottomNav: this.renderBottomNav(),
}),
)
}
Expand Down
15 changes: 11 additions & 4 deletions src/calendar-app/calendar/settings/CalendarSettingsView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ import { ReferralSettingsViewer } from "../../../common/settings/ReferralSetting
import { GroupDetailsView } from "../../../common/settings/groups/GroupDetailsView.js"
import { TemplateDetailsViewer } from "../../../mail-app/settings/TemplateDetailsViewer.js"
import { KnowledgeBaseSettingsDetailsViewer } from "../../../mail-app/settings/KnowledgeBaseListView.js"
import { NavButtonAttrs, NavButtonColor } from "../../../common/gui/base/NavButton.js"
import { NavButton, NavButtonAttrs, NavButtonColor } from "../../../common/gui/base/NavButton.js"
import { CustomerInfoTypeRef, CustomerTypeRef, User } from "../../../common/api/entities/sys/TypeRefs.js"
import { Dialog } from "../../../common/gui/base/Dialog.js"
import { AboutDialog } from "../../../common/settings/AboutDialog.js"
import { SettingsViewAttrs, UpdatableSettingsDetailsViewer, UpdatableSettingsViewer } from "../../../common/settings/Interfaces.js"
import { NotificationSettingsViewer } from "./NotificationSettingsViewer.js"
import { GlobalSettingsViewer } from "./GlobalSettingsViewer.js"
import { CalendarBottomNav } from "../../gui/CalendarBottomNav.js"
import { calendarLocator } from "../../calendarLocator.js"
import { locator } from "../../../common/api/main/CommonLocator.js"
import { CALENDAR_PREFIX } from "../../../common/misc/RouteChange.js"

assertMainOrNode()

Expand Down Expand Up @@ -153,7 +153,15 @@ export class CalendarSettingsView extends BaseTopLevelView implements TopLevelVi
columnType: "first",
title: lang.getMaybeLazy(this._selectedFolder.name),
actions: [],
primaryAction: () => null,
primaryAction: () =>
m(NavButton, {
label: "calendar_label",
hideLabel: true,
icon: () => BootIcons.Calendar,
href: CALENDAR_PREFIX,
centred: true,
fillSpaceAround: false,
}),
}),
desktopToolbar: () => null,
}),
Expand Down Expand Up @@ -318,7 +326,6 @@ export class CalendarSettingsView extends BaseTopLevelView implements TopLevelVi
header: m(Header, {
...attrs.header,
}),
bottomNav: m(CalendarBottomNav),
}),
)
}
Expand Down
Loading

0 comments on commit 1e7365c

Please sign in to comment.