Skip to content

Commit

Permalink
feat(digital-guide): add rooms content (#531)
Browse files Browse the repository at this point in the history
* feat(digital-guide): add data layer for rooms section

* feat(digital-guide): add presentation layer

* feat(digital-guide): navigation

* feat(digital-guide): localization

* feat(digital-guide): docs

* feat(digital-guide): apply pr's fixes

* feat(digital-guide): final touch

* feat(digital-guide): final touch v2
  • Loading branch information
mikolaj-jalocha authored and mmzek committed Jan 18, 2025
1 parent 076cff9 commit c96dbf2
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "../../tabs/adapted_toilets/presentation/adapted_toilets_expansion_tile_c
import "../../tabs/amenities/presentation/amenities_expansion_tile_content.dart";
import "../../tabs/evacuation/evacuation_widget.dart";
import "../../tabs/localization/presentation/localization_expansion_tile_content.dart";
import "../../tabs/rooms/presentation/digital_guide_rooms_expansion_tile_content.dart";
import "../../tabs/surrounding/presentation/surroundings_expansion_tile_content.dart";

typedef TileContent = ({String title, List<Widget> content});
Expand Down Expand Up @@ -73,7 +74,11 @@ class DigitalGuideFeaturesSection extends StatelessWidget {
),
(
title: context.localize.room_information,
content: [LocalizationExpansionTileContent()],
content: [
DigitalGuideRoomExpansionTileContent(
digitalGuideResponse: digitalGuideData,
),
],
),
(
title: context.localize.evacuation,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import "package:freezed_annotation/freezed_annotation.dart";

part "digital_guide_room.freezed.dart";

part "digital_guide_room.g.dart";

@freezed
class DigitalGuideRoom with _$DigitalGuideRoom {
const factory DigitalGuideRoom({
required int id,
required DigitalGuideTranslationsRoom translations,
@JsonKey(name: "images") required List<int>? imagesIds,
}) = _DigitalGuideRoom;

factory DigitalGuideRoom.fromJson(Map<String, dynamic> json) =>
_$DigitalGuideRoomFromJson(json);
}

@freezed
class DigitalGuideTranslationsRoom with _$DigitalGuideTranslationsRoom {
const factory DigitalGuideTranslationsRoom({
required DigitalGuideTranslationRoom pl,
}) = _DigitalGuideTranslationsRoom;

factory DigitalGuideTranslationsRoom.fromJson(Map<String, dynamic> json) =>
_$DigitalGuideTranslationsRoomFromJson(json);
}

@freezed
class DigitalGuideTranslationRoom with _$DigitalGuideTranslationRoom {
@JsonSerializable(fieldRename: FieldRename.snake)
const factory DigitalGuideTranslationRoom({
required String name,
required String roomPurpose,
required String location,
required String workingDaysAndHours,
required String areEntrancesComment,
required String isOneLevelFloorComment,
required String arePlacesForWheelchairsComment,
required String comment,
}) = _DigitalGuideTranslationRoom;

factory DigitalGuideTranslationRoom.fromJson(Map<String, dynamic> json) =>
_$DigitalGuideTranslationRoomFromJson(json);
}
Original file line number Diff line number Diff line change
@@ -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 "../../../../data/models/digital_guide_response.dart";
import "../models/digital_guide_room.dart";

part "rooms_repository.g.dart";

@riverpod
Future<IList<DigitalGuideRoom>> roomsRepository(
Ref ref,
DigitalGuideResponse building,
) async {
final String endpoint = "rooms/?building=${building.id}";

return ref.getAndCacheDataFromDigitalGuide(
endpoint,
(List<dynamic> json) => json
.whereType<Map<String, dynamic>>()
.map(DigitalGuideRoom.fromJson)
.toIList(),
onRetry: () => ref.invalidateSelf(),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import "package:auto_route/annotations.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 "../../../../../utils/ilist_nonempty.dart";
import "../../../../../widgets/detail_views/detail_view_app_bar.dart";
import "../../../presentation/widgets/accessibility_button.dart";
import "../../../presentation/widgets/bullet_list.dart";
import "../../../presentation/widgets/digital_guide_nav_link.dart";
import "../../../presentation/widgets/digital_guide_photo_row.dart";
import "../data/models/digital_guide_room.dart";

@RoutePage()
class DigitalGuideRoomDetailView extends ConsumerWidget {
const DigitalGuideRoomDetailView({required this.room});

final DigitalGuideRoom room;

@override
Widget build(BuildContext context, WidgetRef ref) {
final roomInformation = room.translations.pl;
final widgets = [
Text(
roomInformation.name,
style: context.textTheme.headline.copyWith(fontSize: 18),
),
const SizedBox(height: DigitalGuideConfig.heightTiny),
Text(
roomInformation.roomPurpose,
style: context.textTheme.headline
.copyWith(fontSize: 12, fontWeight: FontWeight.normal),
),
if (roomInformation.workingDaysAndHours.isNotEmpty)
const SizedBox(height: DigitalGuideConfig.heightMedium),
if (roomInformation.workingDaysAndHours.isNotEmpty)
Text(
"${context.localize.working_hours}:",
style: context.textTheme.headline,
),
if (roomInformation.workingDaysAndHours.isNotEmpty)
const SizedBox(height: DigitalGuideConfig.heightSmall),
Text(
roomInformation.workingDaysAndHours,
style: context.textTheme.body.copyWith(fontSize: 16),
),
if (roomInformation.workingDaysAndHours.isNotEmpty)
const SizedBox(height: DigitalGuideConfig.heightMedium),
Text(
context.localize.key_information,
style: context.textTheme.headline,
),
const SizedBox(height: DigitalGuideConfig.heightSmall),
BulletList(
items: [
roomInformation.location,
roomInformation.comment,
roomInformation.areEntrancesComment,
roomInformation.isOneLevelFloorComment,
roomInformation.arePlacesForWheelchairsComment,
roomInformation.isOneLevelFloorComment,
].toIList(),
),
if (room.imagesIds != null && room.imagesIds!.isNotEmpty)
const SizedBox(
height: DigitalGuideConfig.heightMedium,
),
DigitalGuidePhotoRow(imagesIDs: room.imagesIds.toIList()),
const SizedBox(
height: DigitalGuideConfig.heightMedium,
),
DigitalGuideNavLink(
onTap: () {},
text: context.localize.doors,
),
const SizedBox(
height: DigitalGuideConfig.heightMedium,
),
DigitalGuideNavLink(
onTap: () {},
text: context.localize.platforms,
),
const SizedBox(
height: DigitalGuideConfig.heightMedium,
),
DigitalGuideNavLink(
onTap: () {},
text: context.localize.stairs,
),
];
return Scaffold(
appBar: DetailViewAppBar(
actions: [AccessibilityButton()],
),
body: Padding(
padding: const EdgeInsets.all(DigitalGuideConfig.paddingMedium),
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemCount: widgets.length,
shrinkWrap: true,
itemBuilder: (context, index) => widgets[index],
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
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 "../../../presentation/widgets/digital_guide_nav_link.dart";
import "../data/models/digital_guide_room.dart";
import "../data/repository/rooms_repository.dart";

class DigitalGuideRoomExpansionTileContent extends ConsumerWidget {
const DigitalGuideRoomExpansionTileContent({
required this.digitalGuideResponse,
});

final DigitalGuideResponse digitalGuideResponse;

@override
Widget build(BuildContext context, WidgetRef ref) {
final roomsInBuilding =
ref.watch(roomsRepositoryProvider(digitalGuideResponse));
return roomsInBuilding.when(
data: (data) => _DigitalGuideRoomExpansionTileContent(rooms: data),
error: (error, _) => MyErrorWidget(error),
loading: () => const Center(
child: CircularProgressIndicator(),
),
);
}
}

class _DigitalGuideRoomExpansionTileContent extends ConsumerWidget {
const _DigitalGuideRoomExpansionTileContent({required this.rooms});

final IList<DigitalGuideRoom> rooms;

@override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: DigitalGuideConfig.paddingMedium,
vertical: DigitalGuideConfig.paddingMedium,
),
child: ListView.separated(
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (context, index) => const SizedBox(
height: DigitalGuideConfig.heightMedium,
),
itemCount: rooms.length,
shrinkWrap: true,
itemBuilder: (context, index) => DigitalGuideNavLink(
onTap: () async {
await ref.navigateRoomDetails(
rooms[index],
);
},
text: rooms[index].translations.pl.name,
),
),
);
}
}
6 changes: 6 additions & 0 deletions lib/features/navigator/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import "../departments_view/departments_view.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";
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 "../guide_detail_view/guide_detail_view.dart";
import "../guide_view/guide_view.dart";
import "../home_view/home_view.dart";
Expand All @@ -21,6 +23,7 @@ import "../sks-menu/presentation/sks_menu_screen.dart";
import "root_view.dart";

part "app_router.g.dart";

part "app_router.gr.dart";

class _NoTransitionRoute extends CustomRoute {
Expand Down Expand Up @@ -108,6 +111,9 @@ class AppRouter extends RootStackRouter {
path: "/aboutUs",
page: AboutUsRoute.page,
),
AutoRoute(
page: DigitalGuideRoomDetailRoute.page,
),
];
}

Expand Down
7 changes: 6 additions & 1 deletion lib/features/navigator/utils/navigation_commands.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import "package:flutter_riverpod/flutter_riverpod.dart";

import "../../buildings_view/model/building_model.dart";
import "../../digital_guide_view/tabs/adapted_toilets/data/models/adapted_toilet.dart";
import "../../digital_guide_view/tabs/rooms/data/models/digital_guide_room.dart";
import "../../parkings_view/models/parking.dart";
import "../app_router.dart";
import "../navigation_controller.dart";

/// just a one place to gather implementation details of navigation flow
/// - for easy maintainance
/// - for easy maintenance
extension NavigationX on WidgetRef {
NavigationController get _router =>
read(navigationControllerProvider.notifier);
Expand Down Expand Up @@ -85,4 +86,8 @@ extension NavigationX on WidgetRef {
Future<void> navigateAdaptedToiletDetails(AdaptedToilet adaptedToilet) async {
await _router.push(AdaptedToiletDetailRoute(adaptedToilet: adaptedToilet));
}

Future<void> navigateRoomDetails(DigitalGuideRoom room) async {
await _router.push(DigitalGuideRoomDetailRoute(room: room));
}
}
8 changes: 6 additions & 2 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
"people_blind" : "niewidomych",
"people_with_motor_disability" : "posiadających dysfunkcje ruchu",
"people_with_high_sensory_sensitivity" : "o wysokiej wrażliwości sensorycznej",
"see_all_photos" : "Zobacz {photos, plural, =0{{photos} zdjęć} =1{{photos} zdjęcie} few{wszystkie {photos} zdjęcia} other{wszystkie {photos} zjęć}}",
"see_all_photos" : "Zobacz {photos, plural, =0{{photos} zdjęć} =1{{photos} zdjęcie} few{wszystkie {photos} zdjęcia} other{wszystkie {photos} zdjęć}}",
"are_dangerous_elements_comment_prefix" : "W otoczeniu budynku znajdują się następujące obiekty, które mogą stanowić zagrożenie: {text}",
"are_high_curbs_at_parking_space_for_pwd" : "Przy miejscach postojowych dla osób z niepełnosprawnościami {value, select, false{nie} other{}} znajduje się wysoki krawężnik. ",
"is_lit" : "Otoczenie budynku {value, select, false{nie} other{}} jest oświetlone po zmroku. ",
Expand All @@ -283,5 +283,9 @@
"strategicBadgeTooltip": "Koło Strategiczne PWr",
"strategic_club_abbr": "KS",
"emptySection": "Brak członków zespołu w tej wersji",
"digital_guide_offline" : "Cyfrowego Przewodnika"
"digital_guide_offline" : "Cyfrowego Przewodnika",
"platforms" : "Podesty",
"stairs" : "Schody",
"key_information" : "Najważniejsze informacje",
"working_hours" : "Godziny otwarcia"
}

0 comments on commit c96dbf2

Please sign in to comment.