Skip to content

Commit b0418ef

Browse files
committed
Done detail
1 parent d98523d commit b0418ef

File tree

6 files changed

+361
-72
lines changed

6 files changed

+361
-72
lines changed

lib/app/app.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ class MyApp extends StatelessWidget {
239239
blocSupplier: () {
240240
return RelatedRoomsTabBloc(
241241
injector.roomRepository,
242+
injector.priceFormat,
242243
roomId,
243244
)..fetch.call();
244245
},

lib/pages/detail/comments/comments_tab_page.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,33 @@ class _CommentsTabPagesState extends State<CommentsTabPages> {
122122
}
123123

124124
final comments = state.comments;
125+
126+
if (comments.isEmpty) {
127+
return Container(
128+
constraints: BoxConstraints.expand(),
129+
child: Center(
130+
child: Column(
131+
mainAxisAlignment: MainAxisAlignment.center,
132+
children: <Widget>[
133+
Icon(
134+
Icons.comment,
135+
size: 48,
136+
color: Theme.of(context).accentColor,
137+
),
138+
const SizedBox(height: 8),
139+
Text(
140+
'Empty comments',
141+
style: Theme.of(context)
142+
.textTheme
143+
.title
144+
.copyWith(fontSize: 15),
145+
),
146+
],
147+
),
148+
),
149+
);
150+
}
151+
125152
return Scrollbar(
126153
child: ListView.separated(
127154
physics: const BouncingScrollPhysics(),

lib/pages/detail/related/related_rooms_tab_bloc.dart

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:find_room/data/rooms/firestore_room_repository.dart';
88
import 'package:find_room/models/room_entity.dart';
99
import 'package:find_room/pages/detail/related/related_rooms_tab_state.dart';
1010
import 'package:flutter/foundation.dart';
11+
import 'package:intl/intl.dart';
1112
import 'package:rxdart/rxdart.dart';
1213

1314
class RelatedRoomsTabBloc implements BaseBloc {
@@ -35,6 +36,7 @@ class RelatedRoomsTabBloc implements BaseBloc {
3536

3637
factory RelatedRoomsTabBloc(
3738
FirestoreRoomRepository roomsRepo,
39+
NumberFormat priceFormat,
3840
String roomId,
3941
) {
4042
// ignore_for_file: close_sinks
@@ -50,30 +52,27 @@ class RelatedRoomsTabBloc implements BaseBloc {
5052
/// Input actions to state
5153
///
5254
final fetchChanges = fetchSubject.exhaustMap(
53-
(_) {
54-
return Rx.defer(() =>
55-
Stream.fromFuture(roomsRepo.getRelatedRoomsBy(roomId: roomId)))
56-
.map(_toItem)
57-
.map<PartialStateChange>((items) => GetUsersSuccessChange(items))
58-
.startWith(const LoadingChange())
59-
.doOnError((e, s) => messageSubject.add(GetRoomsErrorMessage(e)))
60-
.onErrorReturnWith((e) => GetUsersErrorChange(e));
61-
},
55+
(_) => Rx.defer(() =>
56+
Stream.fromFuture(roomsRepo.getRelatedRoomsBy(roomId: roomId)))
57+
.map((entities) => _toItem(entities, priceFormat))
58+
.map<PartialStateChange>((items) => GetUsersSuccessChange(items))
59+
.startWith(const LoadingChange())
60+
.doOnError((e, s) => messageSubject.add(GetRoomsErrorMessage(e)))
61+
.onErrorReturnWith((e) => GetUsersErrorChange(e)),
6262
);
6363
final refreshChanges = refreshSubject
6464
.throttleTime(const Duration(milliseconds: 600))
6565
.exhaustMap(
66-
(completer) {
67-
return Rx.defer(() =>
68-
Stream.fromFuture(roomsRepo.getRelatedRoomsBy(roomId: roomId)))
69-
.map(_toItem)
70-
.map<PartialStateChange>((items) => GetUsersSuccessChange(items))
71-
.doOnError((e, s) => messageSubject.add(RefreshFailureMessage(e)))
72-
.doOnData((_) => messageSubject.add(const RefreshSuccessMessage()))
73-
.onErrorResumeNext(Stream.empty())
74-
.doOnDone(() => completer.complete());
75-
},
76-
);
66+
(completer) => Rx.defer(() => Stream.fromFuture(
67+
roomsRepo.getRelatedRoomsBy(roomId: roomId)))
68+
.map((entities) => _toItem(entities, priceFormat))
69+
.map<PartialStateChange>((items) => GetUsersSuccessChange(items))
70+
.doOnError((e, s) => messageSubject.add(RefreshFailureMessage(e)))
71+
.doOnData(
72+
(_) => messageSubject.add(const RefreshSuccessMessage()))
73+
.onErrorResumeNext(Stream.empty())
74+
.doOnDone(() => completer.complete()),
75+
);
7776

7877
final initialState = RelatedRoomsState.initial();
7978
final state$ = Rx.merge([fetchChanges, refreshChanges])
@@ -132,9 +131,24 @@ class RelatedRoomsTabBloc implements BaseBloc {
132131
return state;
133132
}
134133

135-
static List<RoomItem> _toItem(List<RoomEntity> entities) {
134+
static List<RoomItem> _toItem(
135+
List<RoomEntity> entities,
136+
NumberFormat priceFormat,
137+
) {
136138
return entities
137-
.map((e) => RoomItem((b) => b..id = e.id))
139+
.map(
140+
(e) => RoomItem(
141+
(b) => b
142+
..id = e.id
143+
..imageUrl = e.images.isEmpty ? null : e.images.first
144+
..title = e.title
145+
..districtName = e.districtName
146+
..address = e.address
147+
..price = priceFormat.format(e.price)
148+
..createdTime = e.createdAt?.toDate()
149+
..updatedTime = e.updatedAt?.toDate(),
150+
),
151+
)
138152
.toList(growable: false);
139153
}
140154
}

lib/pages/detail/related/related_rooms_tab_page.dart

Lines changed: 152 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import 'dart:io';
2-
1+
import 'package:cached_network_image/cached_network_image.dart';
2+
import 'package:find_room/app/app_locale_bloc.dart';
33
import 'package:find_room/bloc/bloc_provider.dart';
4+
import 'package:find_room/generated/i18n.dart';
45
import 'package:find_room/pages/detail/related/related_rooms_tab_bloc.dart';
56
import 'package:find_room/pages/detail/related/related_rooms_tab_state.dart';
67
import 'package:flutter/material.dart';
8+
import 'package:intl/intl.dart';
79

810
class RelatedRoomsTabPage extends StatefulWidget {
911
const RelatedRoomsTabPage({Key key}) : super(key: key);
@@ -42,6 +44,33 @@ class _RelatedRoomsTabPageState extends State<RelatedRoomsTabPage> {
4244
error: state.error,
4345
);
4446
}
47+
48+
if (state.items.isEmpty) {
49+
return Container(
50+
constraints: BoxConstraints.expand(),
51+
child: Center(
52+
child: Column(
53+
mainAxisAlignment: MainAxisAlignment.center,
54+
children: <Widget>[
55+
Icon(
56+
Icons.home,
57+
size: 48,
58+
color: Theme.of(context).accentColor,
59+
),
60+
const SizedBox(height: 8),
61+
Text(
62+
'Empty related rooms',
63+
style: Theme.of(context)
64+
.textTheme
65+
.title
66+
.copyWith(fontSize: 15),
67+
),
68+
],
69+
),
70+
),
71+
);
72+
}
73+
4574
return RefreshIndicator(
4675
child: ListView.builder(
4776
physics: AlwaysScrollableScrollPhysics(),
@@ -117,63 +146,141 @@ class ListItemWidget extends StatelessWidget {
117146

118147
@override
119148
Widget build(BuildContext context) {
149+
final currentLocale =
150+
BlocProvider.of<LocaleBloc>(context).locale$.value.languageCode;
151+
final subTitle14 =
152+
Theme.of(context).textTheme.subtitle.copyWith(fontSize: 14);
153+
final subTitle12 = subTitle14.copyWith(fontSize: 12);
154+
155+
final imageW = 64 * 1.5;
156+
final imageH = 96 * 1.5;
157+
120158
return Container(
121159
margin: const EdgeInsets.all(4),
122-
padding: const EdgeInsets.all(12),
123160
decoration: BoxDecoration(
124161
color: Theme.of(context).canvasColor,
125162
borderRadius: BorderRadius.circular(12),
126163
boxShadow: [
127164
BoxShadow(
128-
blurRadius: 16,
165+
blurRadius: 8,
129166
offset: Offset(0, 4),
130-
color: Colors.grey.shade600,
167+
color: Colors.grey.shade400,
131168
)
132169
],
133170
),
134-
child: Row(
135-
children: <Widget>[
136-
Container(
137-
decoration: BoxDecoration(shape: BoxShape.circle, boxShadow: [
138-
BoxShadow(
139-
blurRadius: 10,
140-
offset: Offset(2, 2),
141-
color: Colors.grey.shade500,
142-
spreadRadius: 1)
143-
]),
144-
child: ClipOval(
145-
child: Image.network(
146-
'',
147-
width: 64,
148-
height: 64,
149-
fit: BoxFit.cover,
150-
),
151-
),
152-
),
153-
SizedBox(
154-
width: 16,
155-
),
156-
Expanded(
157-
child: Column(
158-
crossAxisAlignment: CrossAxisAlignment.stretch,
159-
children: <Widget>[
160-
Text(
161-
'${item.id} ${item.id}',
162-
textAlign: TextAlign.left,
163-
style: Theme.of(context).textTheme.title,
164-
),
165-
SizedBox(
166-
height: 8,
171+
child: Material(
172+
child: InkWell(
173+
onTap: () {
174+
Navigator.pushNamed(
175+
context,
176+
'/room_detail',
177+
arguments: item.id,
178+
);
179+
},
180+
child: Row(
181+
children: <Widget>[
182+
ClipRRect(
183+
borderRadius: BorderRadius.circular(12),
184+
child: CachedNetworkImage(
185+
imageUrl: item.imageUrl ?? '',
186+
width: imageW,
187+
height: imageH,
188+
fit: BoxFit.cover,
189+
placeholder: (_, __) => Container(
190+
width: imageW,
191+
height: imageH,
192+
child: Center(
193+
child: CircularProgressIndicator(
194+
strokeWidth: 2,
195+
),
196+
),
197+
),
198+
errorWidget: (_, __, ___) => Center(
199+
child: Container(
200+
width: imageW,
201+
height: imageH,
202+
child: Column(
203+
mainAxisAlignment: MainAxisAlignment.center,
204+
children: <Widget>[
205+
Icon(Icons.error_outline),
206+
Text(
207+
'Error',
208+
style: subTitle12,
209+
),
210+
],
211+
),
212+
),
213+
),
167214
),
168-
Text(
169-
item.id,
170-
textAlign: TextAlign.left,
171-
style: Theme.of(context).textTheme.subtitle,
215+
),
216+
SizedBox(
217+
width: 16,
218+
),
219+
Expanded(
220+
child: Column(
221+
crossAxisAlignment: CrossAxisAlignment.stretch,
222+
mainAxisSize: MainAxisSize.max,
223+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
224+
children: <Widget>[
225+
Text(
226+
item.title,
227+
maxLines: 2,
228+
textAlign: TextAlign.start,
229+
overflow: TextOverflow.ellipsis,
230+
style: Theme.of(context).textTheme.title.copyWith(
231+
fontSize: 16,
232+
fontWeight: FontWeight.bold,
233+
),
234+
),
235+
Text(
236+
'${item.districtName} - ${item.address}',
237+
maxLines: 2,
238+
textAlign: TextAlign.start,
239+
overflow: TextOverflow.ellipsis,
240+
style: subTitle14,
241+
),
242+
SizedBox(
243+
height: 4,
244+
),
245+
Text(
246+
item.price,
247+
maxLines: 1,
248+
textAlign: TextAlign.start,
249+
overflow: TextOverflow.ellipsis,
250+
style: Theme.of(context).textTheme.subtitle.copyWith(
251+
fontSize: 15,
252+
color: Theme.of(context).accentColor,
253+
fontWeight: FontWeight.bold,
254+
),
255+
),
256+
SizedBox(
257+
height: 4,
258+
),
259+
Text(
260+
S.of(context).created_date(DateFormat.yMMMd(currentLocale)
261+
.add_Hm()
262+
.format(item.createdTime)),
263+
maxLines: 1,
264+
textAlign: TextAlign.start,
265+
overflow: TextOverflow.ellipsis,
266+
style: subTitle12,
267+
),
268+
Text(
269+
S.of(context).last_updated_date(
270+
DateFormat.yMMMd(currentLocale)
271+
.add_Hm()
272+
.format(item.createdTime)),
273+
maxLines: 1,
274+
textAlign: TextAlign.start,
275+
overflow: TextOverflow.ellipsis,
276+
style: subTitle12,
277+
),
278+
],
172279
),
173-
],
174-
),
280+
),
281+
],
175282
),
176-
],
283+
),
177284
),
178285
);
179286
}

lib/pages/detail/related/related_rooms_tab_state.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@ abstract class RelatedRoomsState
2828
abstract class RoomItem implements Built<RoomItem, RoomItemBuilder> {
2929
String get id;
3030

31+
String get title;
32+
33+
String get price;
34+
35+
String get address;
36+
37+
String get districtName;
38+
39+
@nullable
40+
String get image;
41+
42+
@nullable
43+
DateTime get createdTime;
44+
45+
@nullable
46+
DateTime get updatedTime;
47+
48+
@nullable
49+
String get imageUrl;
50+
3151
RoomItem._();
3252

3353
factory RoomItem([updates(RoomItemBuilder b)]) = _$RoomItem;

0 commit comments

Comments
 (0)