6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 7c4f40e0

AuthorEdmir Suljic<esu@dwarf.dk>
Date2025-06-23 12:27:26 +0200
Restructured hotel information

Changed files

comwell_key_app/assets/translations/da-DK.json     |   4 +-
 comwell_key_app/assets/translations/en-US.json     |   4 +-
 .../hotel_information/models/facilities.g.dart     |  33 ++-
 .../hotel_information/models/parking_info.g.dart   |  19 +-
 .../hotel_information/models/restaurant.g.dart     |  22 +-
 .../.generated/hotel_information/models/spa.g.dart |  17 +-
 .../models/structured_text.g.dart                  | 191 ++++++++++++-
 .../hotel_information/components/image_widget.dart |   2 +
 .../components/practical_information.dart          |   5 +-
 .../components/structured_text.dart                | 126 ++++++++-
 .../lib/hotel_information/models/facilities.dart   |  47 ++--
 .../lib/hotel_information/models/parking_info.dart |  48 +---
 .../lib/hotel_information/models/restaurant.dart   |  58 +---
 .../lib/hotel_information/models/spa.dart          |  46 +---
 .../hotel_information/models/structured_text.dart  | 301 ++++++++++++++++++++-
 .../pages/hotel_information_menu.dart              |   6 +-
 .../pages/parking_facility_page.dart               |  46 +---
 .../pages/restaurant_facility_page.dart            |  96 +------
 .../hotel_information/pages/spa_facility_page.dart |  76 ++----
 .../components/communications_list.dart            |   2 +-
 comwell_key_app/lib/routing/app_router.dart        |  13 +-
 .../lib/up_sales/pages/room_upgrade_page.dart      |   4 +-
 22 files changed, 770 insertions(+), 396 deletions(-)

Diff

diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index 63be253f..bd6b2978 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -284,5 +284,7 @@
"confirm_up_sales_dialog_title": "Bekræft tilkøb",
"confirm_up_sales_dialog_subtitle": "Er du sikker på, at du vil tilføje disse tilkøb for {} kr. til din booking?",
"confirm_up_sales_dialog_confirm": "Ja, tilføj tilkøb",
- "confirm_up_sales_dialog_cancel": "Nej"
+ "confirm_up_sales_dialog_cancel": "Nej",
+ "email_launch_error": "Kunne ikke åbne email klient",
+ "phone_launch_error": "Kunne ikke åbne telefon"
}
\ No newline at end of file
diff --git a/comwell_key_app/assets/translations/en-US.json b/comwell_key_app/assets/translations/en-US.json
index 055920e4..305662be 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -283,6 +283,8 @@
"confirm_up_sales_dialog_title": "Confirm upgrades",
"confirm_up_sales_dialog_subtitle": "Are you sure you want to add these upgrades for {} kr to your booking?",
"confirm_up_sales_dialog_confirm": "Yes, add upgrades",
- "confirm_up_sales_dialog_cancel": "No"
+ "confirm_up_sales_dialog_cancel": "No",
+ "email_launch_error": "Could not launch email client",
+ "phone_launch_error": "Could not launch phone call"
}
diff --git a/comwell_key_app/lib/.generated/hotel_information/models/facilities.g.dart b/comwell_key_app/lib/.generated/hotel_information/models/facilities.g.dart
index 3648eebc..0dfcabe9 100644
--- a/comwell_key_app/lib/.generated/hotel_information/models/facilities.g.dart
+++ b/comwell_key_app/lib/.generated/hotel_information/models/facilities.g.dart
@@ -6,10 +6,35 @@ part of '../../../hotel_information/models/facilities.dart';
// JsonSerializableGenerator
// **************************************************************************
+Facility _$FacilityFromJson(Map json) => Facility(
+ title: json['title'] as String,
+ headerImage: json['headerImage'] as String?,
+ structuredText: (json['structuredText'] as List<dynamic>)
+ .map((e) =>
+ StructuredTextBlock.fromJson(Map<String, dynamic>.from(e as Map)))
+ .toList(),
+ callToAction: json['callToAction'] == null
+ ? null
+ : CallToAction.fromJson(
+ Map<String, dynamic>.from(json['callToAction'] as Map)),
+ );
+
Map<String, dynamic> _$FacilityToJson(Facility instance) => <String, dynamic>{
- r'$type': instance.type,
'title': instance.title,
- 'iconPath': instance.iconPath,
- 'routeName': instance.routeName,
- 'value': instance.value,
+ 'headerImage': instance.headerImage,
+ 'structuredText': instance.structuredText.map((e) => e.toJson()).toList(),
+ 'callToAction': instance.callToAction?.toJson(),
+ };
+
+CallToAction _$CallToActionFromJson(Map json) => CallToAction(
+ name: json['name'] as String,
+ url: json['url'] as String,
+ target: json['target'] as String?,
+ );
+
+Map<String, dynamic> _$CallToActionToJson(CallToAction instance) =>
+ <String, dynamic>{
+ 'name': instance.name,
+ 'url': instance.url,
+ 'target': instance.target,
};
diff --git a/comwell_key_app/lib/.generated/hotel_information/models/parking_info.g.dart b/comwell_key_app/lib/.generated/hotel_information/models/parking_info.g.dart
index 0ab13115..0c0d99d5 100644
--- a/comwell_key_app/lib/.generated/hotel_information/models/parking_info.g.dart
+++ b/comwell_key_app/lib/.generated/hotel_information/models/parking_info.g.dart
@@ -8,22 +8,21 @@ part of '../../../hotel_information/models/parking_info.dart';
ParkingInfo _$ParkingInfoFromJson(Map json) => ParkingInfo(
title: json['title'] as String,
- electricCharging: json['electricCharging'] as bool,
- electricChargingTitle: json['electricChargingTitle'] as String,
- electricChargingDescription:
- json['electricChargingDescription'] as String,
- structuredTextBlocks: (json['structuredTextBlocks'] as List<dynamic>)
+ headerImage: json['headerImage'] as String?,
+ structuredText: (json['structuredText'] as List<dynamic>)
.map((e) =>
StructuredTextBlock.fromJson(Map<String, dynamic>.from(e as Map)))
.toList(),
+ callToAction: json['callToAction'] == null
+ ? null
+ : CallToAction.fromJson(
+ Map<String, dynamic>.from(json['callToAction'] as Map)),
);
Map<String, dynamic> _$ParkingInfoToJson(ParkingInfo instance) =>
<String, dynamic>{
'title': instance.title,
- 'electricCharging': instance.electricCharging,
- 'electricChargingTitle': instance.electricChargingTitle,
- 'electricChargingDescription': instance.electricChargingDescription,
- 'structuredTextBlocks':
- instance.structuredTextBlocks.map((e) => e.toJson()).toList(),
+ 'headerImage': instance.headerImage,
+ 'structuredText': instance.structuredText.map((e) => e.toJson()).toList(),
+ 'callToAction': instance.callToAction?.toJson(),
};
diff --git a/comwell_key_app/lib/.generated/hotel_information/models/restaurant.g.dart b/comwell_key_app/lib/.generated/hotel_information/models/restaurant.g.dart
index d540d0f7..a8a7c588 100644
--- a/comwell_key_app/lib/.generated/hotel_information/models/restaurant.g.dart
+++ b/comwell_key_app/lib/.generated/hotel_information/models/restaurant.g.dart
@@ -8,25 +8,21 @@ part of '../../../hotel_information/models/restaurant.dart';
Restaurant _$RestaurantFromJson(Map json) => Restaurant(
title: json['title'] as String,
- image: json['image'] as String,
- address: json['address'] as String,
- openingHours: json['openingHours'] as String,
- phoneNumber: json['phoneNumber'] as String,
- email: json['email'] as String,
- structuredTextBlocks: (json['structuredText'] as List<dynamic>)
+ headerImage: json['headerImage'] as String?,
+ structuredText: (json['structuredText'] as List<dynamic>)
.map((e) =>
StructuredTextBlock.fromJson(Map<String, dynamic>.from(e as Map)))
.toList(),
+ callToAction: json['callToAction'] == null
+ ? null
+ : CallToAction.fromJson(
+ Map<String, dynamic>.from(json['callToAction'] as Map)),
);
Map<String, dynamic> _$RestaurantToJson(Restaurant instance) =>
<String, dynamic>{
'title': instance.title,
- 'image': instance.image,
- 'address': instance.address,
- 'openingHours': instance.openingHours,
- 'phoneNumber': instance.phoneNumber,
- 'email': instance.email,
- 'structuredText':
- instance.structuredTextBlocks.map((e) => e.toJson()).toList(),
+ 'headerImage': instance.headerImage,
+ 'structuredText': instance.structuredText.map((e) => e.toJson()).toList(),
+ 'callToAction': instance.callToAction?.toJson(),
};
diff --git a/comwell_key_app/lib/.generated/hotel_information/models/spa.g.dart b/comwell_key_app/lib/.generated/hotel_information/models/spa.g.dart
index ebaf87e2..c1a23cfb 100644
--- a/comwell_key_app/lib/.generated/hotel_information/models/spa.g.dart
+++ b/comwell_key_app/lib/.generated/hotel_information/models/spa.g.dart
@@ -8,21 +8,22 @@ part of '../../../hotel_information/models/spa.dart';
Spa _$SpaFromJson(Map json) => Spa(
title: json['title'] as String,
- image: json['image'] as String,
- spaBookingLink: SpaBookingLink.fromJson(
- Map<String, dynamic>.from(json['spaBookingLink'] as Map)),
- structuredTextBlocks: (json['structuredText'] as List<dynamic>)
+ headerImage: json['headerImage'] as String?,
+ structuredText: (json['structuredText'] as List<dynamic>)
.map((e) =>
StructuredTextBlock.fromJson(Map<String, dynamic>.from(e as Map)))
.toList(),
+ callToAction: json['callToAction'] == null
+ ? null
+ : CallToAction.fromJson(
+ Map<String, dynamic>.from(json['callToAction'] as Map)),
);
Map<String, dynamic> _$SpaToJson(Spa instance) => <String, dynamic>{
'title': instance.title,
- 'image': instance.image,
- 'spaBookingLink': instance.spaBookingLink.toJson(),
- 'structuredText':
- instance.structuredTextBlocks.map((e) => e.toJson()).toList(),
+ 'headerImage': instance.headerImage,
+ 'structuredText': instance.structuredText.map((e) => e.toJson()).toList(),
+ 'callToAction': instance.callToAction?.toJson(),
};
SpaBookingLink _$SpaBookingLinkFromJson(Map json) => SpaBookingLink(
diff --git a/comwell_key_app/lib/.generated/hotel_information/models/structured_text.g.dart b/comwell_key_app/lib/.generated/hotel_information/models/structured_text.g.dart
index 7c45d5be..c6313d91 100644
--- a/comwell_key_app/lib/.generated/hotel_information/models/structured_text.g.dart
+++ b/comwell_key_app/lib/.generated/hotel_information/models/structured_text.g.dart
@@ -6,15 +6,190 @@ part of '../../../hotel_information/models/structured_text.dart';
// JsonSerializableGenerator
// **************************************************************************
-StructuredTextBlock _$StructuredTextBlockFromJson(Map json) =>
- StructuredTextBlock(
- type: json['type'] as String,
- data: json['data'] as String,
+HeaderStructuredTextModel _$HeaderStructuredTextModelFromJson(Map json) =>
+ HeaderStructuredTextModel(
+ type: json[r'$type'] as String? ?? 'HeaderStructuredTextModel',
+ header: json['header'] as String,
);
-Map<String, dynamic> _$StructuredTextBlockToJson(
- StructuredTextBlock instance) =>
+Map<String, dynamic> _$HeaderStructuredTextModelToJson(
+ HeaderStructuredTextModel instance) =>
<String, dynamic>{
- 'type': instance.type,
- 'data': instance.data,
+ r'$type': instance.type,
+ 'header': instance.header,
+ };
+
+TextModelStructuredTextModel _$TextModelStructuredTextModelFromJson(Map json) =>
+ TextModelStructuredTextModel(
+ type: json[r'$type'] as String? ?? 'TextModelStructuredTextModel',
+ text: json['text'] as String,
+ );
+
+Map<String, dynamic> _$TextModelStructuredTextModelToJson(
+ TextModelStructuredTextModel instance) =>
+ <String, dynamic>{
+ r'$type': instance.type,
+ 'text': instance.text,
+ };
+
+AddressStructuredTextModel _$AddressStructuredTextModelFromJson(Map json) =>
+ AddressStructuredTextModel(
+ type: json[r'$type'] as String? ?? 'AddressStructuredTextModel',
+ headline: json['headline'] as String,
+ address: json['address'] as String,
+ );
+
+Map<String, dynamic> _$AddressStructuredTextModelToJson(
+ AddressStructuredTextModel instance) =>
+ <String, dynamic>{
+ r'$type': instance.type,
+ 'headline': instance.headline,
+ 'address': instance.address,
+ };
+
+EmailContactStructuredTextModel _$EmailContactStructuredTextModelFromJson(
+ Map json) =>
+ EmailContactStructuredTextModel(
+ type: json[r'$type'] as String? ?? 'EmailContactStructuredTextModel',
+ headline: json['headline'] as String,
+ email: json['email'] as String,
+ );
+
+Map<String, dynamic> _$EmailContactStructuredTextModelToJson(
+ EmailContactStructuredTextModel instance) =>
+ <String, dynamic>{
+ r'$type': instance.type,
+ 'headline': instance.headline,
+ 'email': instance.email,
+ };
+
+PhoneContactStructuredTextModel _$PhoneContactStructuredTextModelFromJson(
+ Map json) =>
+ PhoneContactStructuredTextModel(
+ type: json[r'$type'] as String? ?? 'PhoneContactStructuredTextModel',
+ headline: json['headline'] as String,
+ phoneNumber: json['phoneNumber'] as String,
+ );
+
+Map<String, dynamic> _$PhoneContactStructuredTextModelToJson(
+ PhoneContactStructuredTextModel instance) =>
+ <String, dynamic>{
+ r'$type': instance.type,
+ 'headline': instance.headline,
+ 'phoneNumber': instance.phoneNumber,
+ };
+
+ImageWidgetStructuredTextModel _$ImageWidgetStructuredTextModelFromJson(
+ Map json) =>
+ ImageWidgetStructuredTextModel(
+ type: json['\x024type'] as String? ?? 'ImageWidgetStructuredTextModel',
+ image: json['image'] as String,
+ );
+
+Map<String, dynamic> _$ImageWidgetStructuredTextModelToJson(
+ ImageWidgetStructuredTextModel instance) =>
+ <String, dynamic>{
+ '\x024type': instance.type,
+ 'image': instance.image,
+ };
+
+SpaBookingLinkStructuredTextModel _$SpaBookingLinkStructuredTextModelFromJson(
+ Map json) =>
+ SpaBookingLinkStructuredTextModel(
+ type: json['\x024type'] as String? ?? 'SpaBookingLinkStructuredTextModel',
+ link: json['link'] as String,
+ );
+
+Map<String, dynamic> _$SpaBookingLinkStructuredTextModelToJson(
+ SpaBookingLinkStructuredTextModel instance) =>
+ <String, dynamic>{
+ '\x024type': instance.type,
+ 'link': instance.link,
+ };
+
+HotelInformationListTileStructuredTextModel
+ _$HotelInformationListTileStructuredTextModelFromJson(Map json) =>
+ HotelInformationListTileStructuredTextModel(
+ type: json['\x024type'] as String? ??
+ 'HotelInformationListTileStructuredTextModel',
+ iconPath: json['iconPath'] as String,
+ title: json['title'] as String,
+ );
+
+Map<String, dynamic> _$HotelInformationListTileStructuredTextModelToJson(
+ HotelInformationListTileStructuredTextModel instance) =>
+ <String, dynamic>{
+ '\x024type': instance.type,
+ 'iconPath': instance.iconPath,
+ 'title': instance.title,
+ };
+
+MapsBottomModalStructuredTextModel _$MapsBottomModalStructuredTextModelFromJson(
+ Map json) =>
+ MapsBottomModalStructuredTextModel(
+ type:
+ json['\x024type'] as String? ?? 'MapsBottomModalStructuredTextModel',
+ address: json['address'] as String,
+ );
+
+Map<String, dynamic> _$MapsBottomModalStructuredTextModelToJson(
+ MapsBottomModalStructuredTextModel instance) =>
+ <String, dynamic>{
+ '\x024type': instance.type,
+ 'address': instance.address,
+ };
+
+OpeningHoursStructuredTextModel _$OpeningHoursStructuredTextModelFromJson(
+ Map json) =>
+ OpeningHoursStructuredTextModel(
+ type: json['\x024type'] as String? ?? 'OpeningHoursStructuredTextModel',
+ openingHours: json['openingHours'] as String,
+ );
+
+Map<String, dynamic> _$OpeningHoursStructuredTextModelToJson(
+ OpeningHoursStructuredTextModel instance) =>
+ <String, dynamic>{
+ '\x024type': instance.type,
+ 'openingHours': instance.openingHours,
+ };
+
+PageTitleStructuredTextModel _$PageTitleStructuredTextModelFromJson(Map json) =>
+ PageTitleStructuredTextModel(
+ type: json['\x024type'] as String? ?? 'PageTitleStructuredTextModel',
+ title: json['title'] as String,
+ );
+
+Map<String, dynamic> _$PageTitleStructuredTextModelToJson(
+ PageTitleStructuredTextModel instance) =>
+ <String, dynamic>{
+ '\x024type': instance.type,
+ 'title': instance.title,
+ };
+
+PracticalInformationStructuredTextModel
+ _$PracticalInformationStructuredTextModelFromJson(Map json) =>
+ PracticalInformationStructuredTextModel(
+ type: json['\x024type'] as String? ??
+ 'PracticalInformationStructuredTextModel',
+ restaurantId: json['restaurantId'] as String,
+ );
+
+Map<String, dynamic> _$PracticalInformationStructuredTextModelToJson(
+ PracticalInformationStructuredTextModel instance) =>
+ <String, dynamic>{
+ '\x024type': instance.type,
+ 'restaurantId': instance.restaurantId,
+ };
+
+EmailStructuredTextModel _$EmailStructuredTextModelFromJson(Map json) =>
+ EmailStructuredTextModel(
+ type: json['\x024type'] as String? ?? 'EmailStructuredTextModel',
+ email: json['email'] as String,
+ );
+
+Map<String, dynamic> _$EmailStructuredTextModelToJson(
+ EmailStructuredTextModel instance) =>
+ <String, dynamic>{
+ '\x024type': instance.type,
+ 'email': instance.email,
};
diff --git a/comwell_key_app/lib/hotel_information/components/image_widget.dart b/comwell_key_app/lib/hotel_information/components/image_widget.dart
index 27c063e9..1a28e6d5 100644
--- a/comwell_key_app/lib/hotel_information/components/image_widget.dart
+++ b/comwell_key_app/lib/hotel_information/components/image_widget.dart
@@ -29,6 +29,8 @@ class ImageWidget extends StatelessWidget {
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
+ // This code makes the loading spinner show actual progress if possible,
+ // or just spin if the total size is unknown, providing a better user experience while images load.
final progress = loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null;
diff --git a/comwell_key_app/lib/hotel_information/components/practical_information.dart b/comwell_key_app/lib/hotel_information/components/practical_information.dart
index 569977dd..fce7b000 100644
--- a/comwell_key_app/lib/hotel_information/components/practical_information.dart
+++ b/comwell_key_app/lib/hotel_information/components/practical_information.dart
@@ -1,5 +1,6 @@
import 'package:comwell_key_app/hotel_information/components/maps_bottom_modal.dart';
import 'package:comwell_key_app/hotel_information/models/restaurant.dart';
+import 'package:comwell_key_app/hotel_information/models/structured_text.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
@@ -25,9 +26,9 @@ class PracticalInformation extends StatelessWidget {
style: theme.textTheme.headlineMedium,
),
GestureDetector(
- onTap: () => MapsBottomModal.show(context, restaurant.address),
+ onTap: () => MapsBottomModal.show(context, restaurant.structuredText.firstWhere((block) => block is AddressStructuredTextModel).toString()),
child: Text(
- restaurant.address,
+ restaurant.structuredText.firstWhere((block) => block is AddressStructuredTextModel).toString(),
style: theme.textTheme.bodySmall?.copyWith(
color: sandColor,
decoration: TextDecoration.underline,
diff --git a/comwell_key_app/lib/hotel_information/components/structured_text.dart b/comwell_key_app/lib/hotel_information/components/structured_text.dart
index 5a5b3962..dc0c884e 100644
--- a/comwell_key_app/lib/hotel_information/components/structured_text.dart
+++ b/comwell_key_app/lib/hotel_information/components/structured_text.dart
@@ -1,5 +1,17 @@
import 'package:comwell_key_app/hotel_information/models/structured_text.dart';
+import 'package:comwell_key_app/hotel_information/components/address.dart';
+import 'package:comwell_key_app/hotel_information/components/phone_number.dart';
+import 'package:comwell_key_app/hotel_information/components/contact_hotel_button.dart';
+import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
+import 'package:url_launcher/url_launcher.dart';
+import 'package:comwell_key_app/hotel_information/components/image_widget.dart';
+import 'package:comwell_key_app/hotel_information/components/spa_booking_link.dart';
+import 'package:comwell_key_app/hotel_information/components/hotel_information_list_tile.dart';
+import 'package:comwell_key_app/hotel_information/components/maps_bottom_modal.dart';
+import 'package:comwell_key_app/hotel_information/components/opening_hours.dart';
+import 'package:comwell_key_app/hotel_information/components/page_title.dart';
+import 'package:comwell_key_app/hotel_information/components/email.dart';
class StructuredText extends StatelessWidget {
final List<StructuredTextBlock> blocks;
@@ -12,17 +24,109 @@ class StructuredText extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: blocks.map((block) {
- return Padding(
- padding: const EdgeInsets.only(bottom: 16.0),
- child: Text(
- block.data,
- style: block.type == "headerBlock"
- ? theme.textTheme.headlineMedium
- : theme.textTheme.bodySmall?.copyWith(
- color: Colors.black.withValues(alpha: 0.65),
- ),
- ),
- );
+ if (block is HeaderStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: Text(
+ block.header,
+ style: theme.textTheme.headlineMedium,
+ ),
+ );
+ } else if (block is TextModelStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: Text(
+ block.text,
+ style: theme.textTheme.bodySmall?.copyWith(
+ color: Colors.black.withValues(alpha: 0.65),
+ ),
+ ),
+ );
+ } else if (block is AddressStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: Address(address: block.address),
+ );
+ } else if (block is EmailContactStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: ContactHotelButton(
+ title: block.headline,
+ subtitle: block.email,
+ iconPath: "assets/icons/ic_send.svg",
+ onClick: () async {
+ final Uri emailUri = Uri.parse("mailto:${block.email}");
+ if (await canLaunchUrl(emailUri)) {
+ await launchUrl(emailUri, mode: LaunchMode.externalApplication);
+ } else {
+ if (context.mounted) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(content: Text("email_launch_error".tr())),
+ );
+ }
+ }
+ },
+ ),
+ );
+ } else if (block is PhoneContactStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: PhoneNumber(phoneNumber: block.phoneNumber),
+ );
+ } else if (block is ImageWidgetStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: ImageWidget(image: block.image),
+ );
+ } else if (block is SpaBookingLinkStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: SpaBookingLink(link: block.link),
+ );
+ } else if (block is HotelInformationListTileStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: HotelInformationListTile(
+ iconPath: block.iconPath,
+ title: block.title,
+ onClick: () {}, // You may want to provide a callback
+ ),
+ );
+ } else if (block is MapsBottomModalStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: Builder(
+ builder: (context) => ElevatedButton(
+ onPressed: () => MapsBottomModal.show(context, block.address),
+ child: Text(block.address),
+ ),
+ ),
+ );
+ } else if (block is OpeningHoursStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: OpeningHours(openingHours: block.openingHours),
+ );
+ } else if (block is PageTitleStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: PageTitle(title: block.title),
+ );
+ } else if (block is PracticalInformationStructuredTextModel) {
+ // PracticalInformation expects a Restaurant, but block only has restaurantId. You may need to fetch the Restaurant by ID.
+ // For now, just show the restaurantId as a placeholder.
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: Text('Practical Information for Restaurant: \\${block.restaurantId}'),
+ );
+ } else if (block is EmailStructuredTextModel) {
+ return Padding(
+ padding: const EdgeInsets.only(bottom: 16.0),
+ child: Email(email: block.email),
+ );
+ } else {
+ return const SizedBox.shrink();
+ }
}).toList(),
);
}
diff --git a/comwell_key_app/lib/hotel_information/models/facilities.dart b/comwell_key_app/lib/hotel_information/models/facilities.dart
index d09f6613..eee9a700 100644
--- a/comwell_key_app/lib/hotel_information/models/facilities.dart
+++ b/comwell_key_app/lib/hotel_information/models/facilities.dart
@@ -1,38 +1,41 @@
-import 'package:comwell_key_app/hotel_information/models/parking_info.dart';
-import 'package:comwell_key_app/hotel_information/models/restaurant.dart';
-import 'package:comwell_key_app/hotel_information/models/spa.dart';
+import 'package:comwell_key_app/hotel_information/models/structured_text.dart';
import 'package:comwell_key_app/utils/json.dart';
import 'package:json_annotation/json_annotation.dart';
part '../../.generated/hotel_information/models/facilities.g.dart';
-@JsonSerializable(createFactory: false)
+@JsonSerializable()
class Facility {
- @JsonKey(name: '\$type')
- final String type;
final String title;
- final String iconPath;
- final String routeName;
- final Json value;
+ final String? headerImage;
+ final List<StructuredTextBlock> structuredText;
+ final CallToAction? callToAction;
Facility({
- required this.type,
required this.title,
- required this.iconPath,
- required this.routeName,
- required this.value,
+ this.headerImage,
+ required this.structuredText,
+ this.callToAction,
});
- factory Facility.fromJson(Json json) {
- return switch (json["\$type"] as String) {
- "SpaFacility" => Spa.fromJson(json),
- "RestaurantFacility" => Restaurant.fromJson(json),
- "ParkingFacility" => ParkingInfo.fromJson(json),
- _ => throw Exception("Unsupported facility type: ${json["\$type"]}")
- };
- }
-
+ factory Facility.fromJson(Json json) => _$FacilityFromJson(json);
Json toJson() => _$FacilityToJson(this);
}
+@JsonSerializable()
+class CallToAction {
+ final String name;
+ final String url;
+ final String? target;
+
+ CallToAction({
+ required this.name,
+ required this.url,
+ this.target,
+ });
+
+ factory CallToAction.fromJson(Json json) => _$CallToActionFromJson(json);
+ Json toJson() => _$CallToActionToJson(this);
+}
+
diff --git a/comwell_key_app/lib/hotel_information/models/parking_info.dart b/comwell_key_app/lib/hotel_information/models/parking_info.dart
index 41c3e734..ba6650e4 100644
--- a/comwell_key_app/lib/hotel_information/models/parking_info.dart
+++ b/comwell_key_app/lib/hotel_information/models/parking_info.dart
@@ -1,48 +1,24 @@
-import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:comwell_key_app/hotel_information/models/structured_text.dart';
+import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:comwell_key_app/utils/json.dart';
import 'package:json_annotation/json_annotation.dart';
part '../../.generated/hotel_information/models/parking_info.g.dart';
@JsonSerializable()
-class ParkingInfo extends Facility {
- final bool electricCharging;
- final String electricChargingTitle;
- final String electricChargingDescription;
- final List<StructuredTextBlock> structuredTextBlocks;
+class ParkingInfo {
+ final String title;
+ final String? headerImage;
+ final List<StructuredTextBlock> structuredText;
+ final CallToAction? callToAction;
ParkingInfo({
- required super.title,
- required this.electricCharging,
- required this.electricChargingTitle,
- required this.electricChargingDescription,
- required this.structuredTextBlocks,
- }) : super(
- type: "ParkingFacility",
- iconPath: "assets/icons/ic_car.svg",
- routeName: "parking",
- value: {
- "title": title,
- "electricCharging": electricCharging,
- "electricChargingTitle": electricChargingTitle,
- "electricChargingDescription": electricChargingDescription,
- "structuredText": structuredTextBlocks.map((block) => block.toJson()).toList(),
- },
- );
-
- factory ParkingInfo.fromJson(Json json) {
- return ParkingInfo(
- title: json["title"] as String,
- electricCharging: json["electricCharging"] as bool,
- electricChargingTitle: json["electricChargingTitle"] as String,
- electricChargingDescription: json["electricChargingDescription"] as String,
- structuredTextBlocks: (json["structuredText"] as List)
- .map((block) => StructuredTextBlock.fromJson(block as Json))
- .toList(),
- );
- }
+ required this.title,
+ this.headerImage,
+ required this.structuredText,
+ this.callToAction,
+ });
- @override
+ factory ParkingInfo.fromJson(Json json) => _$ParkingInfoFromJson(json);
Json toJson() => _$ParkingInfoToJson(this);
}
diff --git a/comwell_key_app/lib/hotel_information/models/restaurant.dart b/comwell_key_app/lib/hotel_information/models/restaurant.dart
index 8811ebab..c2f6c15d 100644
--- a/comwell_key_app/lib/hotel_information/models/restaurant.dart
+++ b/comwell_key_app/lib/hotel_information/models/restaurant.dart
@@ -1,58 +1,24 @@
-import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:comwell_key_app/hotel_information/models/structured_text.dart';
+import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:comwell_key_app/utils/json.dart';
import 'package:json_annotation/json_annotation.dart';
part '../../.generated/hotel_information/models/restaurant.g.dart';
-
@JsonSerializable()
-class Restaurant extends Facility {
- final String image;
- final String address;
- final String openingHours;
- final String phoneNumber;
- final String email;
- @JsonKey(name: 'structuredText')
- final List<StructuredTextBlock> structuredTextBlocks;
+class Restaurant {
+ final String title;
+ final String? headerImage;
+ final List<StructuredTextBlock> structuredText;
+ final CallToAction? callToAction;
Restaurant({
- required super.title,
- required this.image,
- required this.address,
- required this.openingHours,
- required this.phoneNumber,
- required this.email,
- required this.structuredTextBlocks,
- }) : super(
- type: "RestaurantFacility",
- iconPath: "assets/icons/ic_chefs_hat.svg",
- routeName: "restaurant",
- value: {
- "image": image,
- "title": title,
- "address": address,
- "openingHours": openingHours,
- "phoneNumber": phoneNumber,
- "email": email,
- "structuredText": structuredTextBlocks.map((block) => block.toJson()).toList(),
- },
- );
-
- factory Restaurant.fromJson(Json json) {
- return Restaurant(
- title: json["title"] as String,
- image: json["image"] as String,
- address: json["address"] as String,
- openingHours: json["openingHours"] as String,
- phoneNumber: json["phoneNumber"] as String,
- email: json["email"] as String,
- structuredTextBlocks: (json["structuredText"] as List)
- .map((block) => StructuredTextBlock.fromJson(block as Json))
- .toList(),
- );
- }
+ required this.title,
+ this.headerImage,
+ required this.structuredText,
+ this.callToAction,
+ });
- @override
+ factory Restaurant.fromJson(Json json) => _$RestaurantFromJson(json);
Json toJson() => _$RestaurantToJson(this);
}
diff --git a/comwell_key_app/lib/hotel_information/models/spa.dart b/comwell_key_app/lib/hotel_information/models/spa.dart
index 4d1126f8..a8f3a7d1 100644
--- a/comwell_key_app/lib/hotel_information/models/spa.dart
+++ b/comwell_key_app/lib/hotel_information/models/spa.dart
@@ -1,47 +1,25 @@
-import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:comwell_key_app/hotel_information/models/structured_text.dart';
+import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:comwell_key_app/utils/json.dart';
import 'package:json_annotation/json_annotation.dart';
part '../../.generated/hotel_information/models/spa.g.dart';
@JsonSerializable()
-class Spa extends Facility {
- final String image;
- final SpaBookingLink spaBookingLink;
- @JsonKey(name: 'structuredText')
- final List<StructuredTextBlock> structuredTextBlocks;
+class Spa {
+ final String title;
+ final String? headerImage;
+ final List<StructuredTextBlock> structuredText;
+ final CallToAction? callToAction;
Spa({
- required super.title,
- required this.image,
- required this.spaBookingLink,
- required this.structuredTextBlocks,
- }) : super(
- type: "SpaFacility",
- iconPath: "assets/icons/ic_spa.svg",
- routeName: "spa",
- value: {
- "image": image,
- "spaBookingLink": spaBookingLink.toJson(),
- "title": title,
- "structuredText":
- structuredTextBlocks.map((block) => block.toJson()).toList(),
- },
- );
-
- factory Spa.fromJson(Json json) {
- return Spa(
- title: json["title"] as String,
- image: json["image"] as String,
- spaBookingLink: SpaBookingLink.fromJson(json["spaBookingLink"] as Json),
- structuredTextBlocks: (json["structuredText"] as List)
- .map((block) => StructuredTextBlock.fromJson(block as Json))
- .toList(),
- );
- }
+ required this.title,
+ this.headerImage,
+ required this.structuredText,
+ this.callToAction,
+ });
- @override
+ factory Spa.fromJson(Json json) => _$SpaFromJson(json);
Json toJson() => _$SpaToJson(this);
}
diff --git a/comwell_key_app/lib/hotel_information/models/structured_text.dart b/comwell_key_app/lib/hotel_information/models/structured_text.dart
index d3198d72..d057cedc 100644
--- a/comwell_key_app/lib/hotel_information/models/structured_text.dart
+++ b/comwell_key_app/lib/hotel_information/models/structured_text.dart
@@ -3,16 +3,303 @@ import 'package:json_annotation/json_annotation.dart';
part '../../.generated/hotel_information/models/structured_text.g.dart';
+sealed class StructuredTextBlock {
+ factory StructuredTextBlock.fromJson(Json json) {
+ switch (json['\$type'] as String) {
+ case 'HeaderStructuredTextModel':
+ return HeaderStructuredTextModel.fromJson(json);
+ case 'TextModelStructuredTextModel':
+ return TextModelStructuredTextModel.fromJson(json);
+ case 'AddressStructuredTextModel':
+ return AddressStructuredTextModel.fromJson(json);
+ case 'EmailContactStructuredTextModel':
+ return EmailContactStructuredTextModel.fromJson(json);
+ case 'PhoneContactStructuredTextModel':
+ return PhoneContactStructuredTextModel.fromJson(json);
+ case 'ImageWidgetStructuredTextModel':
+ return ImageWidgetStructuredTextModel.fromJson(json);
+ case 'SpaBookingLinkStructuredTextModel':
+ return SpaBookingLinkStructuredTextModel.fromJson(json);
+ case 'HotelInformationListTileStructuredTextModel':
+ return HotelInformationListTileStructuredTextModel.fromJson(json);
+ case 'MapsBottomModalStructuredTextModel':
+ return MapsBottomModalStructuredTextModel.fromJson(json);
+ case 'OpeningHoursStructuredTextModel':
+ return OpeningHoursStructuredTextModel.fromJson(json);
+ case 'PageTitleStructuredTextModel':
+ return PageTitleStructuredTextModel.fromJson(json);
+ case 'PracticalInformationStructuredTextModel':
+ return PracticalInformationStructuredTextModel.fromJson(json);
+ case 'EmailStructuredTextModel':
+ return EmailStructuredTextModel.fromJson(json);
+ default:
+ throw Exception('Unknown StructuredTextBlock type: \'${json['\$type']}\'');
+ }
+ }
+ Json toJson();
+}
+
+@JsonSerializable()
+class HeaderStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '\$type')
+ final String type;
+ final String header;
+
+ HeaderStructuredTextModel({
+ this.type = 'HeaderStructuredTextModel',
+ required this.header,
+ });
+
+ factory HeaderStructuredTextModel.fromJson(Json json) => _$HeaderStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$HeaderStructuredTextModelToJson(this);
+
+ @override
+ String toString() {
+ return header;
+ }
+}
+
+@JsonSerializable()
+class TextModelStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '\$type')
+ final String type;
+ final String text;
+
+ TextModelStructuredTextModel({
+ this.type = 'TextModelStructuredTextModel',
+ required this.text,
+ });
+
+ factory TextModelStructuredTextModel.fromJson(Json json) => _$TextModelStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$TextModelStructuredTextModelToJson(this);
+
+ @override
+ String toString() {
+ return text;
+ }
+}
+
+@JsonSerializable()
+class AddressStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '\$type')
+ final String type;
+ final String headline;
+ final String address;
+
+ AddressStructuredTextModel({
+ this.type = 'AddressStructuredTextModel',
+ required this.headline,
+ required this.address,
+ });
+
+ factory AddressStructuredTextModel.fromJson(Json json) => _$AddressStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$AddressStructuredTextModelToJson(this);
+
+ @override
+ String toString() {
+ return "$headline\n$address";
+ }
+}
+
+@JsonSerializable()
+class EmailContactStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '\$type')
+ final String type;
+ final String headline;
+ final String email;
+
+ EmailContactStructuredTextModel({
+ this.type = 'EmailContactStructuredTextModel',
+ required this.headline,
+ required this.email,
+ });
+
+ factory EmailContactStructuredTextModel.fromJson(Json json) => _$EmailContactStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$EmailContactStructuredTextModelToJson(this);
+
+ @override
+ String toString() {
+ return "$headline\n$email";
+ }
+}
+
+@JsonSerializable()
+class PhoneContactStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '\$type')
+ final String type;
+ final String headline;
+ final String phoneNumber;
+
+ PhoneContactStructuredTextModel({
+ this.type = 'PhoneContactStructuredTextModel',
+ required this.headline,
+ required this.phoneNumber,
+ });
+
+ factory PhoneContactStructuredTextModel.fromJson(Json json) => _$PhoneContactStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$PhoneContactStructuredTextModelToJson(this);
+
+ @override
+ String toString() {
+ return "$headline\n$phoneNumber";
+ }
+}
+
+@JsonSerializable()
+class ImageWidgetStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '4type')
+ final String type;
+ final String image;
+
+ ImageWidgetStructuredTextModel({
+ this.type = 'ImageWidgetStructuredTextModel',
+ required this.image,
+ });
+
+ factory ImageWidgetStructuredTextModel.fromJson(Json json) => _$ImageWidgetStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$ImageWidgetStructuredTextModelToJson(this);
+
+ @override
+ String toString() => image;
+}
+
@JsonSerializable()
-class StructuredTextBlock {
+class SpaBookingLinkStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '4type')
final String type;
- final String data;
+ final String link;
- StructuredTextBlock({
- required this.type,
- required this.data,
+ SpaBookingLinkStructuredTextModel({
+ this.type = 'SpaBookingLinkStructuredTextModel',
+ required this.link,
});
- factory StructuredTextBlock.fromJson(Json json) => _$StructuredTextBlockFromJson(json);
- Json toJson() => _$StructuredTextBlockToJson(this);
+ factory SpaBookingLinkStructuredTextModel.fromJson(Json json) => _$SpaBookingLinkStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$SpaBookingLinkStructuredTextModelToJson(this);
+
+ @override
+ String toString() => link;
+}
+
+@JsonSerializable()
+class HotelInformationListTileStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '4type')
+ final String type;
+ final String iconPath;
+ final String title;
+
+ HotelInformationListTileStructuredTextModel({
+ this.type = 'HotelInformationListTileStructuredTextModel',
+ required this.iconPath,
+ required this.title,
+ });
+
+ factory HotelInformationListTileStructuredTextModel.fromJson(Json json) => _$HotelInformationListTileStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$HotelInformationListTileStructuredTextModelToJson(this);
+
+ @override
+ String toString() => title;
+}
+
+@JsonSerializable()
+class MapsBottomModalStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '4type')
+ final String type;
+ final String address;
+
+ MapsBottomModalStructuredTextModel({
+ this.type = 'MapsBottomModalStructuredTextModel',
+ required this.address,
+ });
+
+ factory MapsBottomModalStructuredTextModel.fromJson(Json json) => _$MapsBottomModalStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$MapsBottomModalStructuredTextModelToJson(this);
+
+ @override
+ String toString() => address;
+}
+
+@JsonSerializable()
+class OpeningHoursStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '4type')
+ final String type;
+ final String openingHours;
+
+ OpeningHoursStructuredTextModel({
+ this.type = 'OpeningHoursStructuredTextModel',
+ required this.openingHours,
+ });
+
+ factory OpeningHoursStructuredTextModel.fromJson(Json json) => _$OpeningHoursStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$OpeningHoursStructuredTextModelToJson(this);
+
+ @override
+ String toString() => openingHours;
+}
+
+@JsonSerializable()
+class PageTitleStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '4type')
+ final String type;
+ final String title;
+
+ PageTitleStructuredTextModel({
+ this.type = 'PageTitleStructuredTextModel',
+ required this.title,
+ });
+
+ factory PageTitleStructuredTextModel.fromJson(Json json) => _$PageTitleStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$PageTitleStructuredTextModelToJson(this);
+
+ @override
+ String toString() => title;
+}
+
+@JsonSerializable()
+class PracticalInformationStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '4type')
+ final String type;
+ final String restaurantId;
+
+ PracticalInformationStructuredTextModel({
+ this.type = 'PracticalInformationStructuredTextModel',
+ required this.restaurantId,
+ });
+
+ factory PracticalInformationStructuredTextModel.fromJson(Json json) => _$PracticalInformationStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$PracticalInformationStructuredTextModelToJson(this);
+
+ @override
+ String toString() => restaurantId;
+}
+
+@JsonSerializable()
+class EmailStructuredTextModel implements StructuredTextBlock {
+ @JsonKey(name: '4type')
+ final String type;
+ final String email;
+
+ EmailStructuredTextModel({
+ this.type = 'EmailStructuredTextModel',
+ required this.email,
+ });
+
+ factory EmailStructuredTextModel.fromJson(Json json) => _$EmailStructuredTextModelFromJson(json);
+ @override
+ Json toJson() => _$EmailStructuredTextModelToJson(this);
+
+ @override
+ String toString() => email;
}
\ No newline at end of file
diff --git a/comwell_key_app/lib/hotel_information/pages/hotel_information_menu.dart b/comwell_key_app/lib/hotel_information/pages/hotel_information_menu.dart
index bc9c2428..aba0bbda 100644
--- a/comwell_key_app/lib/hotel_information/pages/hotel_information_menu.dart
+++ b/comwell_key_app/lib/hotel_information/pages/hotel_information_menu.dart
@@ -15,7 +15,7 @@ class HotelInformationMenu extends StatelessWidget {
Widget build(BuildContext context) {
final cubit = context.read<HotelInformationCubit>();
final hotel = cubit.hotel;
-
+
return Column(
children: [
ImageWidget(image: hotel.image),
@@ -33,11 +33,11 @@ class HotelInformationMenu extends StatelessWidget {
return Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: HotelInformationListTile(
- iconPath: facility.iconPath,
+ iconPath: "assets/icons/ic_info.svg",
title: facility.title,
onClick: () {
context.pushNamed(
- "${AppRoutes.hotelInformation.name}/${facility.routeName}",
+ "${AppRoutes.hotelInformation.name}/${facility.title.toLowerCase()}",
extra: facility);
},
),
diff --git a/comwell_key_app/lib/hotel_information/pages/parking_facility_page.dart b/comwell_key_app/lib/hotel_information/pages/parking_facility_page.dart
index 04ba7884..48f4bba0 100644
--- a/comwell_key_app/lib/hotel_information/pages/parking_facility_page.dart
+++ b/comwell_key_app/lib/hotel_information/pages/parking_facility_page.dart
@@ -8,47 +8,6 @@ class ParkingFacilityPage extends StatelessWidget {
const ParkingFacilityPage({super.key, required this.parkingInfo});
- List<Widget> _buildDynamicContent(BuildContext context) {
- final theme = Theme.of(context);
- final Map<String, dynamic> parkingData = parkingInfo.toJson();
- final List<Widget> widgets = [];
-
- parkingData.forEach((key, value) {
- switch (key) {
- case 'title':
- widgets.add(Text(
- value as String,
- style: theme.textTheme.headlineLarge,
- ));
- widgets.add(const SizedBox(height: 20));
- break;
-
- case 'structuredText':
- widgets.add(StructuredText(blocks: parkingInfo.structuredTextBlocks));
- widgets.add(const SizedBox(height: 20));
- break;
-
- case 'electricCharging':
- if (value as bool) {
- widgets.add(const SizedBox(height: 40));
- widgets.add(Text(
- parkingInfo.electricChargingTitle,
- style: theme.textTheme.headlineMedium,
- ));
- widgets.add(const SizedBox(height: 20));
- widgets.add(Text(
- parkingInfo.electricChargingDescription,
- style: theme.textTheme.bodySmall,
- ));
- }
- break;
- }
- });
-
- widgets.add(const SizedBox(height: 100));
- return widgets;
- }
-
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -65,7 +24,10 @@ class ParkingFacilityPage extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
- children: _buildDynamicContent(context),
+ children: [
+ StructuredText(blocks: parkingInfo.structuredText),
+ const SizedBox(height: 100),
+ ],
),
),
),
diff --git a/comwell_key_app/lib/hotel_information/pages/restaurant_facility_page.dart b/comwell_key_app/lib/hotel_information/pages/restaurant_facility_page.dart
index 11bbfa4d..4501a1a7 100644
--- a/comwell_key_app/lib/hotel_information/pages/restaurant_facility_page.dart
+++ b/comwell_key_app/lib/hotel_information/pages/restaurant_facility_page.dart
@@ -3,115 +3,33 @@ import 'package:comwell_key_app/hotel_information/components/image_widget.dart';
import 'package:comwell_key_app/hotel_information/components/structured_text.dart';
import 'package:comwell_key_app/hotel_information/components/address.dart';
import 'package:comwell_key_app/hotel_information/components/opening_hours.dart';
-import 'package:comwell_key_app/hotel_information/models/restaurant.dart';
+import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class RestaurantFacilityPage extends StatelessWidget {
- final Restaurant restaurant;
+ final Facility restaurant;
const RestaurantFacilityPage({super.key, required this.restaurant});
- List<Widget> _buildDynamicContent(BuildContext context) {
- final theme = Theme.of(context);
- final Map<String, dynamic> restaurantData = restaurant.toJson();
- final List<Widget> widgets = [];
-
- restaurantData.forEach((key, value) {
- switch (key) {
- case 'title':
- widgets.add(Text(
- value as String,
- style: theme.textTheme.headlineLarge,
- ));
- widgets.add(const SizedBox(height: 20));
- break;
-
- case 'structuredText':
- widgets.add(StructuredText(blocks: restaurant.structuredTextBlocks));
- widgets.add(const SizedBox(height: 20));
- break;
-
- case 'address':
- widgets.add(Address(address: value as String));
- widgets.add(const SizedBox(height: 20));
- break;
-
- case 'openingHours':
- widgets.add(OpeningHours(openingHours: value as String));
- widgets.add(const SizedBox(height: 20));
- break;
-
- case 'phoneNumber':
- widgets.add(Text(
- "restaurant_page_book_table".tr(),
- style: theme.textTheme.headlineMedium,
- ));
- widgets.add(const SizedBox(height: 20));
- widgets.add(ContactHotelButton(
- title: "call_us".tr(),
- subtitle: value as String,
- iconPath: "assets/icons/ic_telephone.svg",
- onClick: () async {
- final cleanPhoneNumber = value.replaceAll(' ', '');
- final Uri phoneUri = Uri.parse("tel:$cleanPhoneNumber");
- if (await canLaunchUrl(phoneUri)) {
- await launchUrl(phoneUri);
- } else {
- if (context.mounted) {
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(content: Text("Could not launch phone call")),
- );
- }
- }
- },
- ));
- widgets.add(const SizedBox(height: 6));
- break;
-
- case 'email':
- widgets.add(ContactHotelButton(
- title: "restaurant_page_send_email".tr(),
- subtitle: value as String,
- iconPath: "assets/icons/ic_send.svg",
- onClick: () async {
- final Uri emailUri = Uri.parse("mailto:$value");
- print("emailUri=$emailUri");
- if (await canLaunchUrl(emailUri)) {
- await launchUrl(emailUri, mode: LaunchMode.externalApplication);
- } else {
- if (context.mounted) {
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(content: Text("Could not launch email client")),
- );
- }
- }
- },
- ));
- widgets.add(const SizedBox(height: 20));
- break;
- }
- });
-
- widgets.add(const SizedBox(height: 100));
- return widgets;
- }
-
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Column(
children: [
- ImageWidget(image: restaurant.image),
+ ImageWidget(image: restaurant.headerImage ?? ""),
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 26),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
- children: _buildDynamicContent(context),
+ children: [
+ StructuredText(blocks: restaurant.structuredText),
+ const SizedBox(height: 100),
+ ],
),
),
),
diff --git a/comwell_key_app/lib/hotel_information/pages/spa_facility_page.dart b/comwell_key_app/lib/hotel_information/pages/spa_facility_page.dart
index 671583ea..f6e33a88 100644
--- a/comwell_key_app/lib/hotel_information/pages/spa_facility_page.dart
+++ b/comwell_key_app/lib/hotel_information/pages/spa_facility_page.dart
@@ -1,44 +1,16 @@
import 'package:comwell_key_app/hotel_information/components/image_widget.dart';
import 'package:comwell_key_app/hotel_information/components/structured_text.dart';
import 'package:comwell_key_app/hotel_information/cubit/hotel_information_cubit.dart';
-import 'package:comwell_key_app/hotel_information/models/spa.dart';
+import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SpaFacilityPage extends StatelessWidget {
- final Spa spa;
+ final Facility spa;
const SpaFacilityPage({super.key, required this.spa});
- List<Widget> _buildDynamicContent(BuildContext context) {
- final theme = Theme.of(context);
- final Map<String, dynamic> spaData = spa.toJson();
- final List<Widget> widgets = [];
-
- spaData.forEach((key, value) {
- if (value == null) return;
-
- switch (key) {
- case 'title':
- widgets.add(Text(
- value as String,
- style: theme.textTheme.headlineLarge,
- ));
- widgets.add(const SizedBox(height: 20));
- break;
-
- case 'structuredText':
- widgets.add(StructuredText(blocks: spa.structuredTextBlocks));
- widgets.add(const SizedBox(height: 20));
- break;
- }
- });
-
- widgets.add(const SizedBox(height: 100));
- return widgets;
- }
-
@override
Widget build(BuildContext context) {
final cubit = context.read<HotelInformationCubit>();
@@ -47,6 +19,26 @@ class SpaFacilityPage extends StatelessWidget {
return Scaffold(
backgroundColor: Colors.white,
+ body: Column(
+ children: [
+ ImageWidget(image: spa.headerImage ?? ""),
+ Expanded(
+ child: SingleChildScrollView(
+ child: Padding(
+ padding:
+ const EdgeInsets.symmetric(horizontal: 16.0, vertical: 26),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ StructuredText(blocks: spa.structuredText),
+ const SizedBox(height: 100),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
bottomSheet: Builder(builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
@@ -61,17 +53,19 @@ class SpaFacilityPage extends StatelessWidget {
child: Container(
color: Colors.white,
child: Padding(
- padding: const EdgeInsets.all(16.0),
+ padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 32.0, top: 16.0),
child: ElevatedButton(
onPressed: isLoading ? null : cubit.onBookSpaClicked,
style: ButtonStyle(
- backgroundColor: WidgetStateProperty.resolveWith((states) {
+ backgroundColor:
+ WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.disabled)) {
return Colors.grey;
}
return sandColor[80];
}),
- foregroundColor: const WidgetStatePropertyAll(Colors.white),
+ foregroundColor:
+ const WidgetStatePropertyAll(Colors.white),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
@@ -97,22 +91,6 @@ class SpaFacilityPage extends StatelessWidget {
],
);
}),
- body: Column(
- children: [
- ImageWidget(image: spa.image),
- Expanded(
- child: SingleChildScrollView(
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 26),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: _buildDynamicContent(context),
- ),
- ),
- ),
- ),
- ],
- ),
);
}
}
diff --git a/comwell_key_app/lib/notifications/components/communications_list.dart b/comwell_key_app/lib/notifications/components/communications_list.dart
index 41bdb3e5..ffb11e07 100644
--- a/comwell_key_app/lib/notifications/components/communications_list.dart
+++ b/comwell_key_app/lib/notifications/components/communications_list.dart
@@ -40,7 +40,7 @@ class CommunicationsList extends StatelessWidget {
.notificationPermissionDescription ??
'',
style: theme.textTheme.bodySmall?.copyWith(
- color: Colors.black.withOpacity(0.65),
+ color: Colors.black.withValues(alpha: 0.65),
fontSize: 12,
fontWeight: FontWeight.w400,
),
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index 577d6a65..7a8de6bc 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -11,6 +11,7 @@ import 'package:comwell_key_app/contact/cubit/contact_cubit.dart';
import 'package:comwell_key_app/contact/repository/contact_repository.dart';
import 'package:comwell_key_app/find_booking/find_booking_page.dart';
import 'package:comwell_key_app/find_booking/loading_page.dart';
+import 'package:comwell_key_app/hotel_information/models/facilities.dart';
import 'package:comwell_key_app/hotel_information/pages/hotel_information_menu.dart';
import 'package:comwell_key_app/hotel_information/pages/parking_facility_page.dart';
import 'package:comwell_key_app/hotel_information/pages/restaurant_facility_page.dart';
@@ -18,7 +19,6 @@ import 'package:comwell_key_app/hotel_information/pages/spa_facility_page.dart';
import 'package:comwell_key_app/hotel_information/cubit/hotel_information_cubit.dart';
import 'package:comwell_key_app/hotel_information/hotel_information_page.dart';
import 'package:comwell_key_app/hotel_information/models/parking_info.dart';
-import 'package:comwell_key_app/hotel_information/models/spa.dart';
import 'package:comwell_key_app/housekeeping/housekeeping_page.dart';
import 'package:comwell_key_app/key/key_page.dart';
import 'package:comwell_key_app/login/login_page.dart';
@@ -112,15 +112,14 @@ GoRouter goRouter() {
ShellRoute(
navigatorKey: _shellNavigatorKey,
parentNavigatorKey: _rootNavigatorKey,
- pageBuilder: (context, state, child) {
- final culture = context.locale;
- return NoTransitionPage(
+ pageBuilder: (context, state, child) {
+ return NoTransitionPage(
child: BlocProvider<HotelInformationCubit>(
create: (BuildContext context) => HotelInformationCubit(
hotelInformationRepository:
locator<HotelInformationRepository>(),
booking: state.extra as Booking,
- culture: culture)
+ culture: context.locale)
..init(),
child:
BlocBuilder<HotelInformationCubit, HotelInformationState>(
@@ -143,7 +142,7 @@ GoRouter goRouter() {
name:
"${AppRoutes.hotelInformation.name}/${AppRoutes.spa.name}",
builder: (context, state) {
- final spa = state.extra as Spa;
+ final spa = state.extra as Facility;
return SpaFacilityPage(spa: spa);
}),
GoRoute(
@@ -152,7 +151,7 @@ GoRouter goRouter() {
name:
"${AppRoutes.hotelInformation.name}/${AppRoutes.restaurant.name}",
builder: (context, state) {
- final restaurant = state.extra as Restaurant;
+ final restaurant = state.extra as Facility;
return RestaurantFacilityPage(restaurant: restaurant);
}),
GoRoute(
diff --git a/comwell_key_app/lib/up_sales/pages/room_upgrade_page.dart b/comwell_key_app/lib/up_sales/pages/room_upgrade_page.dart
index 47f59b62..9f675bea 100644
--- a/comwell_key_app/lib/up_sales/pages/room_upgrade_page.dart
+++ b/comwell_key_app/lib/up_sales/pages/room_upgrade_page.dart
@@ -163,11 +163,11 @@ class _RoomUpgradePageState extends State<RoomUpgradePage> {
?.copyWith(color: Colors.white),
),
isSelected ? Text(
- " -${widget.roomUpgradeList.roomUpgrade.price} kr.",
+ "-${"total_charge_value".tr(args: [widget.roomUpgradeList.roomUpgrade.price])}",
style: theme.textTheme.headlineSmall
?.copyWith(color: Colors.white),
) : Text(
- " +${widget.roomUpgradeList.roomUpgrade.price} kr.",
+ "+${"total_charge_value".tr(args: [widget.roomUpgradeList.roomUpgrade.price])}",
style: theme.textTheme.headlineSmall
?.copyWith(color: Colors.white),
),