diff --git a/lib/config/nav_bar_config.dart b/lib/config/nav_bar_config.dart index f77bc957..36ba8d37 100644 --- a/lib/config/nav_bar_config.dart +++ b/lib/config/nav_bar_config.dart @@ -63,6 +63,8 @@ extension IsRouteATabViewX on PageRouteInfo { ScienceClubDetailRoute.name => context.localize.scientific_cirlces, GuideDetailRoute.name => context.localize.guide, DigitalGuideRoute.name => context.localize.digital_guide, + LevelRoute.name => context.localize.level, + RegionRoute.name => context.localize.region, _ => null, }; } diff --git a/lib/config/ui_config.dart b/lib/config/ui_config.dart index 371e0f5f..683dd4c6 100644 --- a/lib/config/ui_config.dart +++ b/lib/config/ui_config.dart @@ -263,6 +263,8 @@ abstract class DigitalGuideConfig { static const paddingBig = 24.0; static const difficultiesCardIconSize = 35.0; static const photoRowHeight = 75.0; + static const bodyFont = 16.0; + static const headlineFont = 22.0; // Basically there are 4 levels of accessability, but 0 and 1 are shown as the same on digital guide site static const accessibilityLevelColors = [ diff --git a/lib/features/digital_guide_view/data/models/level.dart b/lib/features/digital_guide_view/data/models/level.dart index 2e696ad5..b6835a16 100644 --- a/lib/features/digital_guide_view/data/models/level.dart +++ b/lib/features/digital_guide_view/data/models/level.dart @@ -29,6 +29,7 @@ class LevelTranslations with _$LevelTranslations { class LevelTranslation with _$LevelTranslation { const factory LevelTranslation({ required String name, + @JsonKey(name: "room_numbers_range") required String roomNumbersRange, }) = _LevelTranslation; factory LevelTranslation.fromJson(Map json) => diff --git a/lib/features/digital_guide_view/data/models/level_with_regions.dart b/lib/features/digital_guide_view/data/models/level_with_regions.dart index 5a1fa347..0d562ad3 100644 --- a/lib/features/digital_guide_view/data/models/level_with_regions.dart +++ b/lib/features/digital_guide_view/data/models/level_with_regions.dart @@ -12,7 +12,7 @@ extension HasAdaptedToiletsX on IList { bool hasAdaptedToilets() { for (final level in this) { for (final region in level.regions) { - if (region.adaptedToiletsIndices.isNotEmpty) { + if (region.adaptedToilets.isNotEmpty) { return true; } } diff --git a/lib/features/digital_guide_view/data/models/region.dart b/lib/features/digital_guide_view/data/models/region.dart index c75b5a9f..d1fa388a 100644 --- a/lib/features/digital_guide_view/data/models/region.dart +++ b/lib/features/digital_guide_view/data/models/region.dart @@ -5,11 +5,43 @@ part "region.g.dart"; @freezed class Region with _$Region { + @JsonSerializable(fieldRename: FieldRename.snake) const factory Region({ - @JsonKey(name: "adapted_toilets") required List adaptedToiletsIndices, - @JsonKey(name: "rooms") required List roomsIds, - @JsonKey(name: "lifts") required List liftsIds, + required RegionTranslations translations, + required List dressingRooms, + required List lodges, + required List informationPoints, + required List toilets, + required List adaptedToilets, + required List lifts, + required List stairs, + required List ramps, + required List corridors, + required List stairways, + required List rooms, + required List parkings, }) = _Region; factory Region.fromJson(Map json) => _$RegionFromJson(json); } + +@freezed +class RegionTranslations with _$RegionTranslations { + const factory RegionTranslations({ + @JsonKey(name: "pl") required RegionTranslation plTranslation, + }) = _RegionTranslations; + + factory RegionTranslations.fromJson(Map json) => + _$RegionTranslationsFromJson(json); +} + +@freezed +class RegionTranslation with _$RegionTranslation { + const factory RegionTranslation({ + required String name, + required String location, + }) = _RegionTranslation; + + factory RegionTranslation.fromJson(Map json) => + _$RegionTranslationFromJson(json); +} diff --git a/lib/features/digital_guide_view/presentation/widgets/digital_guide_features_section.dart b/lib/features/digital_guide_view/presentation/widgets/digital_guide_features_section.dart index 30d5019b..90f6ad4e 100644 --- a/lib/features/digital_guide_view/presentation/widgets/digital_guide_features_section.dart +++ b/lib/features/digital_guide_view/presentation/widgets/digital_guide_features_section.dart @@ -17,6 +17,7 @@ import "../../tabs/localization/presentation/localization_expansion_tile_content import "../../tabs/lodge/presentation/digital_guide_lodge_expansion_tile_content.dart"; import "../../tabs/micronavigation/presentation/micronavigation_expansion_tile_content.dart"; import "../../tabs/rooms/presentation/digital_guide_rooms_expansion_tile_content.dart"; +import "../../tabs/structure/presentation/structure_expansion_tile_content.dart"; import "../../tabs/surrounding/presentation/surroundings_expansion_tile_content.dart"; typedef TileContent = ({String title, List content}); @@ -99,7 +100,9 @@ class DigitalGuideFeaturesSection extends ConsumerWidget { ), ( title: context.localize.building_structure, - content: [], + content: [ + StructureExpansionTileContent(digitalGuideData: digitalGuideData), + ], ), ( title: context.localize.room_information, diff --git a/lib/features/digital_guide_view/tabs/adapted_toilets/data/repository/adapted_toilets_repository.dart b/lib/features/digital_guide_view/tabs/adapted_toilets/data/repository/adapted_toilets_repository.dart index d645e5f2..bac0353f 100644 --- a/lib/features/digital_guide_view/tabs/adapted_toilets/data/repository/adapted_toilets_repository.dart +++ b/lib/features/digital_guide_view/tabs/adapted_toilets/data/repository/adapted_toilets_repository.dart @@ -24,7 +24,7 @@ Future> adaptedToiletsRepository( } final adaptedToiletsIDs = - level.regions.expand((region) => region.adaptedToiletsIndices); + level.regions.expand((region) => region.adaptedToilets); final toilets = await Future.wait(adaptedToiletsIDs.map(getAdaptedToilet)); return toilets.toIList(); } diff --git a/lib/features/digital_guide_view/tabs/adapted_toilets/presentation/adapted_toilet_detail_view.dart b/lib/features/digital_guide_view/tabs/adapted_toilets/presentation/adapted_toilet_detail_view.dart index 3b116bd1..01dcb49b 100644 --- a/lib/features/digital_guide_view/tabs/adapted_toilets/presentation/adapted_toilet_detail_view.dart +++ b/lib/features/digital_guide_view/tabs/adapted_toilets/presentation/adapted_toilet_detail_view.dart @@ -64,13 +64,14 @@ class AdaptedToiletDetailView extends ConsumerWidget { context.localize.adapted_toilet_is_not_marked, ].lock, ), - const SizedBox(height: DigitalGuideConfig.heightBig), + if (adaptedToilet.doorsIndices.isNotEmpty) + const SizedBox(height: DigitalGuideConfig.heightMedium), ListView.separated( physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return DigitalGuideNavLink( onTap: () {}, - text: context.localize.doors, + text: context.localize.door, ); }, itemCount: adaptedToilet.doorsIndices.length, @@ -79,11 +80,11 @@ class AdaptedToiletDetailView extends ConsumerWidget { ), shrinkWrap: true, ), - const SizedBox(height: DigitalGuideConfig.heightBig), + const SizedBox(height: DigitalGuideConfig.heightMedium), if (adaptedToilet.imagesIndices.isNotEmpty) Text( context.localize.images, - style: context.textTheme.title.copyWith(fontSize: 24), + style: context.textTheme.title.copyWith(fontSize: 22), ), ]; diff --git a/lib/features/digital_guide_view/tabs/dressing_room/data/repository/dressing_rooms_repository.dart b/lib/features/digital_guide_view/tabs/dressing_room/data/repository/dressing_rooms_repository.dart index c240091b..8b2ee079 100644 --- a/lib/features/digital_guide_view/tabs/dressing_room/data/repository/dressing_rooms_repository.dart +++ b/lib/features/digital_guide_view/tabs/dressing_room/data/repository/dressing_rooms_repository.dart @@ -23,3 +23,22 @@ Future> dressingRoomsRepository( onRetry: () => ref.invalidateSelf(), ); } + +@riverpod +Future> dressingRoomsFromIDsRepository( + Ref ref, + List dressingRoomsIDs, +) async { + Future getDressingRoom(int dressingRoomID) async { + return ref.getAndCacheDataFromDigitalGuide( + "dressing_rooms/$dressingRoomID", + DigitalGuideDressingRoom.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final dressingRooms = + await Future.wait(dressingRoomsIDs.map(getDressingRoom)); + + return dressingRooms.lock; +} diff --git a/lib/features/digital_guide_view/tabs/lifts/data/repository/lifts_repository.dart b/lib/features/digital_guide_view/tabs/lifts/data/repository/lifts_repository.dart index 5dbfe65e..f65e2e6f 100644 --- a/lib/features/digital_guide_view/tabs/lifts/data/repository/lifts_repository.dart +++ b/lib/features/digital_guide_view/tabs/lifts/data/repository/lifts_repository.dart @@ -13,18 +13,26 @@ part "lifts_repository.g.dart"; @riverpod Future> liftsRepository( Ref ref, - LevelWithRegions level, + List liftIDs, ) async { - Future getDigitalGuideLift(int liftId) async { - final endpoint = "lifts/$liftId"; + Future getLift(int liftID) async { return ref.getAndCacheDataFromDigitalGuide( - endpoint, + "lifts/$liftID", DigitalGuideLift.fromJson, onRetry: () => ref.invalidateSelf(), ); } - final liftsIds = level.regions.expand((region) => region.liftsIds); - final lifts = await Future.wait(liftsIds.map(getDigitalGuideLift)); - return lifts.toIList(); + final lifts = await Future.wait(liftIDs.map(getLift)); + + return lifts.lock; +} + +@riverpod +Future> liftsFromLevelRepository( + Ref ref, + LevelWithRegions level, +) async { + final liftsIds = level.regions.expand((region) => region.lifts).toList(); + return liftsRepository(ref, liftsIds); } diff --git a/lib/features/digital_guide_view/tabs/lifts/domain/digital_guide_lifts_use_cases.dart b/lib/features/digital_guide_view/tabs/lifts/domain/digital_guide_lifts_use_cases.dart index eddc77b8..dd33c008 100644 --- a/lib/features/digital_guide_view/tabs/lifts/domain/digital_guide_lifts_use_cases.dart +++ b/lib/features/digital_guide_view/tabs/lifts/domain/digital_guide_lifts_use_cases.dart @@ -24,7 +24,8 @@ Future> getLevelWithLiftsUseCase( .watch(levelsWithRegionsRepositoryProvider(digitalGuideData).future); final levelsWithLiftsData = await Future.wait( levels.map((level) async { - final lifts = await ref.watch(liftsRepositoryProvider(level).future); + final lifts = + await ref.watch(liftsFromLevelRepositoryProvider(level).future); return (level: level.level, lifts: lifts); }), ); diff --git a/lib/features/digital_guide_view/tabs/lodge/data/repository/lodges_repository.dart b/lib/features/digital_guide_view/tabs/lodge/data/repository/lodges_repository.dart index 748b1220..e62bcc5a 100644 --- a/lib/features/digital_guide_view/tabs/lodge/data/repository/lodges_repository.dart +++ b/lib/features/digital_guide_view/tabs/lodge/data/repository/lodges_repository.dart @@ -23,3 +23,21 @@ Future> lodgesRepository( onRetry: () => ref.invalidateSelf(), ); } + +@riverpod +Future> lodgesFromIDsRepository( + Ref ref, + List lodgesIDs, +) async { + Future getLodge(int lodgeID) async { + return ref.getAndCacheDataFromDigitalGuide( + "lodges/$lodgeID", + DigitalGuideLodge.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final lodges = await Future.wait(lodgesIDs.map(getLodge)); + + return lodges.lock; +} diff --git a/lib/features/digital_guide_view/tabs/rooms/data/repository/rooms_repository.dart b/lib/features/digital_guide_view/tabs/rooms/data/repository/rooms_repository.dart index f765b3b7..c686dd27 100644 --- a/lib/features/digital_guide_view/tabs/rooms/data/repository/rooms_repository.dart +++ b/lib/features/digital_guide_view/tabs/rooms/data/repository/rooms_repository.dart @@ -24,7 +24,7 @@ Future> roomsRepository( ); } - final roomsIds = level.regions.expand((region) => region.roomsIds); + final roomsIds = level.regions.expand((region) => region.rooms); final rooms = await Future.wait(roomsIds.map(getDigitalGuideRoom)); return rooms.toIList(); } diff --git a/lib/features/digital_guide_view/tabs/rooms/presentation/digital_guide_room_detail_view.dart b/lib/features/digital_guide_view/tabs/rooms/presentation/digital_guide_room_detail_view.dart index 73e38483..cee8a936 100644 --- a/lib/features/digital_guide_view/tabs/rooms/presentation/digital_guide_room_detail_view.dart +++ b/lib/features/digital_guide_view/tabs/rooms/presentation/digital_guide_room_detail_view.dart @@ -75,7 +75,7 @@ class DigitalGuideRoomDetailView extends ConsumerWidget { ), DigitalGuideNavLink( onTap: () {}, - text: context.localize.doors, + text: context.localize.door, ), const SizedBox( height: DigitalGuideConfig.heightMedium, diff --git a/lib/features/digital_guide_view/tabs/structure/data/models/corridor.dart b/lib/features/digital_guide_view/tabs/structure/data/models/corridor.dart new file mode 100644 index 00000000..730437da --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/models/corridor.dart @@ -0,0 +1,63 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:freezed_annotation/freezed_annotation.dart"; + +part "corridor.freezed.dart"; +part "corridor.g.dart"; + +@freezed +class Corridor with _$Corridor { + @JsonSerializable(fieldRename: FieldRename.snake) + const factory Corridor({ + required CorridorTranslations translations, + @JsonKey(fromJson: stringToBool) required bool isSimpleCorridorLayout, + @JsonKey(fromJson: stringToBool) required bool isFloorMarked, + @JsonKey(fromJson: stringToBool) required bool areRoomsEntrances, + @JsonKey(fromJson: stringToBool) required bool isInformationBoard, + @JsonKey(fromJson: stringToBool) required bool areRoomPurposeDescribedInEn, + @JsonKey(fromJson: stringToBool) + required bool isConsistentLevelColorPattern, + @JsonKey(fromJson: stringToBool) required bool arePictorialDirectionalSigns, + @JsonKey(fromJson: stringToBool) required bool areSeats, + @JsonKey(fromJson: stringToBool) required bool areVendingMachines, + @JsonKey(fromJson: stringToBool) required bool isEmergencyPlan, + @JsonKey(name: "doors") required IList doorsIndices, + @JsonKey(name: "images") required IList imagesIndices, + }) = _Corridor; + + factory Corridor.fromJson(Map json) => + _$CorridorFromJson(json); +} + +@freezed +class CorridorTranslations with _$CorridorTranslations { + const factory CorridorTranslations({ + @JsonKey(name: "pl") required CorridorTranslation plTranslation, + }) = _CorridorTranslations; + + factory CorridorTranslations.fromJson(Map json) => + _$CorridorTranslationsFromJson(json); +} + +@freezed +class CorridorTranslation with _$CorridorTranslation { + @JsonSerializable(fieldRename: FieldRename.snake) + const factory CorridorTranslation({ + required String name, + required String isSimpleCorridorLayoutComment, + required String isFloorMarkedComment, + required String areRoomsEntrancesComment, + required String isInformationBoardComment, + required String arePictorialDirectionalSignsComment, + required String areSeatsComment, + required String areVendingMachinesComment, + required String vendingMachinesProducts, + required String comment, + }) = _CorridorTranslation; + + factory CorridorTranslation.fromJson(Map json) => + _$CorridorTranslationFromJson(json); +} + +bool stringToBool(String text) { + return text.toLowerCase() == "true"; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/models/information_point.dart b/lib/features/digital_guide_view/tabs/structure/data/models/information_point.dart new file mode 100644 index 00000000..86d12311 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/models/information_point.dart @@ -0,0 +1,34 @@ +import "package:freezed_annotation/freezed_annotation.dart"; + +part "information_point.g.dart"; +part "information_point.freezed.dart"; + +@freezed +class InformationPoint with _$InformationPoint { + const factory InformationPoint({ + required InformationPointTranslations translations, + }) = _InformationPoint; + + factory InformationPoint.fromJson(Map json) => + _$InformationPointFromJson(json); +} + +@freezed +class InformationPointTranslations with _$InformationPointTranslations { + const factory InformationPointTranslations({ + @JsonKey(name: "pl") required InformationPointTranslation plTranslation, + }) = _InformationPointTranslations; + + factory InformationPointTranslations.fromJson(Map json) => + _$InformationPointTranslationsFromJson(json); +} + +@freezed +class InformationPointTranslation with _$InformationPointTranslation { + const factory InformationPointTranslation({ + required String location, + }) = _InformationPointTranslation; + + factory InformationPointTranslation.fromJson(Map json) => + _$InformationPointTranslationFromJson(json); +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/models/parking.dart b/lib/features/digital_guide_view/tabs/structure/data/models/parking.dart new file mode 100644 index 00000000..f52836b4 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/models/parking.dart @@ -0,0 +1,35 @@ +import "package:freezed_annotation/freezed_annotation.dart"; + +part "parking.freezed.dart"; +part "parking.g.dart"; + +@freezed +class Parking with _$Parking { + const factory Parking({ + required ParkingTranslations translations, + }) = _Parking; + + factory Parking.fromJson(Map json) => + _$ParkingFromJson(json); +} + +@freezed +class ParkingTranslations with _$ParkingTranslations { + const factory ParkingTranslations({ + @JsonKey(name: "pl") required ParkingTranslation plTranslation, + }) = _ParkingTranslations; + + factory ParkingTranslations.fromJson(Map json) => + _$ParkingTranslationsFromJson(json); +} + +@freezed +class ParkingTranslation with _$ParkingTranslation { + @JsonSerializable(fieldRename: FieldRename.snake) + const factory ParkingTranslation({ + required String entryLocation, + }) = _ParkingTranslation; + + factory ParkingTranslation.fromJson(Map json) => + _$ParkingTranslationFromJson(json); +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/models/ramp.dart b/lib/features/digital_guide_view/tabs/structure/data/models/ramp.dart new file mode 100644 index 00000000..76fee30e --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/models/ramp.dart @@ -0,0 +1,33 @@ +import "package:freezed_annotation/freezed_annotation.dart"; + +part "ramp.freezed.dart"; +part "ramp.g.dart"; + +@freezed +class Ramp with _$Ramp { + const factory Ramp({ + required RampTranslations translations, + }) = _Ramp; + + factory Ramp.fromJson(Map json) => _$RampFromJson(json); +} + +@freezed +class RampTranslations with _$RampTranslations { + const factory RampTranslations({ + @JsonKey(name: "pl") required RampTranslation plTranslation, + }) = _RampTranslations; + + factory RampTranslations.fromJson(Map json) => + _$RampTranslationsFromJson(json); +} + +@freezed +class RampTranslation with _$RampTranslation { + const factory RampTranslation({ + required String location, + }) = _RampTranslation; + + factory RampTranslation.fromJson(Map json) => + _$RampTranslationFromJson(json); +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/models/stairs.dart b/lib/features/digital_guide_view/tabs/structure/data/models/stairs.dart new file mode 100644 index 00000000..8a0198a9 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/models/stairs.dart @@ -0,0 +1,33 @@ +import "package:freezed_annotation/freezed_annotation.dart"; + +part "stairs.g.dart"; +part "stairs.freezed.dart"; + +@freezed +class Stairs with _$Stairs { + const factory Stairs({ + required StairsTranslations translations, + }) = _Stairs; + + factory Stairs.fromJson(Map json) => _$StairsFromJson(json); +} + +@freezed +class StairsTranslations with _$StairsTranslations { + const factory StairsTranslations({ + @JsonKey(name: "pl") required StairsTranslation plTranslation, + }) = _StairsTranslations; + + factory StairsTranslations.fromJson(Map json) => + _$StairsTranslationsFromJson(json); +} + +@freezed +class StairsTranslation with _$StairsTranslation { + const factory StairsTranslation({ + required String location, + }) = _StairsTranslation; + + factory StairsTranslation.fromJson(Map json) => + _$StairsTranslationFromJson(json); +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/models/stairway.dart b/lib/features/digital_guide_view/tabs/structure/data/models/stairway.dart new file mode 100644 index 00000000..a600ec75 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/models/stairway.dart @@ -0,0 +1,34 @@ +import "package:freezed_annotation/freezed_annotation.dart"; + +part "stairway.g.dart"; +part "stairway.freezed.dart"; + +@freezed +class Stairway with _$Stairway { + const factory Stairway({ + required StairwayTranslations translations, + }) = _Stairway; + + factory Stairway.fromJson(Map json) => + _$StairwayFromJson(json); +} + +@freezed +class StairwayTranslations with _$StairwayTranslations { + const factory StairwayTranslations({ + @JsonKey(name: "pl") required StairwayTranslation plTranslation, + }) = _StairwayTranslations; + + factory StairwayTranslations.fromJson(Map json) => + _$StairwayTranslationsFromJson(json); +} + +@freezed +class StairwayTranslation with _$StairwayTranslation { + const factory StairwayTranslation({ + required String name, + }) = _StairwayTranslation; + + factory StairwayTranslation.fromJson(Map json) => + _$StairwayTranslationFromJson(json); +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/models/toilet.dart b/lib/features/digital_guide_view/tabs/structure/data/models/toilet.dart new file mode 100644 index 00000000..a711dd24 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/models/toilet.dart @@ -0,0 +1,39 @@ +import "package:freezed_annotation/freezed_annotation.dart"; + +part "toilet.g.dart"; +part "toilet.freezed.dart"; + +@freezed +class Toilet with _$Toilet { + const factory Toilet({ + required ToiletTranslations translations, + @JsonKey(name: "is_available_for", fromJson: decideMenToilet) + required bool menToilet, + }) = _Toilet; + + factory Toilet.fromJson(Map json) => _$ToiletFromJson(json); +} + +@freezed +class ToiletTranslations with _$ToiletTranslations { + const factory ToiletTranslations({ + @JsonKey(name: "pl") required ToiletTranslation plTranslation, + }) = _ToiletTranslations; + + factory ToiletTranslations.fromJson(Map json) => + _$ToiletTranslationsFromJson(json); +} + +@freezed +class ToiletTranslation with _$ToiletTranslation { + const factory ToiletTranslation({ + required String location, + }) = _ToiletTranslation; + + factory ToiletTranslation.fromJson(Map json) => + _$ToiletTranslationFromJson(json); +} + +bool decideMenToilet(String option) { + return option == "1"; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/repository/corridors_repository.dart b/lib/features/digital_guide_view/tabs/structure/data/repository/corridors_repository.dart new file mode 100644 index 00000000..1501721b --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/repository/corridors_repository.dart @@ -0,0 +1,26 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +import "../../../../data/api/digital_guide_get_and_cache.dart"; +import "../models/corridor.dart"; + +part "corridors_repository.g.dart"; + +@riverpod +Future> corridorsRepository( + Ref ref, + List corridorsIDs, +) async { + Future getCorridor(int corridorID) async { + return ref.getAndCacheDataFromDigitalGuide( + "corridors/$corridorID", + Corridor.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final corridors = await Future.wait(corridorsIDs.map(getCorridor)); + + return corridors.lock; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/repository/information_points_repository.dart b/lib/features/digital_guide_view/tabs/structure/data/repository/information_points_repository.dart new file mode 100644 index 00000000..430524d5 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/repository/information_points_repository.dart @@ -0,0 +1,27 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +import "../../../../data/api/digital_guide_get_and_cache.dart"; +import "../models/information_point.dart"; + +part "information_points_repository.g.dart"; + +@riverpod +Future> informationPointsRepository( + Ref ref, + List informationPointsIDs, +) async { + Future getInformationPoint(int informationPointID) async { + return ref.getAndCacheDataFromDigitalGuide( + "information_points/$informationPointID", + InformationPoint.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final informationPoints = + await Future.wait(informationPointsIDs.map(getInformationPoint)); + + return informationPoints.lock; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/repository/ramps_repository.dart b/lib/features/digital_guide_view/tabs/structure/data/repository/ramps_repository.dart new file mode 100644 index 00000000..6f7e9ebc --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/repository/ramps_repository.dart @@ -0,0 +1,23 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +import "../../../../data/api/digital_guide_get_and_cache.dart"; +import "../models/ramp.dart"; + +part "ramps_repository.g.dart"; + +@riverpod +Future> rampsRepository(Ref ref, List rampsIDs) async { + Future getRamp(int rampID) async { + return ref.getAndCacheDataFromDigitalGuide( + "ramps/$rampID", + Ramp.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final ramps = await Future.wait(rampsIDs.map(getRamp)); + + return ramps.lock; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/repository/region_parkings_repository.dart b/lib/features/digital_guide_view/tabs/structure/data/repository/region_parkings_repository.dart new file mode 100644 index 00000000..3cac7bb1 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/repository/region_parkings_repository.dart @@ -0,0 +1,26 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +import "../../../../data/api/digital_guide_get_and_cache.dart"; +import "../models/parking.dart"; + +part "region_parkings_repository.g.dart"; + +@riverpod +Future> regionParkingsRepository( + Ref ref, + List parkingsIDs, +) async { + Future getParking(int parkingID) async { + return ref.getAndCacheDataFromDigitalGuide( + "parkings/$parkingID", + Parking.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final parkings = await Future.wait(parkingsIDs.map(getParking)); + + return parkings.lock; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/repository/region_rooms_repository.dart b/lib/features/digital_guide_view/tabs/structure/data/repository/region_rooms_repository.dart new file mode 100644 index 00000000..c627ba7d --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/repository/region_rooms_repository.dart @@ -0,0 +1,26 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +import "../../../../data/api/digital_guide_get_and_cache.dart"; +import "../../../rooms/data/models/digital_guide_room.dart"; + +part "region_rooms_repository.g.dart"; + +@riverpod +Future> regionRoomsRepository( + Ref ref, + List roomsIDs, +) async { + Future getRoom(int roomID) async { + return ref.getAndCacheDataFromDigitalGuide( + "rooms/$roomID", + DigitalGuideRoom.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final rooms = await Future.wait(roomsIDs.map(getRoom)); + + return rooms.lock; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/repository/stairs_repository.dart b/lib/features/digital_guide_view/tabs/structure/data/repository/stairs_repository.dart new file mode 100644 index 00000000..812ac296 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/repository/stairs_repository.dart @@ -0,0 +1,23 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +import "../../../../data/api/digital_guide_get_and_cache.dart"; +import "../models/stairs.dart"; + +part "stairs_repository.g.dart"; + +@riverpod +Future> stairsRepository(Ref ref, List stairsIDs) async { + Future getStairs(int stairsID) async { + return ref.getAndCacheDataFromDigitalGuide( + "stairs/$stairsID", + Stairs.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final stairs = await Future.wait(stairsIDs.map(getStairs)); + + return stairs.lock; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/repository/stairways_repository.dart b/lib/features/digital_guide_view/tabs/structure/data/repository/stairways_repository.dart new file mode 100644 index 00000000..3dacfa09 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/repository/stairways_repository.dart @@ -0,0 +1,26 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +import "../../../../data/api/digital_guide_get_and_cache.dart"; +import "../models/stairway.dart"; + +part "stairways_repository.g.dart"; + +@riverpod +Future> stairwaysRepository( + Ref ref, + List stairwaysIDs, +) async { + Future getStairway(int stairwayID) async { + return ref.getAndCacheDataFromDigitalGuide( + "stairways/$stairwayID", + Stairway.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final stairways = await Future.wait(stairwaysIDs.map(getStairway)); + + return stairways.lock; +} diff --git a/lib/features/digital_guide_view/tabs/structure/data/repository/toilets_repository.dart b/lib/features/digital_guide_view/tabs/structure/data/repository/toilets_repository.dart new file mode 100644 index 00000000..8b2e0fc6 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/data/repository/toilets_repository.dart @@ -0,0 +1,26 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; + +import "../../../../data/api/digital_guide_get_and_cache.dart"; +import "../models/toilet.dart"; + +part "toilets_repository.g.dart"; + +@riverpod +Future> toiletsRepository( + Ref ref, + List toiletsIDs, +) async { + Future getToilet(int toiletID) async { + return ref.getAndCacheDataFromDigitalGuide( + "toilets/$toiletID", + Toilet.fromJson, + onRetry: () => ref.invalidateSelf(), + ); + } + + final toilets = await Future.wait(toiletsIDs.map(getToilet)); + + return toilets.lock; +} diff --git a/lib/features/digital_guide_view/tabs/structure/domain/digital_guide_region_use_cases.dart b/lib/features/digital_guide_view/tabs/structure/domain/digital_guide_region_use_cases.dart new file mode 100644 index 00000000..d0e6a9e9 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/domain/digital_guide_region_use_cases.dart @@ -0,0 +1,82 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:riverpod_annotation/riverpod_annotation.dart"; +import "../../../data/models/region.dart"; +import "../../dressing_room/data/models/digital_guide_dressing_room.dart"; +import "../../dressing_room/data/repository/dressing_rooms_repository.dart"; +import "../../lifts/data/models/digital_guide_lift.dart"; +import "../../lifts/data/repository/lifts_repository.dart"; +import "../../lodge/data/models/digital_guide_lodge.dart"; +import "../../lodge/data/repository/lodges_repository.dart"; +import "../../rooms/data/models/digital_guide_room.dart"; +import "../data/models/corridor.dart"; +import "../data/models/information_point.dart"; +import "../data/models/parking.dart"; +import "../data/models/ramp.dart"; +import "../data/models/stairs.dart"; +import "../data/models/stairway.dart"; +import "../data/models/toilet.dart"; +import "../data/repository/corridors_repository.dart"; +import "../data/repository/information_points_repository.dart"; +import "../data/repository/ramps_repository.dart"; +import "../data/repository/region_parkings_repository.dart"; +import "../data/repository/region_rooms_repository.dart"; +import "../data/repository/stairs_repository.dart"; +import "../data/repository/stairways_repository.dart"; +import "../data/repository/toilets_repository.dart"; + +part "digital_guide_region_use_cases.g.dart"; + +typedef RegionData = ({ + IList corridors, + IList stairs, + IList ramps, + IList stairways, + IList lifts, + IList lodges, + IList informationPoints, + IList dressingRooms, + IList toilets, + IList rooms, + IList parkings, +}); + +@riverpod +Future digitalGuideRegionUrseCases(Ref ref, Region region) async { + final corridors = + await ref.watch(corridorsRepositoryProvider(region.corridors).future); + final stairs = + await ref.watch(stairsRepositoryProvider(region.stairs).future); + final ramps = await ref.watch(rampsRepositoryProvider(region.ramps).future); + final stairways = + await ref.watch(stairwaysRepositoryProvider(region.stairways).future); + final lifts = await ref.watch(liftsRepositoryProvider(region.lifts).future); + final lodges = + await ref.watch(lodgesFromIDsRepositoryProvider(region.lodges).future); + final informationPoints = await ref.watch( + informationPointsRepositoryProvider(region.informationPoints).future, + ); + final dressingRooms = await ref.watch( + dressingRoomsFromIDsRepositoryProvider(region.dressingRooms).future, + ); + final toilets = + await ref.watch(toiletsRepositoryProvider(region.toilets).future); + final rooms = + await ref.watch(regionRoomsRepositoryProvider(region.rooms).future); + final parkings = + await ref.watch(regionParkingsRepositoryProvider(region.parkings).future); + + return ( + corridors: corridors, + stairs: stairs, + ramps: ramps, + stairways: stairways, + lifts: lifts, + lodges: lodges, + informationPoints: informationPoints, + dressingRooms: dressingRooms, + toilets: toilets, + rooms: rooms, + parkings: parkings, + ); +} diff --git a/lib/features/digital_guide_view/tabs/structure/presentation/structure_expansion_tile_content.dart b/lib/features/digital_guide_view/tabs/structure/presentation/structure_expansion_tile_content.dart new file mode 100644 index 00000000..dff07386 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/presentation/structure_expansion_tile_content.dart @@ -0,0 +1,73 @@ +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter/material.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; + +import "../../../../../config/ui_config.dart"; +import "../../../../../widgets/my_error_widget.dart"; +import "../../../../navigator/utils/navigation_commands.dart"; +import "../../../data/models/digital_guide_response.dart"; +import "../../../data/models/level_with_regions.dart"; +import "../../../data/repository/levels_repository.dart"; +import "../../../presentation/widgets/digital_guide_nav_link.dart"; + +class StructureExpansionTileContent extends ConsumerWidget { + const StructureExpansionTileContent({ + required this.digitalGuideData, + }); + + final DigitalGuideResponse digitalGuideData; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final levelDataAsync = + ref.watch(levelsWithRegionsRepositoryProvider(digitalGuideData)); + + return levelDataAsync.when( + data: (data) => _StructureExpansionTileContent( + digitalGuideResponse: digitalGuideData, + levels: data, + ), + loading: () => const Center( + child: CircularProgressIndicator(), + ), + error: (error, _) => MyErrorWidget(error), + ); + } +} + +class _StructureExpansionTileContent extends ConsumerWidget { + const _StructureExpansionTileContent({ + required this.digitalGuideResponse, + required this.levels, + }); + + final DigitalGuideResponse digitalGuideResponse; + final IList levels; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Padding( + padding: const EdgeInsets.only( + top: DigitalGuideConfig.heightMedium, + left: DigitalGuideConfig.heightMedium, + right: DigitalGuideConfig.heightMedium, + ), + child: ListView.separated( + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) => DigitalGuideNavLink( + onTap: () async { + await ref.navigateDigitalGuideLevel( + levels[index], + ); + }, + text: levels[index].level.translations.plTranslation.name, + ), + separatorBuilder: (context, index) => const SizedBox( + height: DigitalGuideConfig.heightMedium, + ), + itemCount: levels.length, + shrinkWrap: true, + ), + ); + } +} diff --git a/lib/features/digital_guide_view/tabs/structure/presentation/views/corridor_view.dart b/lib/features/digital_guide_view/tabs/structure/presentation/views/corridor_view.dart new file mode 100644 index 00000000..7e6c6f5a --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/presentation/views/corridor_view.dart @@ -0,0 +1,176 @@ +import "package:auto_route/auto_route.dart"; +import "package:fast_immutable_collections/fast_immutable_collections.dart"; +import "package:flutter/material.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; + +import "../../../../../../config/ui_config.dart"; +import "../../../../../../theme/app_theme.dart"; +import "../../../../../../utils/context_extensions.dart"; +import "../../../../../../widgets/detail_views/detail_view_app_bar.dart"; +import "../../../../presentation/widgets/bullet_list.dart"; +import "../../../../presentation/widgets/digital_guide_image.dart"; +import "../../../../presentation/widgets/digital_guide_nav_link.dart"; +import "../../data/models/corridor.dart"; + +@RoutePage() +class CorridorView extends ConsumerWidget { + const CorridorView({ + required this.corridor, + }); + + final Corridor corridor; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Scaffold( + appBar: DetailViewAppBar(), + body: Padding( + padding: const EdgeInsets.symmetric( + horizontal: DigitalGuideConfig.heightBig, + ), + child: CustomScrollView( + slivers: [ + SliverList( + delegate: SliverChildListDelegate([ + Text( + corridor.translations.plTranslation.name, + style: context.textTheme.headline + .copyWith(fontSize: DigitalGuideConfig.headlineFont), + ), + const SizedBox(height: DigitalGuideConfig.heightMedium), + TextPoints( + corridor: corridor, + ), + if (corridor.doorsIndices.isNotEmpty) + const SizedBox(height: DigitalGuideConfig.heightMedium), + ListView.separated( + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) { + return DigitalGuideNavLink( + onTap: () {}, + text: context.localize.door, + ); + }, + itemCount: corridor.doorsIndices.length, + separatorBuilder: (context, index) => const SizedBox( + height: DigitalGuideConfig.heightMedium, + ), + shrinkWrap: true, + ), + const SizedBox(height: DigitalGuideConfig.heightMedium), + if (corridor.imagesIndices.isNotEmpty) + Text( + context.localize.images, + style: context.textTheme.title + .copyWith(fontSize: DigitalGuideConfig.headlineFont), + ), + ]), + ), + SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + return Padding( + padding: + const EdgeInsets.all(DigitalGuideConfig.heightMedium), + child: ClipRRect( + borderRadius: BorderRadius.circular( + DigitalGuideConfig.borderRadiusSmall, + ), + child: DigitalGuideImage( + id: corridor.imagesIndices[index], + ), + ), + ); + }, + childCount: corridor.imagesIndices.length, + ), + ), + ], + ), + ), + ); + } +} + +class TextPoints extends ConsumerWidget { + const TextPoints({ + required this.corridor, + }); + + final Corridor corridor; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return BulletList( + items: [ + corridor.translations.plTranslation.comment, + if (corridor.isSimpleCorridorLayout) + context.localize.corridor_simple_layout_text( + corridor.translations.plTranslation.isSimpleCorridorLayoutComment, + ) + else + context.localize.corridor_no_simple_layout_text( + corridor.translations.plTranslation.isSimpleCorridorLayoutComment, + ), + if (corridor.isFloorMarked) + context.localize.floor_marked_text( + corridor.translations.plTranslation.isFloorMarkedComment, + ) + else + context.localize.floor_not_marked_text( + corridor.translations.plTranslation.isFloorMarkedComment, + ), + if (corridor.areRoomsEntrances) + context.localize.room_entrances_text( + corridor.translations.plTranslation.areRoomsEntrancesComment, + ) + else + context.localize.no_room_entrances_text, + if (corridor.isInformationBoard) + context.localize.information_board_text( + corridor.translations.plTranslation.isInformationBoardComment, + ) + else + context.localize.no_information_board_text( + corridor.translations.plTranslation.isInformationBoardComment, + ), + if (corridor.areRoomPurposeDescribedInEn) + context.localize.room_puropose_described_in_en_text + else + context.localize.room_puropose_not_described_in_en_text, + if (corridor.isConsistentLevelColorPattern) + context.localize.room_puropose_described_in_en_text + else + context.localize.not_consistent_level_color_pattern_text, + if (corridor.arePictorialDirectionalSigns) + context.localize.pictorial_directional_signs_text( + corridor + .translations.plTranslation.arePictorialDirectionalSignsComment, + ) + else + context.localize.no_pictorial_directional_signs_text( + corridor + .translations.plTranslation.arePictorialDirectionalSignsComment, + ), + if (corridor.areSeats) + context.localize.seats_text( + corridor.translations.plTranslation.areSeatsComment, + ) + else + context.localize.no_seats_text, + if (corridor.areVendingMachines) + context.localize.vending_machines_text( + corridor.translations.plTranslation.areVendingMachinesComment, + ), + if (corridor.areVendingMachines) + corridor.translations.plTranslation.vendingMachinesProducts + else + context.localize.no_vending_machines_text, + if (corridor.isEmergencyPlan) + context.localize.emergency_plan_text + else + context.localize.no_emergency_plan_text, + ].lock, + ); + } +} diff --git a/lib/features/digital_guide_view/tabs/structure/presentation/views/level_view.dart b/lib/features/digital_guide_view/tabs/structure/presentation/views/level_view.dart new file mode 100644 index 00000000..75e5afcd --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/presentation/views/level_view.dart @@ -0,0 +1,85 @@ +import "package:auto_route/auto_route.dart"; +import "package:flutter/material.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; + +import "../../../../../../config/ui_config.dart"; +import "../../../../../../theme/app_theme.dart"; +import "../../../../../../utils/context_extensions.dart"; +import "../../../../../../widgets/detail_views/detail_view_app_bar.dart"; +import "../../../../../navigator/utils/navigation_commands.dart"; +import "../../../../data/models/level_with_regions.dart"; +import "../../../../presentation/widgets/digital_guide_nav_link.dart"; + +@RoutePage() +class LevelView extends ConsumerWidget { + const LevelView({ + required this.levelInfo, + }); + final LevelWithRegions levelInfo; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Scaffold( + appBar: DetailViewAppBar(), + body: Padding( + padding: const EdgeInsets.symmetric( + horizontal: DigitalGuideConfig.heightBig, + ), + child: CustomScrollView( + slivers: [ + SliverList( + delegate: SliverChildListDelegate([ + Text( + levelInfo.level.translations.plTranslation.name, + style: context.textTheme.headline + .copyWith(fontSize: DigitalGuideConfig.headlineFont), + ), + const SizedBox( + height: DigitalGuideConfig.heightSmall, + ), + Text( + context.localize.rooms_distribution, + style: context.textTheme.boldBody + .copyWith(fontSize: DigitalGuideConfig.bodyFont), + ), + const SizedBox( + height: DigitalGuideConfig.heightSmall, + ), + Text( + levelInfo.level.translations.plTranslation.roomNumbersRange, + style: context.textTheme.body + .copyWith(fontSize: DigitalGuideConfig.bodyFont), + ), + const SizedBox( + height: DigitalGuideConfig.heightMedium, + ), + ]), + ), + SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) => Column( + children: [ + DigitalGuideNavLink( + onTap: () async { + await ref.navigateDigitalGuideRegion( + levelInfo.level, + levelInfo.regions[index], + ); + }, + text: levelInfo + .regions[index].translations.plTranslation.name, + ), + const SizedBox( + height: DigitalGuideConfig.heightMedium, + ), + ], + ), + childCount: levelInfo.regions.length, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/features/digital_guide_view/tabs/structure/presentation/views/region_view.dart b/lib/features/digital_guide_view/tabs/structure/presentation/views/region_view.dart new file mode 100644 index 00000000..36bef525 --- /dev/null +++ b/lib/features/digital_guide_view/tabs/structure/presentation/views/region_view.dart @@ -0,0 +1,215 @@ +import "dart:async"; + +import "package:auto_route/auto_route.dart"; +import "package:flutter/material.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; + +import "../../../../../../config/ui_config.dart"; +import "../../../../../../theme/app_theme.dart"; +import "../../../../../../utils/context_extensions.dart"; +import "../../../../../../widgets/detail_views/detail_view_app_bar.dart"; +import "../../../../../../widgets/loading_widgets/shimmer_loading.dart"; +import "../../../../../../widgets/my_error_widget.dart"; +import "../../../../../navigator/utils/navigation_commands.dart"; +import "../../../../data/models/level.dart"; +import "../../../../data/models/region.dart"; +import "../../../../presentation/widgets/digital_guide_nav_link.dart"; +import "../../domain/digital_guide_region_use_cases.dart"; + +@RoutePage() +class RegionView extends ConsumerWidget { + const RegionView({ + required this.level, + required this.region, + }); + + final Level level; + final Region region; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final regionDataAsync = + ref.watch(digitalGuideRegionUrseCasesProvider(region)); + + return regionDataAsync.when( + data: (regionData) => + _RegionView(level: level, region: region, regionData: regionData), + error: (error, stackTrace) => Scaffold( + appBar: DetailViewAppBar(), + body: MyErrorWidget(error), + ), + loading: () => const Center( + child: ShimmeringEffect( + child: ColoredBox( + color: Colors.white, + ), + ), + ), + ); + } +} + +class _RegionView extends ConsumerWidget { + const _RegionView({ + required this.level, + required this.region, + required this.regionData, + }); + + final Level level; + final Region region; + final RegionData regionData; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final sliverListItems = [ + RegionDataSliverListItem( + text: (index) => + regionData.corridors[index].translations.plTranslation.name, + onTap: (index) async => + ref.navigateDigitalGuideCorridor(regionData.corridors[index]), + itemCount: region.corridors.length, + ), + RegionDataSliverListItem( + text: (index) => context.localize.stairs, + onTap: (index) async => () {}, + itemCount: region.corridors.length, + ), + RegionDataSliverListItem( + text: (index) => context.localize.ramp, + onTap: (index) async => () {}, + itemCount: region.corridors.length, + ), + RegionDataSliverListItem( + text: (index) => + regionData.stairways[index].translations.plTranslation.name, + onTap: (index) async => () {}, + itemCount: region.stairways.length, + ), + RegionDataSliverListItem( + text: (index) => context.localize.lift, + onTap: (index) async => ref.navigateLiftDetails( + regionData.lifts[index], + level.translations.plTranslation.name, + ), + itemCount: region.lifts.length, + ), + RegionDataSliverListItem( + text: (index) => context.localize.lodge, + onTap: (index) async => () {}, + itemCount: region.lodges.length, + ), + RegionDataSliverListItem( + text: (index) => context.localize.information_point, + onTap: (index) async => () {}, + itemCount: region.informationPoints.length, + ), + RegionDataSliverListItem( + text: (index) => context.localize.dressing_room, + onTap: (index) async => () {}, + itemCount: region.dressingRooms.length, + ), + RegionDataSliverListItem( + text: (index) => regionData.toilets[index].menToilet + ? context.localize.men_toilet + : context.localize.women_toilet, + onTap: (index) async => () {}, + itemCount: region.toilets.length, + ), + RegionDataSliverListItem( + text: (index) => regionData.rooms[index].translations.pl.name, + onTap: (index) async => + ref.navigateRoomDetails(regionData.rooms[index]), + itemCount: region.rooms.length, + ), + RegionDataSliverListItem( + text: (index) => context.localize.parking, + onTap: (index) async => () {}, + itemCount: region.parkings.length, + ), + ]; + + return Scaffold( + appBar: DetailViewAppBar(), + body: Padding( + padding: const EdgeInsets.symmetric( + horizontal: DigitalGuideConfig.heightBig, + ), + child: CustomScrollView( + slivers: [ + SliverList( + delegate: SliverChildListDelegate([ + Text( + region.translations.plTranslation.name, + style: context.textTheme.headline.copyWith(fontSize: 22), + ), + const SizedBox( + height: DigitalGuideConfig.heightSmall, + ), + Text( + context.localize.region_location, + style: context.textTheme.boldBody.copyWith(fontSize: 16), + ), + const SizedBox( + height: DigitalGuideConfig.heightSmall, + ), + Text( + region.translations.plTranslation.location, + style: context.textTheme.body.copyWith(fontSize: 16), + ), + const SizedBox( + height: DigitalGuideConfig.heightMedium, + ), + ]), + ), + ...sliverListItems.map( + (regionDataSliverListItem) => RegionDataSliverList( + regionDataSliverListItem: regionDataSliverListItem, + ), + ), + ], + ), + ), + ); + } +} + +class RegionDataSliverList extends ConsumerWidget { + const RegionDataSliverList({ + required this.regionDataSliverListItem, + }); + + final RegionDataSliverListItem regionDataSliverListItem; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) => Column( + children: [ + DigitalGuideNavLink( + onTap: () async => regionDataSliverListItem.onTap?.call(index), + text: regionDataSliverListItem.text(index), + ), + const SizedBox( + height: DigitalGuideConfig.heightMedium, + ), + ], + ), + childCount: regionDataSliverListItem.itemCount, + ), + ); + } +} + +class RegionDataSliverListItem { + final String Function(int) text; + final Future Function(int index)? onTap; + final int itemCount; + + RegionDataSliverListItem({ + required this.text, + this.onTap, + required this.itemCount, + }); +} diff --git a/lib/features/digital_guide_view/tabs/surrounding/data/models/surrounding_response.dart b/lib/features/digital_guide_view/tabs/surrounding/data/models/surrounding_response.dart index 27039876..e9008678 100644 --- a/lib/features/digital_guide_view/tabs/surrounding/data/models/surrounding_response.dart +++ b/lib/features/digital_guide_view/tabs/surrounding/data/models/surrounding_response.dart @@ -162,7 +162,7 @@ class SurroundingResponseTranslationsDetails } bool _stringToBool(String value) { - return value == "True"; + return value.toLowerCase() == "true"; } int _stringToInt(String value) { diff --git a/lib/features/navigator/app_router.dart b/lib/features/navigator/app_router.dart index 4f4e5775..eb074dcf 100644 --- a/lib/features/navigator/app_router.dart +++ b/lib/features/navigator/app_router.dart @@ -8,6 +8,9 @@ import "../about_us_view/about_us_view.dart"; import "../buildings_view/buildings_view.dart"; import "../department_detail_view/department_detail_view.dart"; import "../departments_view/departments_view.dart"; +import "../digital_guide_view/data/models/level.dart"; +import "../digital_guide_view/data/models/level_with_regions.dart"; +import "../digital_guide_view/data/models/region.dart"; import "../digital_guide_view/presentation/digital_guide_view.dart"; import "../digital_guide_view/tabs/adapted_toilets/data/models/adapted_toilet.dart"; import "../digital_guide_view/tabs/adapted_toilets/presentation/adapted_toilet_detail_view.dart"; @@ -17,6 +20,10 @@ import "../digital_guide_view/tabs/micronavigation/data/models/micronavigation_r import "../digital_guide_view/tabs/micronavigation/presentation/micronavigation_detail_view.dart"; import "../digital_guide_view/tabs/rooms/data/models/digital_guide_room.dart"; import "../digital_guide_view/tabs/rooms/presentation/digital_guide_room_detail_view.dart"; +import "../digital_guide_view/tabs/structure/data/models/corridor.dart"; +import "../digital_guide_view/tabs/structure/presentation/views/corridor_view.dart"; +import "../digital_guide_view/tabs/structure/presentation/views/level_view.dart"; +import "../digital_guide_view/tabs/structure/presentation/views/region_view.dart"; import "../guide_detail_view/guide_detail_view.dart"; import "../guide_view/guide_view.dart"; import "../home_view/home_view.dart"; @@ -113,13 +120,20 @@ class AppRouter extends RootStackRouter { page: DigitalGuideRoute.page, ), AutoRoute( - path: "/digital-guide/:id/room-details", - page: DigitalGuideRoomDetailRoute.page, + page: AdaptedToiletDetailRoute.page, + ), + AutoRoute( + page: LevelRoute.page, + ), + AutoRoute( + page: RegionRoute.page, ), AutoRoute( - path: "/digital-guide/:id/lift-details", page: DigitalGuideLiftDetailRoute.page, ), + AutoRoute( + page: CorridorRoute.page, + ), AutoRoute( path: "/digital-guide/:id/micronavigation-details", page: MicronavigationDetailRoute.page, diff --git a/lib/features/navigator/utils/navigation_commands.dart b/lib/features/navigator/utils/navigation_commands.dart index 78ede985..c1c2cb1f 100644 --- a/lib/features/navigator/utils/navigation_commands.dart +++ b/lib/features/navigator/utils/navigation_commands.dart @@ -5,10 +5,15 @@ import "package:logger/logger.dart"; import "../../../utils/launch_url_util.dart"; import "../../buildings_view/model/building_model.dart"; +// ignore: library_prefixes +import "../../digital_guide_view/data/models/level.dart" as digitalGuide; +import "../../digital_guide_view/data/models/level_with_regions.dart"; +import "../../digital_guide_view/data/models/region.dart"; import "../../digital_guide_view/tabs/adapted_toilets/data/models/adapted_toilet.dart"; import "../../digital_guide_view/tabs/lifts/data/models/digital_guide_lift.dart"; import "../../digital_guide_view/tabs/micronavigation/data/models/micronavigation_response.dart"; import "../../digital_guide_view/tabs/rooms/data/models/digital_guide_room.dart"; +import "../../digital_guide_view/tabs/structure/data/models/corridor.dart"; import "../../parkings_view/models/parking.dart"; import "../app_router.dart"; import "../navigation_controller.dart"; @@ -116,6 +121,26 @@ extension NavigationX on WidgetRef { .push(DigitalGuideLiftDetailRoute(lift: lift, levelName: levelName)); } + Future navigateDigitalGuideLevel(LevelWithRegions levelInfo) async { + await _router.push(LevelRoute(levelInfo: levelInfo)); + } + + Future navigateDigitalGuideRegion( + digitalGuide.Level level, + Region region, + ) async { + await _router.push( + RegionRoute( + level: level, + region: region, + ), + ); + } + + Future navigateDigitalGuideCorridor(Corridor corridor) async { + await _router.push(CorridorRoute(corridor: corridor)); + } + Future navigateBuildingDetailAction(BuildingModel building) async { return switch (building.externalDigitalGuideMode) { "web_url" => launch(building.externalDigitalGuideIdOrURL!), diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index d21751dc..34379a46 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -238,7 +238,7 @@ }, "adapted_toilet_is_not_marked": "Lokalizacja toalety nie jest oznaczona za pomocą informacji kierunkowej.", "images": "Zdjęcia", - "doors": "Drzwi", + "door": "Drzwi", "accessibility_profile" : "Profil dostępności", "accessibility_profile_empty" : "Brak informacji dotyczących wybranego profilu dostępności", "accessibility_card_information" : "{message} jest {accessibility_level} dla osób {disability_description}", @@ -310,5 +310,120 @@ "max_capacity" : "Maksymalny udźwig", "generic_error_message": "Upsss...Coś poszło nie tak", "you_can_adjust": "Możesz dostosować informacje pod swoje specjalne potrzeby", - "navigate_to_building": "Nawiguj do budynku" + "navigate_to_building": "Nawiguj do budynku", + "working_hours" : "Godziny otwarcia", + "rooms_distribution" : "Rozkład pomieszczeń:", + "region_location" : "Lokalizacja strefy:", + "level" : "Piętro", + "region" : "Strefa", + "stairs" : "Schody", + "lodge" : "Portiernia", + "information_point" : "Punkt informacyjny", + "dressing_room" : "Szatnia", + "men_toilet" : "Toaleta męska", + "women_toilet" : "Toaleta damska", + "ramp" : "Pochylnia", + "lift" : "Winda", + "parking" : "Parking", + "corridor_simple_layout_text" : "Korytarz ma prosty i przejrzysty układ, który jest powtarzalny na każdej kondygnacji. {comment}", + "@corridor_simple_layout_text": { + "description": "comment", + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "corridor_no_simple_layout_text" : "Układ korytarza nie jest prosty, czytelny ani powtarzalny na każdej kondygnacji. {comment}", + "@corridor_no_simple_layout_text": { + "description": "comment", + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "floor_marked_text" : "Korytarz jest oznakowany. Widoczny jest numer piętra. {comment}", + "@floor_marked_text": { + "description": "comment", + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "floor_not_marked_text" : "Korytarz nie jest oznakowany. Nie ma widocznego numeru piętra. {comment}", + "@floor_not_marked_text": { + "description": "comment", + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "room_entrances_text" : "Z korytarza możliwe jest wejście do następujących pomieszczeń: {comment}", + "@floor_marked_text": { + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "no_room_entrances_text" : "Z korytarza nie ma możliwości wejścia do żadnego pomieszczenia.", + "information_board_text" : "W korytarzu nie ma tablicy informacyjnej ze spisem pomieszczeń. {comment}", + "@information_board_text": { + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "no_information_board_text" : "W korytarzu nie ma tablicy informacyjnej ze spisem pomieszczeń. {comment}", + "@no_information_board_text": { + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "room_puropose_described_in_en_text" : "Funkcje pomieszczeń nie są opisane w języku angielskim.", + "room_puropose_not_described_in_en_text" : "Funkcje pomieszczeń nie są opisane w języku angielskim.", + "consistent_level_color_pattern_text" : "Kolor, wzór i krój oznakowania pomieszczeń są spójne dla całego piętra.", + "not_consistent_level_color_pattern_text" : "Kolor, wzór i krój oznakowania pomieszczeń nie są spójne dla całego piętra.", + "pictorial_directional_signs_text" : "W kluczowych punktach korytarza znajdują się wyraźne i kontrastowe oznakowania kierunkowe. {comment}", + "@pictorial_directional_signs_text": { + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "no_pictorial_directional_signs_text" : "W kluczowych punktach korytarza nie ma wyraźnych i kontrastowych oznakowań kierunkowych. {comment}", + "@no_pictorial_directional_signs_text": { + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "seats_text" : "W korytarzu znajdują się miejsca siedzące. Są to: {comment}", + "@seats_text": { + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "no_seats_text" : "W korytarzu nie ma miejsc siedzących.", + "vending_machines_text" : "W korytarzu znajdują się automaty sprzedające. {comment}", + "@vending_machines_text": { + "placeholders": { + "comment": { + "type": "String" + } + } + }, + "no_vending_machines_text" : "W korytarzu nie ma automatów sprzedających.", + "emergency_plan_text" : "W korytarzu znajdują się plany ewakuacyjne.", + "no_emergency_plan_text" : "W korytarzu nie ma planów ewakuacyjnych." }