mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: optimize calendar for mobile (#3979)
* feat: calendar mobile ui - Resolves double border on Calendar Cells - Adds Jump to year quick action for Mobile - Reduces Cell height in Calendar - Change out EventList with EventIndicator in Cell * chore: push card details screen * fix: navigation to card details * feat: day events screen update on new event * fix: changes after merging main * fix: missing argument * fix: amend test and remove stack
This commit is contained in:
parent
b3dd5fb8bd
commit
7fb1b4f43f
@ -74,10 +74,10 @@ void main() {
|
||||
await tester.scrollToToday();
|
||||
|
||||
// Hover over today's calendar cell
|
||||
await tester.hoverOnTodayCalendarCell();
|
||||
|
||||
// Tap on create new event button
|
||||
await tester.tapAddCalendarEventButton();
|
||||
await tester.hoverOnTodayCalendarCell(
|
||||
// Tap on create new event button
|
||||
onHover: () async => await tester.tapAddCalendarEventButton(),
|
||||
);
|
||||
|
||||
// Make sure that the event editor popup is shown
|
||||
tester.assertEventEditorOpen();
|
||||
@ -90,15 +90,9 @@ void main() {
|
||||
// Double click on today's calendar cell to create a new event
|
||||
await tester.doubleClickCalendarCell(DateTime.now());
|
||||
|
||||
// Make sure that the event editor popup is shown
|
||||
tester.assertEventEditorOpen();
|
||||
|
||||
// Make sure that the event is inserted in the cell
|
||||
tester.assertNumberOfEventsInCalendar(2);
|
||||
|
||||
// Dismiss the event editor popup
|
||||
await tester.dismissEventEditor();
|
||||
|
||||
// Click on the event
|
||||
await tester.openCalendarEvent(index: 0);
|
||||
tester.assertEventEditorOpen();
|
||||
@ -112,7 +106,7 @@ void main() {
|
||||
tester.assertNumberOfEventsOnSpecificDay(2, DateTime.now());
|
||||
|
||||
// Click on the event
|
||||
await tester.openCalendarEvent(index: 1);
|
||||
await tester.openCalendarEvent(index: 0);
|
||||
tester.assertEventEditorOpen();
|
||||
|
||||
// Click on the open icon
|
||||
@ -137,7 +131,7 @@ void main() {
|
||||
tester.assertNumberOfEventsOnSpecificDay(2, DateTime.now());
|
||||
|
||||
// Delete event from row detail page
|
||||
await tester.openCalendarEvent(index: 1);
|
||||
await tester.openCalendarEvent(index: 0);
|
||||
await tester.openEventToRowDetailPage();
|
||||
tester.assertRowDetailPageOpened();
|
||||
|
||||
@ -163,7 +157,7 @@ void main() {
|
||||
await tester.dismissEventEditor();
|
||||
|
||||
// Drag and drop the event onto the next week, same day
|
||||
await tester.dragDropRescheduleCalendarEvent(firstOfThisMonth);
|
||||
await tester.dragDropRescheduleCalendarEvent();
|
||||
|
||||
// Make sure that the event has been rescheduled to the new date
|
||||
final sameDayNextWeek = firstOfThisMonth.add(const Duration(days: 7));
|
||||
|
@ -1249,12 +1249,14 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await pumpAndSettle(const Duration(milliseconds: 300));
|
||||
}
|
||||
|
||||
Future<void> hoverOnTodayCalendarCell() async {
|
||||
Future<void> hoverOnTodayCalendarCell({
|
||||
Future<void> Function()? onHover,
|
||||
}) async {
|
||||
final todayCell = find.byWidgetPredicate(
|
||||
(widget) => widget is CalendarDayCard && widget.isToday,
|
||||
);
|
||||
|
||||
await hoverOnWidget(todayCell);
|
||||
await hoverOnWidget(todayCell, onHover: onHover);
|
||||
}
|
||||
|
||||
Future<void> tapAddCalendarEventButton() async {
|
||||
@ -1362,7 +1364,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
||||
await tapButton(button);
|
||||
}
|
||||
|
||||
Future<void> dragDropRescheduleCalendarEvent(DateTime startDate) async {
|
||||
Future<void> dragDropRescheduleCalendarEvent() async {
|
||||
final findEventCard = find.byType(EventCard);
|
||||
await drag(findEventCard.first, const Offset(0, 300));
|
||||
await pumpAndSettle();
|
||||
|
@ -0,0 +1,97 @@
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_event_card.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class MobileCalendarEventsScreen extends StatefulWidget {
|
||||
static const routeName = "/calendar-events";
|
||||
|
||||
// GoRouter Arguments
|
||||
static const calendarBlocKey = "calendar_bloc";
|
||||
static const calendarDateKey = "date";
|
||||
static const calendarEventsKey = "events";
|
||||
static const calendarRowCacheKey = "row_cache";
|
||||
static const calendarViewIdKey = "view_id";
|
||||
|
||||
const MobileCalendarEventsScreen({
|
||||
super.key,
|
||||
required this.calendarBloc,
|
||||
required this.date,
|
||||
required this.events,
|
||||
required this.rowCache,
|
||||
required this.viewId,
|
||||
});
|
||||
|
||||
final CalendarBloc calendarBloc;
|
||||
final DateTime date;
|
||||
final List<CalendarDayEvent> events;
|
||||
final RowCache rowCache;
|
||||
final String viewId;
|
||||
|
||||
@override
|
||||
State<MobileCalendarEventsScreen> createState() =>
|
||||
_MobileCalendarEventsScreenState();
|
||||
}
|
||||
|
||||
class _MobileCalendarEventsScreenState
|
||||
extends State<MobileCalendarEventsScreen> {
|
||||
late final List<CalendarDayEvent> _events = widget.events;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider.value(
|
||||
value: widget.calendarBloc,
|
||||
child: BlocBuilder<CalendarBloc, CalendarState>(
|
||||
buildWhen: (p, c) => p.newEvent != c.newEvent,
|
||||
builder: (context, state) {
|
||||
if (state.newEvent?.event != null) {
|
||||
_events.add(state.newEvent!.event!);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
key: const Key('add_event_fab'),
|
||||
elevation: 6,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
foregroundColor: Theme.of(context).colorScheme.onPrimary,
|
||||
onPressed: () => widget.calendarBloc
|
||||
.add(CalendarEvent.createEvent(widget.date)),
|
||||
child: const Text('+'),
|
||||
),
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
DateFormat.yMMMMd(context.locale.toLanguageTag())
|
||||
.format(widget.date),
|
||||
),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const VSpace(10),
|
||||
...widget.events.map((event) {
|
||||
return ListTile(
|
||||
dense: true,
|
||||
title: EventCard(
|
||||
fieldController: widget.calendarBloc.fieldController,
|
||||
event: event,
|
||||
viewId: widget.viewId,
|
||||
rowCache: widget.rowCache,
|
||||
constraints: const BoxConstraints.expand(),
|
||||
autoEdit: false,
|
||||
isDraggable: false,
|
||||
),
|
||||
);
|
||||
}),
|
||||
const VSpace(24),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -146,19 +146,19 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
||||
(settings) async {
|
||||
final dateField = _getCalendarFieldInfo(settings.fieldId);
|
||||
if (dateField != null) {
|
||||
final newRow = await databaseController.createRow(
|
||||
withCells: (builder) {
|
||||
builder.insertDate(dateField, date);
|
||||
},
|
||||
).then(
|
||||
(result) => result.fold(
|
||||
(newRow) => newRow,
|
||||
(err) {
|
||||
Log.error(err);
|
||||
return null;
|
||||
},
|
||||
),
|
||||
);
|
||||
final newRow = await databaseController
|
||||
.createRow(
|
||||
withCells: (builder) => builder.insertDate(dateField, date),
|
||||
)
|
||||
.then(
|
||||
(result) => result.fold(
|
||||
(newRow) => newRow,
|
||||
(err) {
|
||||
Log.error(err);
|
||||
return null;
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (newRow != null) {
|
||||
final event = await _loadEvent(newRow.id);
|
||||
@ -207,10 +207,7 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
|
||||
final payload = RowIdPB(viewId: viewId, rowId: rowId);
|
||||
return DatabaseEventGetCalendarEvent(payload).send().then((result) {
|
||||
return result.fold(
|
||||
(eventPB) {
|
||||
final calendarEvent = _calendarEventDataFromEventPB(eventPB);
|
||||
return calendarEvent;
|
||||
},
|
||||
(eventPB) => _calendarEventDataFromEventPB(eventPB),
|
||||
(r) {
|
||||
Log.error(r);
|
||||
return null;
|
||||
|
@ -1,6 +1,9 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_calendar_events_screen.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:calendar_view/calendar_view.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
|
||||
@ -8,6 +11,7 @@ import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra/time/duration.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../grid/presentation/layout/sizes.dart';
|
||||
@ -15,6 +19,18 @@ import '../application/calendar_bloc.dart';
|
||||
import 'calendar_event_card.dart';
|
||||
|
||||
class CalendarDayCard extends StatelessWidget {
|
||||
const CalendarDayCard({
|
||||
super.key,
|
||||
required this.viewId,
|
||||
required this.isToday,
|
||||
required this.isInMonth,
|
||||
required this.date,
|
||||
required this.rowCache,
|
||||
required this.events,
|
||||
required this.onCreateEvent,
|
||||
required this.position,
|
||||
});
|
||||
|
||||
final String viewId;
|
||||
final bool isToday;
|
||||
final bool isInMonth;
|
||||
@ -22,24 +38,10 @@ class CalendarDayCard extends StatelessWidget {
|
||||
final RowCache rowCache;
|
||||
final List<CalendarDayEvent> events;
|
||||
final void Function(DateTime) onCreateEvent;
|
||||
|
||||
const CalendarDayCard({
|
||||
required this.viewId,
|
||||
required this.isToday,
|
||||
required this.isInMonth,
|
||||
required this.date,
|
||||
required this.onCreateEvent,
|
||||
required this.rowCache,
|
||||
required this.events,
|
||||
super.key,
|
||||
});
|
||||
final CellPosition position;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color backgroundColor = Colors.transparent;
|
||||
if (date.isWeekend) {
|
||||
backgroundColor = AFThemeExtension.of(context).calendarWeekendBGColor;
|
||||
}
|
||||
final hoverBackgroundColor =
|
||||
Theme.of(context).brightness == Brightness.light
|
||||
? Theme.of(context).colorScheme.secondaryContainer
|
||||
@ -64,55 +66,67 @@ class CalendarDayCard extends StatelessWidget {
|
||||
const VSpace(6.0),
|
||||
|
||||
// List of cards or empty space
|
||||
if (events.isNotEmpty)
|
||||
if (events.isNotEmpty && !PlatformExtension.isMobile) ...[
|
||||
_EventList(
|
||||
events: events,
|
||||
viewId: viewId,
|
||||
rowCache: rowCache,
|
||||
constraints: constraints,
|
||||
),
|
||||
] else if (events.isNotEmpty && PlatformExtension.isMobile) ...[
|
||||
const _EventIndicator(),
|
||||
],
|
||||
],
|
||||
);
|
||||
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onDoubleTap: () => onCreateEvent(date),
|
||||
child: Container(color: backgroundColor),
|
||||
return MouseRegion(
|
||||
onEnter: (p) => notifyEnter(context, true),
|
||||
onExit: (p) => notifyEnter(context, false),
|
||||
opaque: false,
|
||||
hitTestBehavior: HitTestBehavior.translucent,
|
||||
child: GestureDetector(
|
||||
onDoubleTap: () => onCreateEvent(date),
|
||||
onTap: PlatformExtension.isMobile
|
||||
? () => _mobileOnTap(context)
|
||||
: null,
|
||||
behavior: HitTestBehavior.deferToChild,
|
||||
child: Container(
|
||||
color: date.isWeekend
|
||||
? AFThemeExtension.of(context).calendarWeekendBGColor
|
||||
: Colors.transparent,
|
||||
child: DragTarget<CalendarDayEvent>(
|
||||
builder: (context, candidate, __) {
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: candidate.isEmpty
|
||||
? null
|
||||
: hoverBackgroundColor,
|
||||
border: _borderFromPosition(context, position),
|
||||
),
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
child: child,
|
||||
),
|
||||
if (candidate.isEmpty && !PlatformExtension.isMobile)
|
||||
NewEventButton(onCreate: () => onCreateEvent(date)),
|
||||
],
|
||||
);
|
||||
},
|
||||
onAccept: (CalendarDayEvent event) {
|
||||
if (event.date == date) {
|
||||
return;
|
||||
}
|
||||
|
||||
context
|
||||
.read<CalendarBloc>()
|
||||
.add(CalendarEvent.moveEvent(event, date));
|
||||
},
|
||||
),
|
||||
),
|
||||
DragTarget<CalendarDayEvent>(
|
||||
builder: (context, candidate, __) {
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
color:
|
||||
candidate.isEmpty ? null : hoverBackgroundColor,
|
||||
padding: const EdgeInsets.only(top: 5.0),
|
||||
child: child,
|
||||
),
|
||||
if (candidate.isEmpty)
|
||||
NewEventButton(onCreate: () => onCreateEvent(date)),
|
||||
],
|
||||
);
|
||||
},
|
||||
onAccept: (CalendarDayEvent event) {
|
||||
if (event.date == date) {
|
||||
return;
|
||||
}
|
||||
context
|
||||
.read<CalendarBloc>()
|
||||
.add(CalendarEvent.moveEvent(event, date));
|
||||
},
|
||||
),
|
||||
MouseRegion(
|
||||
onEnter: (p) => notifyEnter(context, true),
|
||||
onExit: (p) => notifyEnter(context, false),
|
||||
opaque: false,
|
||||
hitTestBehavior: HitTestBehavior.translucent,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
@ -120,42 +134,94 @@ class CalendarDayCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
notifyEnter(BuildContext context, bool isEnter) {
|
||||
Provider.of<_CardEnterNotifier>(
|
||||
context,
|
||||
listen: false,
|
||||
).onEnter = isEnter;
|
||||
void _mobileOnTap(BuildContext context) {
|
||||
context.push(
|
||||
MobileCalendarEventsScreen.routeName,
|
||||
extra: {
|
||||
MobileCalendarEventsScreen.calendarBlocKey:
|
||||
context.read<CalendarBloc>(),
|
||||
MobileCalendarEventsScreen.calendarDateKey: date,
|
||||
MobileCalendarEventsScreen.calendarEventsKey: events,
|
||||
MobileCalendarEventsScreen.calendarRowCacheKey: rowCache,
|
||||
MobileCalendarEventsScreen.calendarViewIdKey: viewId,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
notifyEnter(BuildContext context, bool isEnter) =>
|
||||
Provider.of<_CardEnterNotifier>(context, listen: false).onEnter = isEnter;
|
||||
|
||||
Border _borderFromPosition(BuildContext context, CellPosition position) {
|
||||
final BorderSide borderSide =
|
||||
BorderSide(color: Theme.of(context).dividerColor);
|
||||
|
||||
return Border(
|
||||
top: borderSide,
|
||||
left: borderSide,
|
||||
bottom: [
|
||||
CellPosition.bottom,
|
||||
CellPosition.bottomLeft,
|
||||
CellPosition.bottomRight,
|
||||
].contains(position)
|
||||
? borderSide
|
||||
: BorderSide.none,
|
||||
right: [
|
||||
CellPosition.topRight,
|
||||
CellPosition.bottomRight,
|
||||
CellPosition.right,
|
||||
].contains(position)
|
||||
? borderSide
|
||||
: BorderSide.none,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _EventIndicator extends StatelessWidget {
|
||||
const _EventIndicator();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 6,
|
||||
height: 6,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Header extends StatelessWidget {
|
||||
final bool isToday;
|
||||
final bool isInMonth;
|
||||
final DateTime date;
|
||||
const _Header({
|
||||
required this.isToday,
|
||||
required this.isInMonth,
|
||||
required this.date,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final bool isToday;
|
||||
final bool isInMonth;
|
||||
final DateTime date;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||
child: _DayBadge(
|
||||
isToday: isToday,
|
||||
isInMonth: isInMonth,
|
||||
date: date,
|
||||
),
|
||||
child: _DayBadge(isToday: isToday, isInMonth: isInMonth, date: date),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
class NewEventButton extends StatelessWidget {
|
||||
const NewEventButton({super.key, required this.onCreate});
|
||||
|
||||
final VoidCallback onCreate;
|
||||
const NewEventButton({required this.onCreate, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -164,6 +230,7 @@ class NewEventButton extends StatelessWidget {
|
||||
if (!notifier.onEnter) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: FlowyIconButton(
|
||||
@ -210,15 +277,15 @@ class NewEventButton extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _DayBadge extends StatelessWidget {
|
||||
final bool isToday;
|
||||
final bool isInMonth;
|
||||
final DateTime date;
|
||||
const _DayBadge({
|
||||
required this.isToday,
|
||||
required this.isInMonth,
|
||||
required this.date,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final bool isToday;
|
||||
final bool isInMonth;
|
||||
final DateTime date;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -239,10 +306,12 @@ class _DayBadge extends StatelessWidget {
|
||||
return SizedBox(
|
||||
height: 18,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisAlignment: PlatformExtension.isMobile
|
||||
? MainAxisAlignment.center
|
||||
: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (date.day == 1)
|
||||
if (date.day == 1 && !PlatformExtension.isMobile)
|
||||
FlowyText.medium(
|
||||
monthString,
|
||||
fontSize: 11,
|
||||
@ -255,7 +324,6 @@ class _DayBadge extends StatelessWidget {
|
||||
),
|
||||
width: isToday ? 18 : null,
|
||||
height: isToday ? 18 : null,
|
||||
// padding: GridSize.typeOptionContentInsets,
|
||||
child: Center(
|
||||
child: FlowyText.medium(
|
||||
dayString,
|
||||
@ -271,27 +339,25 @@ class _DayBadge extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _EventList extends StatelessWidget {
|
||||
final List<CalendarDayEvent> events;
|
||||
final String viewId;
|
||||
final RowCache rowCache;
|
||||
final BoxConstraints constraints;
|
||||
|
||||
const _EventList({
|
||||
required this.events,
|
||||
required this.viewId,
|
||||
required this.rowCache,
|
||||
required this.constraints,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
final List<CalendarDayEvent> events;
|
||||
final String viewId;
|
||||
final RowCache rowCache;
|
||||
final BoxConstraints constraints;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final editingEvent = context.watch<CalendarBloc>().state.editingEvent;
|
||||
|
||||
return Flexible(
|
||||
child: ScrollConfiguration(
|
||||
behavior: ScrollConfiguration.of(context).copyWith(
|
||||
scrollbars: true,
|
||||
),
|
||||
behavior: ScrollConfiguration.of(context).copyWith(scrollbars: true),
|
||||
child: ListView.separated(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final autoEdit =
|
||||
@ -307,7 +373,7 @@ class _EventList extends StatelessWidget {
|
||||
},
|
||||
itemCount: events.length,
|
||||
padding: const EdgeInsets.fromLTRB(4.0, 0, 4.0, 4.0),
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
separatorBuilder: (_, __) =>
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
shrinkWrap: true,
|
||||
),
|
||||
|
@ -1,6 +1,8 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/row/row_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/card/card.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/card/card_cell_builder.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/card/cells/card_cell.dart';
|
||||
@ -8,6 +10,7 @@ import 'package:appflowy/plugins/database_view/widgets/card/cells/number_card_ce
|
||||
import 'package:appflowy/plugins/database_view/widgets/card/cells/url_card_cell.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
|
||||
import 'package:appflowy/plugins/database_view/widgets/row/cells/text_cell/text_cell_bloc.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@ -16,27 +19,30 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../application/calendar_bloc.dart';
|
||||
import 'calendar_event_editor.dart';
|
||||
|
||||
class EventCard extends StatefulWidget {
|
||||
const EventCard({
|
||||
super.key,
|
||||
required this.fieldController,
|
||||
required this.event,
|
||||
required this.viewId,
|
||||
required this.rowCache,
|
||||
required this.constraints,
|
||||
required this.autoEdit,
|
||||
this.isDraggable = true,
|
||||
});
|
||||
|
||||
final FieldController fieldController;
|
||||
final CalendarDayEvent event;
|
||||
final String viewId;
|
||||
final RowCache rowCache;
|
||||
final BoxConstraints constraints;
|
||||
final bool autoEdit;
|
||||
|
||||
const EventCard({
|
||||
super.key,
|
||||
required this.event,
|
||||
required this.viewId,
|
||||
required this.rowCache,
|
||||
required this.constraints,
|
||||
required this.autoEdit,
|
||||
required this.fieldController,
|
||||
});
|
||||
final bool isDraggable;
|
||||
|
||||
@override
|
||||
State<EventCard> createState() => _EventCardState();
|
||||
@ -75,7 +81,7 @@ class _EventCardState extends State<EventCard> {
|
||||
);
|
||||
final renderHook = _calendarEventCardRenderHook(context);
|
||||
|
||||
final card = RowCard<CalendarDayEvent>(
|
||||
Widget card = RowCard<CalendarDayEvent>(
|
||||
// Add the key here to make sure the card is rebuilt when the cells
|
||||
// in this row are updated.
|
||||
key: ValueKey(widget.event.eventId),
|
||||
@ -85,7 +91,25 @@ class _EventCardState extends State<EventCard> {
|
||||
cardData: widget.event,
|
||||
isEditing: false,
|
||||
cellBuilder: cellBuilder,
|
||||
openCard: (_) => _popoverController.show(),
|
||||
openCard: (context) {
|
||||
if (PlatformExtension.isMobile) {
|
||||
final dataController = RowController(
|
||||
rowMeta: rowInfo.rowMeta,
|
||||
viewId: widget.viewId,
|
||||
rowCache: widget.rowCache,
|
||||
);
|
||||
|
||||
context.push(
|
||||
MobileCardDetailScreen.routeName,
|
||||
extra: {
|
||||
MobileCardDetailScreen.argRowController: dataController,
|
||||
MobileCardDetailScreen.argFieldController: widget.fieldController,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
_popoverController.show();
|
||||
}
|
||||
},
|
||||
styleConfiguration: RowCardStyleConfiguration(
|
||||
showAccessory: false,
|
||||
cellPadding: EdgeInsets.zero,
|
||||
@ -132,50 +156,56 @@ class _EventCardState extends State<EventCard> {
|
||||
],
|
||||
);
|
||||
|
||||
return Draggable<CalendarDayEvent>(
|
||||
data: widget.event,
|
||||
feedback: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: widget.constraints.maxWidth - 8.0,
|
||||
),
|
||||
child: Opacity(
|
||||
opacity: 0.6,
|
||||
child: DecoratedBox(
|
||||
decoration: decoration,
|
||||
child: card,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: AppFlowyPopover(
|
||||
triggerActions: PopoverTriggerFlags.none,
|
||||
direction: PopoverDirection.rightWithCenterAligned,
|
||||
controller: _popoverController,
|
||||
constraints: const BoxConstraints(maxWidth: 360, maxHeight: 348),
|
||||
asBarrier: true,
|
||||
margin: EdgeInsets.zero,
|
||||
offset: const Offset(10.0, 0),
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
final settings = context.watch<CalendarBloc>().state.settings.fold(
|
||||
() => null,
|
||||
(layoutSettings) => layoutSettings,
|
||||
);
|
||||
if (settings == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return CalendarEventEditor(
|
||||
rowCache: widget.rowCache,
|
||||
rowMeta: widget.event.event.rowMeta,
|
||||
viewId: widget.viewId,
|
||||
layoutSettings: settings,
|
||||
fieldController: widget.fieldController,
|
||||
);
|
||||
},
|
||||
child: DecoratedBox(
|
||||
decoration: decoration,
|
||||
child: card,
|
||||
),
|
||||
card = AppFlowyPopover(
|
||||
triggerActions: PopoverTriggerFlags.none,
|
||||
direction: PopoverDirection.rightWithCenterAligned,
|
||||
controller: _popoverController,
|
||||
constraints: const BoxConstraints(maxWidth: 360, maxHeight: 348),
|
||||
asBarrier: true,
|
||||
margin: EdgeInsets.zero,
|
||||
offset: const Offset(10.0, 0),
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
final settings = context.watch<CalendarBloc>().state.settings.fold(
|
||||
() => null,
|
||||
(layoutSettings) => layoutSettings,
|
||||
);
|
||||
if (settings == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return CalendarEventEditor(
|
||||
fieldController: widget.fieldController,
|
||||
rowCache: widget.rowCache,
|
||||
rowMeta: widget.event.event.rowMeta,
|
||||
viewId: widget.viewId,
|
||||
layoutSettings: settings,
|
||||
);
|
||||
},
|
||||
child: DecoratedBox(
|
||||
decoration: decoration,
|
||||
child: card,
|
||||
),
|
||||
);
|
||||
|
||||
if (widget.isDraggable) {
|
||||
return Draggable<CalendarDayEvent>(
|
||||
data: widget.event,
|
||||
feedback: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: widget.constraints.maxWidth - 8.0,
|
||||
),
|
||||
child: Opacity(
|
||||
opacity: 0.6,
|
||||
child: DecoratedBox(
|
||||
decoration: decoration,
|
||||
child: card,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: card,
|
||||
);
|
||||
}
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
RowCardRenderHook<CalendarDayEvent> _calendarEventCardRenderHook(
|
||||
|
@ -65,14 +65,15 @@ class CalendarEventEditor extends StatelessWidget {
|
||||
}
|
||||
|
||||
class EventEditorControls extends StatelessWidget {
|
||||
final RowController rowController;
|
||||
final FieldController fieldController;
|
||||
const EventEditorControls({
|
||||
super.key,
|
||||
required this.rowController,
|
||||
required this.fieldController,
|
||||
});
|
||||
|
||||
final RowController rowController;
|
||||
final FieldController fieldController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
|
@ -1,11 +1,13 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/show_flowy_mobile_bottom_sheet.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/database_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart';
|
||||
import 'package:appflowy/plugins/database_view/calendar/application/unschedule_event_bloc.dart';
|
||||
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database_view/tab_bar/tab_bar_view.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
@ -18,6 +20,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../application/row/row_cache.dart';
|
||||
import '../../application/row/row_controller.dart';
|
||||
@ -65,24 +68,25 @@ class CalendarPageTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
||||
}
|
||||
|
||||
class CalendarPage extends StatefulWidget {
|
||||
final ViewPB view;
|
||||
final DatabaseController databaseController;
|
||||
final bool shrinkWrap;
|
||||
const CalendarPage({
|
||||
super.key,
|
||||
required this.view,
|
||||
required this.databaseController,
|
||||
this.shrinkWrap = false,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final ViewPB view;
|
||||
final DatabaseController databaseController;
|
||||
final bool shrinkWrap;
|
||||
|
||||
@override
|
||||
State<CalendarPage> createState() => _CalendarPageState();
|
||||
}
|
||||
|
||||
class _CalendarPageState extends State<CalendarPage> {
|
||||
final _eventController = EventController<CalendarDayEvent>();
|
||||
late final CalendarBloc _calendarBloc;
|
||||
GlobalKey<MonthViewState>? _calendarState;
|
||||
late CalendarBloc _calendarBloc;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -181,18 +185,21 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
int firstDayOfWeek,
|
||||
) {
|
||||
return Padding(
|
||||
padding: CalendarSize.contentInsets,
|
||||
padding: PlatformExtension.isMobile
|
||||
? CalendarSize.contentInsetsMobile
|
||||
: CalendarSize.contentInsets,
|
||||
child: LayoutBuilder(
|
||||
// must specify MonthView width for useAvailableVerticalSpace to work properly
|
||||
builder: (context, constraints) => ScrollConfiguration(
|
||||
behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
|
||||
child: MonthView(
|
||||
key: _calendarState,
|
||||
// TODO(Xazin): Border Color on Mobile
|
||||
controller: _eventController,
|
||||
width: constraints.maxWidth,
|
||||
cellAspectRatio: 0.6,
|
||||
cellAspectRatio: PlatformExtension.isMobile ? 1 : 0.6,
|
||||
startDay: _weekdayFromInt(firstDayOfWeek),
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
showBorder: false,
|
||||
headerBuilder: _headerNavigatorBuilder,
|
||||
weekDayBuilder: _headerWeekDayBuilder,
|
||||
cellBuilder: _calendarDayBuilder,
|
||||
@ -209,9 +216,39 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
FlowyText.medium(
|
||||
DateFormat('MMMM y', context.locale.toLanguageTag())
|
||||
.format(currentMonth),
|
||||
GestureDetector(
|
||||
onTap: PlatformExtension.isMobile
|
||||
? () => showFlowyMobileBottomSheet(
|
||||
context,
|
||||
title: LocaleKeys.calendar_quickJumpYear.tr(),
|
||||
builder: (_) => SizedBox(
|
||||
height: 200,
|
||||
child: YearPicker(
|
||||
firstDate: CalendarConstants.epochDate.withoutTime,
|
||||
lastDate: CalendarConstants.maxDate.withoutTime,
|
||||
selectedDate: currentMonth,
|
||||
initialDate: currentMonth,
|
||||
currentDate: DateTime.now(),
|
||||
onChanged: (newDate) {
|
||||
_calendarState?.currentState?.jumpToMonth(newDate);
|
||||
context.pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: Row(
|
||||
children: [
|
||||
FlowyText.medium(
|
||||
DateFormat('MMMM y', context.locale.toLanguageTag())
|
||||
.format(currentMonth),
|
||||
),
|
||||
if (PlatformExtension.isMobile) ...[
|
||||
const HSpace(6),
|
||||
const FlowySvg(FlowySvgs.arrow_down_s),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
FlowyIconButton(
|
||||
@ -253,7 +290,12 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
Widget _headerWeekDayBuilder(day) {
|
||||
// incoming day starts from Monday, the symbols start from Sunday
|
||||
final symbols = DateFormat.EEEE(context.locale.toLanguageTag()).dateSymbols;
|
||||
final weekDayString = symbols.WEEKDAYS[(day + 1) % 7];
|
||||
String weekDayString = symbols.WEEKDAYS[(day + 1) % 7];
|
||||
|
||||
if (PlatformExtension.isMobile) {
|
||||
weekDayString = weekDayString.substring(0, 3);
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: CalendarSize.daysOfWeekInsets,
|
||||
@ -271,14 +313,14 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
List<CalendarEventData<CalendarDayEvent>> calenderEvents,
|
||||
isToday,
|
||||
isInMonth,
|
||||
position,
|
||||
) {
|
||||
final events = calenderEvents.map((value) => value.event!).toList();
|
||||
// Sort the events by timestamp. Because the database view is not
|
||||
// reserving the order of the events. Reserving the order of the rows/events
|
||||
// is implemnted in the develop branch(WIP). Will be replaced with that.
|
||||
events.sort(
|
||||
(a, b) => a.event.timestamp.compareTo(b.event.timestamp),
|
||||
);
|
||||
final events = calenderEvents.map((value) => value.event!).toList()
|
||||
..sort((a, b) => a.event.timestamp.compareTo(b.event.timestamp));
|
||||
|
||||
return CalendarDayCard(
|
||||
viewId: widget.view.id,
|
||||
isToday: isToday,
|
||||
@ -286,11 +328,9 @@ class _CalendarPageState extends State<CalendarPage> {
|
||||
events: events,
|
||||
date: date,
|
||||
rowCache: _calendarBloc.rowCache,
|
||||
onCreateEvent: (date) {
|
||||
_calendarBloc.add(
|
||||
CalendarEvent.createEvent(date),
|
||||
);
|
||||
},
|
||||
onCreateEvent: (date) =>
|
||||
_calendarBloc.add(CalendarEvent.createEvent(date)),
|
||||
position: position,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,13 @@ class CalendarSize {
|
||||
CalendarSize.headerContainerPadding,
|
||||
);
|
||||
|
||||
static EdgeInsets get contentInsetsMobile => EdgeInsets.fromLTRB(
|
||||
GridSize.leadingHeaderPadding / 2,
|
||||
CalendarSize.headerContainerPadding / 2,
|
||||
GridSize.leadingHeaderPadding / 2,
|
||||
CalendarSize.headerContainerPadding / 2,
|
||||
);
|
||||
|
||||
static double get scrollBarSize => 8 * scale;
|
||||
static double get navigatorButtonWidth => 20 * scale;
|
||||
static double get navigatorButtonHeight => 24 * scale;
|
||||
|
@ -7,14 +7,15 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class MobileGridSettingButton extends StatelessWidget {
|
||||
final DatabaseController controller;
|
||||
final ToggleExtensionNotifier toggleExtension;
|
||||
const MobileGridSettingButton({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.toggleExtension,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final DatabaseController controller;
|
||||
final ToggleExtensionNotifier toggleExtension;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
@ -49,10 +50,18 @@ class MobileGridSettingButton extends StatelessWidget {
|
||||
if (isLoading) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return IconButton(
|
||||
onPressed: () {},
|
||||
icon: const FlowySvg(
|
||||
FlowySvgs.m_setting_m,
|
||||
|
||||
return SizedBox(
|
||||
height: 24,
|
||||
width: 24,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
// TODO(Xazin): Database Settings
|
||||
onPressed: () {},
|
||||
icon: const FlowySvg(
|
||||
FlowySvgs.m_setting_m,
|
||||
size: Size.square(24),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
@ -24,7 +24,7 @@ class MobileTabBarHeader extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
|
@ -4,11 +4,12 @@ import 'package:appflowy/plugins/database_view/tab_bar/mobile/mobile_tab_bar_hea
|
||||
import 'package:appflowy/plugins/database_view/widgets/share_button.dart';
|
||||
import 'package:appflowy/plugins/util.dart';
|
||||
import 'package:appflowy/startup/plugin/plugin.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/home_stack.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/tab_bar_item.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
@ -85,6 +86,7 @@ class _DatabaseTabBarViewState extends State<DatabaseTabBarView> {
|
||||
],
|
||||
child: Column(
|
||||
children: [
|
||||
if (PlatformExtension.isMobile) const VSpace(12),
|
||||
BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>(
|
||||
builder: (context, state) {
|
||||
return ValueListenableBuilder<bool>(
|
||||
@ -96,11 +98,14 @@ class _DatabaseTabBarViewState extends State<DatabaseTabBarView> {
|
||||
if (value) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
child: PlatformExtension.isDesktop
|
||||
? const TabBarHeader()
|
||||
: const MobileTabBarHeader(),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: PlatformExtension.isMobile ? 20 : 40,
|
||||
),
|
||||
child: PlatformExtension.isMobile
|
||||
? const MobileTabBarHeader()
|
||||
: const TabBarHeader(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -95,11 +95,11 @@ class _DatabaseSettingListPopoverState
|
||||
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.zero,
|
||||
controller: ScrollController(),
|
||||
itemCount: cells.length,
|
||||
separatorBuilder: (context, index) {
|
||||
return VSpace(GridSize.typeOptionSeparatorHeight);
|
||||
},
|
||||
separatorBuilder: (context, index) =>
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
physics: StyledScrollPhysics(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return cells[index];
|
||||
|
@ -3,6 +3,7 @@ import 'package:appflowy/mobile/presentation/database/card/card_detail/mobile_cr
|
||||
import 'package:appflowy/mobile/presentation/database/card/card_property_edit/card_property_edit_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/card/row/cells/cells.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_board_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_calendar_events_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_calendar_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/database/mobile_grid_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/favorite/mobile_favorite_page.dart';
|
||||
@ -77,6 +78,10 @@ GoRouter generateRouter(Widget child) {
|
||||
_mobileCodeLanguagePickerPageRoute(),
|
||||
_mobileLanguagePickerPageRoute(),
|
||||
_mobileFontPickerPageRoute(),
|
||||
|
||||
// calendar related
|
||||
_mobileCalendarEventsPageRoute(),
|
||||
|
||||
_mobileBlockSettingsPageRoute(),
|
||||
],
|
||||
|
||||
@ -331,6 +336,25 @@ GoRoute _mobileFontPickerPageRoute() {
|
||||
);
|
||||
}
|
||||
|
||||
GoRoute _mobileCalendarEventsPageRoute() {
|
||||
return GoRoute(
|
||||
path: MobileCalendarEventsScreen.routeName,
|
||||
pageBuilder: (context, state) {
|
||||
final args = state.extra as Map<String, dynamic>;
|
||||
|
||||
return MaterialPage(
|
||||
child: MobileCalendarEventsScreen(
|
||||
calendarBloc: args[MobileCalendarEventsScreen.calendarBlocKey],
|
||||
date: args[MobileCalendarEventsScreen.calendarDateKey],
|
||||
events: args[MobileCalendarEventsScreen.calendarEventsKey],
|
||||
rowCache: args[MobileCalendarEventsScreen.calendarRowCacheKey],
|
||||
viewId: args[MobileCalendarEventsScreen.calendarViewIdKey],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
GoRoute _desktopHomeScreenRoute() {
|
||||
return GoRoute(
|
||||
path: DesktopHomeScreen.routeName,
|
||||
|
@ -8,6 +8,7 @@ import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
import 'package:appflowy/user/application/historical_user_bloc.dart';
|
||||
import 'package:appflowy/user/presentation/router.dart';
|
||||
import 'package:appflowy/user/presentation/widgets/widgets.dart';
|
||||
import 'package:appflowy/util/platform_extension.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_language_view.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
@ -53,7 +54,7 @@ class _SkipLogInScreenState extends State<SkipLogInScreen> {
|
||||
const Spacer(),
|
||||
FlowyLogoTitle(
|
||||
title: LocaleKeys.welcomeText.tr(),
|
||||
logoSize: const Size.square(40),
|
||||
logoSize: Size.square(PlatformExtension.isMobile ? 80 : 40),
|
||||
),
|
||||
const VSpace(32),
|
||||
GoButton(
|
||||
@ -113,14 +114,14 @@ class SkipLoginPageFooter extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
// The placeholderWidth should be greater than the longest width of the LanguageSelectorOnWelcomePage
|
||||
const double placeholderWidth = 180;
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
HSpace(placeholderWidth),
|
||||
Expanded(child: SubscribeButtons()),
|
||||
SizedBox(
|
||||
if (!PlatformExtension.isMobile) const HSpace(placeholderWidth),
|
||||
const Expanded(child: SubscribeButtons()),
|
||||
const SizedBox(
|
||||
width: placeholderWidth,
|
||||
height: 28,
|
||||
child: Row(
|
||||
|
@ -5,14 +5,15 @@ import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
class FlowyLogoTitle extends StatelessWidget {
|
||||
final String title;
|
||||
final Size logoSize;
|
||||
const FlowyLogoTitle({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.logoSize = const Size.square(40),
|
||||
});
|
||||
|
||||
final String title;
|
||||
final Size logoSize;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
|
@ -205,11 +205,12 @@ packages:
|
||||
calendar_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: calendar_view
|
||||
sha256: "58a8b851ac0a2d62770fd06ad30f06683bd40848a5dd1a1eca332f5a6064bd82"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
path: "."
|
||||
ref: "6fe0c98"
|
||||
resolved-ref: "6fe0c989289b077569858d5472f3f7ec05b7746f"
|
||||
url: "https://github.com/Xazin/flutter_calendar_view"
|
||||
source: git
|
||||
version: "1.0.5"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -47,7 +47,7 @@ dependencies:
|
||||
appflowy_editor:
|
||||
git:
|
||||
url: https://github.com/AppFlowy-IO/appflowy-editor.git
|
||||
ref: '31acaff'
|
||||
ref: "31acaff"
|
||||
|
||||
appflowy_popover:
|
||||
path: packages/appflowy_popover
|
||||
@ -94,7 +94,10 @@ dependencies:
|
||||
shared_preferences: ^2.1.1
|
||||
google_fonts: ^4.0.5
|
||||
percent_indicator: ^4.2.3
|
||||
calendar_view: ^1.0.3
|
||||
calendar_view:
|
||||
git:
|
||||
url: https://github.com/Xazin/flutter_calendar_view
|
||||
ref: "6fe0c98"
|
||||
window_manager: ^0.3.4
|
||||
http: ^1.0.0
|
||||
path: ^1.8.3
|
||||
|
@ -854,7 +854,8 @@
|
||||
"clickToAdd": "Click to add to the calendar",
|
||||
"name": "Calendar layout"
|
||||
},
|
||||
"referencedCalendarPrefix": "View of"
|
||||
"referencedCalendarPrefix": "View of",
|
||||
"quickJumpYear": "Jump to"
|
||||
},
|
||||
"errorDialog": {
|
||||
"title": "AppFlowy Error",
|
||||
|
Loading…
Reference in New Issue
Block a user