diff --git a/src/app/modules/schedule/page/modal/modal-event-creator.scss b/src/app/animation/easings.ts
similarity index 67%
rename from src/app/modules/schedule/page/modal/modal-event-creator.scss
rename to src/app/animation/easings.ts
index c933f1ae..4c84acee 100644
--- a/src/app/modules/schedule/page/modal/modal-event-creator.scss
+++ b/src/app/animation/easings.ts
@@ -1,5 +1,5 @@
-/*!
- * Copyright (C) 2022 StApps
+/*
+ * Copyright (C) 2023 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -13,23 +13,8 @@
* this program. If not, see .
*/
-:host {
- height: 100%;
- display: flex;
- flex-direction: column;
- flex: 1 1 20%;
-}
-
-ion-button {
- ion-label {
- color: var(--ion-color-light);
- }
-}
-
-ion-card-content {
- height: 100%;
- padding: 0;
- stapps-data-list {
- height: 100%;
- }
-}
+// these are the ionic values
+export const iosEasing = 'cubic-bezier(0.32,0.72,0,1)';
+export const iosDuration = 540;
+export const mdEasing = 'cubic-bezier(0.36,0.66,0.04,1)';
+export const mdDuration = 280;
diff --git a/src/app/animation/fab-expand.ts b/src/app/animation/fab-expand.ts
new file mode 100644
index 00000000..92823fb5
--- /dev/null
+++ b/src/app/animation/fab-expand.ts
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+
+import {AnimationBuilder, AnimationController} from '@ionic/angular';
+import {AnimationOptions} from '@ionic/angular/providers/nav-controller';
+import {iosDuration, iosEasing, mdDuration, mdEasing} from './easings';
+
+/**
+ *
+ */
+export function fabExpand(animationController: AnimationController): AnimationBuilder {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return (_baseElement: HTMLElement, options: AnimationOptions | any) => {
+ const rootTransition = animationController
+ .create()
+ .duration(options.duration ?? (options.mode === 'ios' ? iosDuration : mdDuration * 1.4))
+ .easing(options.mode === 'ios' ? iosEasing : mdEasing);
+ const back = options.direction === 'back';
+ const fabView = back ? options.enteringEl! : options.leavingEl!;
+ const otherView = back ? options.leavingEl! : options.enteringEl!;
+
+ const fab = fabView.querySelector('ion-fab-button').shadowRoot.querySelector('.button-native');
+ const fabBounds = fab.getBoundingClientRect();
+ const viewBounds = otherView.getBoundingClientRect();
+
+ const useReducedMotion = viewBounds.width > 500;
+ const reducedMotionTransform = `${Math.min(viewBounds.width * 0.3, 200)}px`;
+ const reducedMotionViewBorderRadius = '128px';
+ const reducedMotionFabGrow = '2';
+ const reducedMotionViewShrink = '0.9';
+
+ const viewCenterX = (viewBounds.width - viewBounds.x) / 2;
+ const viewCenterY = (viewBounds.height - viewBounds.y) / 2;
+
+ const viewOnFab = useReducedMotion
+ ? `translate(${reducedMotionTransform}, ${reducedMotionTransform}) scale(${reducedMotionViewShrink})`
+ : `translate(${(fabBounds.x - viewBounds.x) / 2}px, ${(fabBounds.y - viewBounds.y) / 2}px) scale(${
+ fabBounds.width / viewBounds.width
+ }, ${fabBounds.height / viewBounds.height})`;
+ const fabOnView = useReducedMotion
+ ? `translate(-${reducedMotionTransform}, -${reducedMotionTransform}) scale(${reducedMotionFabGrow})`
+ : `translate(${viewCenterX - fabBounds.x}px, ${viewCenterY - fabBounds.y}px) scale(${
+ viewBounds.width / fabBounds.width
+ }, ${viewBounds.height / fabBounds.height})`;
+ const transformNormal = `translate(0px, 0px) scale(1, 1)`;
+
+ const viewBorderRadius = useReducedMotion ? reducedMotionViewBorderRadius : '50%';
+
+ const fabViewFade = animationController
+ .create()
+ .beforeStyles({zIndex: -1})
+ .fromTo('opacity', '1', '1')
+ .addElement(fabView);
+ const fabGrow = animationController
+ .create()
+ .beforeStyles({transformOrigin: 'center'})
+ .fromTo('transform', back ? fabOnView : transformNormal, back ? transformNormal : fabOnView)
+ .fromTo('opacity', back ? '0' : '1', back ? '1' : '0')
+ .fromTo('borderRadius', back ? '0' : '50%', back ? '50%' : '0')
+ .addElement(fab);
+ const viewGrow = animationController
+ .create()
+ .beforeStyles({zIndex: 200, overflow: 'hidden', transformOrigin: 'center'})
+ .fromTo('transform', back ? transformNormal : viewOnFab, back ? viewOnFab : transformNormal)
+ .fromTo('opacity', back ? '1' : '0', back ? '0' : '1')
+ .fromTo('borderRadius', back ? '0' : viewBorderRadius, back ? viewBorderRadius : '0')
+ .addElement(otherView);
+
+ return rootTransition.addAnimation(fabGrow).addAnimation(viewGrow).addAnimation(fabViewFade);
+ };
+}
diff --git a/src/app/modules/data/list/search-page.component.ts b/src/app/modules/data/list/search-page.component.ts
index 0fb4ceb1..1b4ee9a5 100644
--- a/src/app/modules/data/list/search-page.component.ts
+++ b/src/app/modules/data/list/search-page.component.ts
@@ -46,7 +46,13 @@ import {searchPageSwitchAnimation} from './search-page-switch-animation';
providers: [ContextMenuService],
})
export class SearchPageComponent implements OnInit, OnDestroy {
- title = 'search.title';
+ @Input() title = 'search.title';
+
+ @Input() placeholder = 'search.search_bar.placeholder';
+
+ @Input() searchInstruction = 'search.instruction';
+
+ @Input() backUrl?: string;
isHebisAvailable = false;
diff --git a/src/app/modules/data/list/search-page.html b/src/app/modules/data/list/search-page.html
index 61793278..f795f974 100644
--- a/src/app/modules/data/list/search-page.html
+++ b/src/app/modules/data/list/search-page.html
@@ -15,9 +15,9 @@
-
+
-
+
{{ title | translate }}
@@ -28,7 +28,7 @@
(search)="hideKeyboard()"
[(ngModel)]="queryText"
showClearButton="always"
- placeholder="{{ 'search.search_bar.placeholder' | translate }}"
+ placeholder="{{ placeholder | translate }}"
mode="md"
type="search"
enterkeyhint="search"
@@ -61,7 +61,7 @@
[style.display]="!showDefaultData && !items && !loading ? 'block' : 'none'"
>
- {{ 'search.instruction' | translate }}
+ {{ searchInstruction | translate }}
.
+ */
+import {Component} from '@angular/core';
+import {SCSearchFilter, SCThingType} from '@openstapps/core';
+
+@Component({
+ selector: 'stapps-choose-events-page',
+ templateUrl: 'choose-events-page.html',
+})
+export class ChooseEventsPageComponent {
+ forcedFilter: SCSearchFilter = {
+ arguments: {
+ field: 'type',
+ value: SCThingType.AcademicEvent,
+ },
+ type: 'value',
+ };
+}
diff --git a/src/app/modules/schedule/page/modal/modal-event-creator.html b/src/app/modules/schedule/page/choose-events-page.html
similarity index 50%
rename from src/app/modules/schedule/page/modal/modal-event-creator.html
rename to src/app/modules/schedule/page/choose-events-page.html
index 7f7b39aa..55cc1c78 100644
--- a/src/app/modules/schedule/page/modal/modal-event-creator.html
+++ b/src/app/modules/schedule/page/choose-events-page.html
@@ -1,5 +1,5 @@
-
-
- {{ 'schedule.addEventModal.addEvent' | translate | titlecase }}
-
-
- {{ 'modal.DISMISS' | translate }}
-
-
-
-
-
-
-
+
diff --git a/src/app/modules/schedule/page/modal/modal-event-creator.component.ts b/src/app/modules/schedule/page/modal/modal-event-creator.component.ts
deleted file mode 100644
index 767aa25a..00000000
--- a/src/app/modules/schedule/page/modal/modal-event-creator.component.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2022 StApps
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 3.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see .
- */
-import {Component, OnDestroy, OnInit} from '@angular/core';
-import {SCSearchFilter, SCThingType} from '@openstapps/core';
-import {ModalController} from '@ionic/angular';
-import {DataRoutingService} from '../../../data/data-routing.service';
-import {DataDetailComponent} from '../../../data/detail/data-detail.component';
-import {Subscription} from 'rxjs';
-
-/**
- * TODO
- */
-@Component({
- selector: 'modal-event-creator',
- templateUrl: 'modal-event-creator.html',
- styleUrls: ['modal-event-creator.scss'],
-})
-export class ModalEventCreatorComponent implements OnInit, OnDestroy {
- subscriptions: Subscription[] = [];
-
- constructor(readonly modalController: ModalController, readonly dataRoutingService: DataRoutingService) {}
-
- ngOnInit() {
- this.subscriptions.push(
- this.dataRoutingService.itemSelectListener().subscribe(async item => {
- const modal = await this.modalController.create({
- component: DataDetailComponent,
- componentProps: {
- isModal: true,
- inputItem: item,
- },
- canDismiss: true,
- });
- return modal.present();
- }),
- );
- }
-
- ngOnDestroy() {
- for (const subscription of this.subscriptions) subscription.unsubscribe();
- }
-
- /**
- * Forced filter
- */
- filter: SCSearchFilter = {
- arguments: {
- field: 'type',
- value: SCThingType.AcademicEvent,
- },
- type: 'value',
- };
-}
diff --git a/src/app/modules/schedule/page/schedule-page.component.ts b/src/app/modules/schedule/page/schedule-page.component.ts
index 815772fa..73860815 100644
--- a/src/app/modules/schedule/page/schedule-page.component.ts
+++ b/src/app/modules/schedule/page/schedule-page.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -15,12 +15,13 @@
import {AfterViewInit, Component, HostListener, Input, OnInit, ViewChild} from '@angular/core';
import {Location} from '@angular/common';
import {ActivatedRoute, Router} from '@angular/router';
-import {IonRouterOutlet} from '@ionic/angular';
+import {AnimationController, IonRouterOutlet} from '@ionic/angular';
import {SharedAxisChoreographer} from '../../../animation/animation-choreographer';
import {materialSharedAxisX} from '../../../animation/material-motion';
import {ScheduleResponsiveBreakpoint} from './schema/schema';
import {CalendarService} from '../../calendar/calendar.service';
import moment from 'moment';
+import {fabExpand} from '../../../animation/fab-expand';
/**
* This needs to be sorted by break point low -> high
@@ -93,6 +94,8 @@ export class SchedulePageComponent implements OnInit, AfterViewInit {
isModalOpen = false;
+ fabAnimation = fabExpand(this.animationController);
+
/**
* Amount of days that should be shown according to current display width
*/
@@ -111,6 +114,7 @@ export class SchedulePageComponent implements OnInit, AfterViewInit {
private calendarService: CalendarService,
readonly routerOutlet: IonRouterOutlet,
private router: Router,
+ private animationController: AnimationController,
private location: Location,
) {}
@@ -168,12 +172,4 @@ export class SchedulePageComponent implements OnInit, AfterViewInit {
onTodayClick() {
this.calendarService.emitGoToDate(moment().startOf('day'));
}
-
- onFABClick() {
- this.isModalOpen = true;
- }
-
- onModalDismiss() {
- this.isModalOpen = false;
- }
}
diff --git a/src/app/modules/schedule/page/schedule-page.html b/src/app/modules/schedule/page/schedule-page.html
index 95f0e267..2ef773ca 100644
--- a/src/app/modules/schedule/page/schedule-page.html
+++ b/src/app/modules/schedule/page/schedule-page.html
@@ -63,15 +63,15 @@
-
+
-
-
-
-
-
-
diff --git a/src/app/modules/schedule/schedule.module.ts b/src/app/modules/schedule/schedule.module.ts
index 46865bbc..4c9d2d38 100644
--- a/src/app/modules/schedule/schedule.module.ts
+++ b/src/app/modules/schedule/schedule.module.ts
@@ -1,16 +1,16 @@
/*
- * Copyright (C) 2022 StApps
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, version 3.
+ * Copyright (C) 2023 StApps
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 3.
*
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see .
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
*/
import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
@@ -26,7 +26,6 @@ import {DataModule} from '../data/data.module';
import {DataProvider} from '../data/data.provider';
import {CalendarViewComponent} from './page/calendar-view.component';
import {ScheduleCursorComponent} from './page/grid/schedule-cursor.component';
-import {ModalEventCreatorComponent} from './page/modal/modal-event-creator.component';
import {SchedulePageComponent} from './page/schedule-page.component';
import {ScheduleSingleEventsComponent} from './page/schedule-single-events.component';
import {ScheduleViewComponent} from './page/schedule-view.component';
@@ -37,6 +36,7 @@ import {ThingTranslateModule} from '../../translation/thing-translate.module';
import {InfiniteSwiperComponent} from './page/grid/infinite-swiper.component';
import {CalendarComponent} from './page/components/calendar.component';
import {IonIconModule} from '../../util/ion-icon/ion-icon.module';
+import {ChooseEventsPageComponent} from './page/choose-events-page.component';
const settingsRoutes: Routes = [
{path: 'schedule', redirectTo: 'schedule/calendar/now'},
@@ -45,6 +45,8 @@ const settingsRoutes: Routes = [
{path: 'schedule/single', redirectTo: 'schedule/single/now'},
// calendar | recurring | single
{path: 'schedule/:mode/:date', component: SchedulePageComponent},
+ // TODO: this is temporary until the new generalized search page is finished
+ {path: 'schedule/:mode/:date/event-picker', component: ChooseEventsPageComponent},
];
/**
@@ -54,7 +56,7 @@ const settingsRoutes: Routes = [
declarations: [
CalendarComponent,
CalendarViewComponent,
- ModalEventCreatorComponent,
+ ChooseEventsPageComponent,
ScheduleCardComponent,
ScheduleCursorComponent,
SchedulePageComponent,
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index 78e91970..e4554570 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -454,8 +454,10 @@
"recurring": "Stundenplan",
"calendar": "Kalender",
"single": "Einzeltermine",
- "addEventModal": {
- "addEvent": "Events Hinzufügen"
+ "addEventPage": {
+ "TITLE": "Termine Hinzufügen",
+ "PLACEHOLDER": "Termine",
+ "SEARCH_INSTRUCTION": "Termine finden"
},
"card": {
"forEach": "Alle",
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 769c8618..664a7e34 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -454,8 +454,10 @@
"recurring": "Recurring",
"calendar": "Calendar",
"single": "Single Events",
- "addEventModal": {
- "addEvent": "Add Events"
+ "addEventPage": {
+ "TITLE": "Add Events",
+ "PLACEHOLDER": "Events",
+ "SEARCH_INSTRUCTION": "Find events"
},
"card": {
"forEach": "Every",