Fakultas Ilmu Komputer UI

dashboard.dart 15.5 KB
Newer Older
1
import 'package:bisaGo/bloc/lokasi_response_bloc.dart';
2
import 'package:bisaGo/model/komentar.dart';
3
import 'package:bisaGo/model/lokasi.dart';
4
5
import 'package:bisaGo/bloc/kegiatan_terdekat_bloc.dart';
import 'package:bisaGo/model/kegiatan.dart';
6
7
import 'package:bisaGo/page/filter_fasilitas/postingan/detail_post_kegiatan.dart';
import 'package:bisaGo/repository/kegiatan_repository.dart';
8
import 'package:bisaGo/utils/custom_kegiatan_terdekat_button.dart';
9
import 'package:bisaGo/network/data/network_model.dart';
10
11
import 'package:bisaGo/page/filter_fasilitas/postingan/detail_post.dart';
import 'package:bisaGo/repository/komentar_repository.dart';
12
import 'package:bisaGo/utils/custom_dashboard_location_button.dart';
13
import 'package:bisaGo/utils/location_turn_on_dialog.dart';
14
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
15
import 'package:flutter/material.dart';
16
import 'package:flutter_dotenv/flutter_dotenv.dart';
17
import 'package:geolocator/geolocator.dart';
18
import 'package:google_maps_flutter/google_maps_flutter.dart';
19
20
21
22
import 'package:bisaGo/component/bisago_appbar.dart';
import 'package:bisaGo/component/bisago_drawer.dart';
import 'package:bisaGo/config/styles.dart';
import 'package:bisaGo/page/pencarian/pencarian.dart';
23
import 'package:google_maps_webservice/places.dart';
24
25

class Dashboard extends StatefulWidget {
26
  const Dashboard({Key key}) : super(key: key);
27
  @override
28
29
30
31
  DashboardState createState() => DashboardState();
}

class DashboardState extends State<Dashboard> {
Fakhira Devina's avatar
Fakhira Devina committed
32
  final double cameraZoom = 15;
33
34
35
  GoogleMapController mapController;
  Geolocator geolocator;
  LatLng currentLocation;
36
  Set<Marker> markers = {};
37

38
  LokasiResponseBloc bloc = LokasiResponseBloc();
39
  KegiatanTerdekatBloc blocKegiatanTerdekat = KegiatanTerdekatBloc();
40

41
42
43
  @override
  void initState() {
    super.initState();
44
    _showTurnOnLocationDialog(context);
45
    geolocator = Geolocator()..forceAndroidLocationManager;
46
    initDynamicLinks();
47
    setInitialLocation();
48
49
  }

50
  void _navigateToPencarianPage(BuildContext context) {
51
    final route = MaterialPageRoute(builder: (_) => const Pencarian());
52
53
54
    Navigator.of(context).push(route);
  }

55
56
57
58
  // void _navigateToInformasiLayananDisabilitasPage(BuildContext context) {
  //   final route = MaterialPageRoute(builder: (_) => ListSekolah());
  //   Navigator.of(context).push(route);
  // }
59

60
  static const textFieldKey = Key('Text Field Mau Kemana');
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

  void _showTurnOnLocationDialog(BuildContext context) {
    bloc.isLocationServiceTurnedOn().then(
      (value) {
        if (!value) {
          showDialog(
            context: context,
            builder: (BuildContext context) {
              return LocationTurnOnDialog(
                message: 'Mohon Menyalakan Lokasi',
                title: 'Lokasi',
                onPressed: () {
                  bloc.requestLocationService().then((loc) {
                    if (loc) {
                      Navigator.pop(context);
                    }
                  });
                },
              );
            },
          );
        }
      },
    );
  }

87
88
89
  @override
  Widget build(BuildContext context) {
    return Scaffold(
90
      drawer: BisaGoDrawer(),
91
92
      body: Stack(
        key: const Key('Stack'),
93
        //alignment: AlignmentDirectional.bottomStart,
94
95
        children: <Widget>[
          Container(
96
              padding: EdgeInsets.only(top: 35),
Yoga Pratama's avatar
Yoga Pratama committed
97
98
99
100
              child: _buildGoogleMap(context)),
          Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <
              Widget>[
            Container(
101
102
103
104
105
                height: 40,
                alignment: Alignment.center,
                decoration: const BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.only(
Yoga Pratama's avatar
Yoga Pratama committed
106
107
                      bottomLeft: Radius.circular(10.0),
                      bottomRight: Radius.circular(10.0)),
108
109
                ),
                child: Padding(
Yoga Pratama's avatar
Yoga Pratama committed
110
111
112
113
                    padding:
                        const EdgeInsets.symmetric(horizontal: doubleSpace),
                    child: StreamBuilder<NetworkModel>(
                        stream: blocKegiatanTerdekat.kegiatanTerdekatStream,
114
115
116
117
118
                        builder: (context, snapshot) {
                          if (snapshot.hasData) {
                            switch (snapshot.data.status) {
                              case Status.loading:
                                return Container(
Yoga Pratama's avatar
Yoga Pratama committed
119
120
121
122
123
                                    child: const Center(
                                        child: LinearProgressIndicator(
                                  valueColor: AlwaysStoppedAnimation<Color>(
                                      greenPrimary),
                                )));
124
125
                                break;
                              case Status.completed:
Yoga Pratama's avatar
Yoga Pratama committed
126
127
128
                                final kegiatanTerdekat = snapshot.data.data;
                                return _buildKegiatanTerdekatWidget(
                                    kegiatanTerdekat);
129
130
131
                                break;
                              case Status.error:
                                return Container(
Yoga Pratama's avatar
Yoga Pratama committed
132
133
134
135
136
137
138
139
140
                                    child: const Center(
                                  child: Text(
                                      'Tidak ada kegiatan dalam waktu dekat',
                                      style: TextStyle(
                                        color: greenPrimary,
                                        fontSize: 16,
                                        fontFamily: 'Muli',
                                      )),
                                ));
141
142
143
144
145
                                break;
                            }
                            return Container();
                          }
                          return Container();
Yoga Pratama's avatar
Yoga Pratama committed
146
147
148
149
150
151
152
153
                        }))), // Container info kegiatan
            Container(
              height: 285,
              alignment: Alignment.bottomCenter,
              decoration: const BoxDecoration(
                color: white,
                borderRadius: BorderRadius.all(
                  Radius.circular(10.0),
154
                ),
Yoga Pratama's avatar
Yoga Pratama committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
              ),
              padding: const EdgeInsets.symmetric(
                  horizontal: doubleSpace, vertical: doubleSpace),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  InkWell(
                    key: const Key('Navigate to Pencarian'),
                    onTap: () => _navigateToPencarianPage(context),
                    child: Container(
                      key: const Key('Container Text Field'),
                      padding: EdgeInsets.zero,
                      decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: regularBorderRadius,
                          border: Border.all(color: greenPrimary),
                          boxShadow: regularShadow),
                      child: TextFormField(
                        enabled: false,
                        key: const Key('Text Field Mau Kemana'),
                        decoration: const InputDecoration(
                          prefixIcon: Icon(
                            Icons.search,
                            color: greenPrimary,
                            size: 25,
                          ),
                          border: InputBorder.none,
                          fillColor: Colors.white,
                          labelText: 'Tekan untuk mencari tempat',
                          labelStyle: TextStyle(
                              color: greenPrimary,
                              fontSize: 20,
                              fontFamily: 'Muli',
                              fontWeight: FontWeight.w700),
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(height: doubleSpace),
                  const Text(
                    'Paling sering dicari',
                    style: TextStyle(
                      color: Colors.black,
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 10),
                  StreamBuilder<NetworkModel<LokasiListResponse>>(
                      stream: bloc.lokasiListStream,
                      builder: (context, snapshot) {
                        if (snapshot.hasData) {
                          switch (snapshot.data.status) {
                            case Status.loading:
                              return Container(
                                height: 130,
                                child: const Center(
                                  child: CircularProgressIndicator(
                                    valueColor: AlwaysStoppedAnimation<Color>(
                                        greenPrimary),
                                  ),
                                ),
                              );
                              break;
                            case Status.completed:
                              final places = snapshot.data.data.listLokasi;
                              return _buildLokasiWidget(places);
                              break;
                            case Status.error:
                              return Container(
                                height: 130,
                                child: const Center(
                                  child: Text('Gagal untuk mendapatkan tempat'),
                                ),
                              );
                              break;
                          }
                          return Container();
                        }
                        return Container();
                      }),
                ],
              ),
            ),
          ])
241
        ],
242
      ),
243
244
245
246
247
248
249
250
251
252
      // floatingActionButton: FloatingActionButton.extended(
      //   key: const Key('FloatingActionButton'),
      //   onPressed: () {
      //     _navigateToInformasiLayananDisabilitasPage(context);
      //   },
      //   label: Text('Informasi Layanan Disabilitas'),
      //   icon: Icon(Icons.search),
      //   backgroundColor: greenPrimary,
      // ),
      // floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
253
254
255
      appBar: const PreferredSize(
        preferredSize: Size.fromHeight(55),
        key: Key('Scaffold Text Field'),
256
        child: BisaGoAppBar(),
Agnes Handoko's avatar
Agnes Handoko committed
257
      ),
258
259
260
    );
  }

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  Widget _buildLokasiWidget(List<Lokasi> lokasilistresponse) {
    return Container(
      height: 130,
      child: ListView(
        scrollDirection: Axis.horizontal,
        children: [
          Row(
              children: lokasilistresponse
                  .map<Widget>((k) => LocationIconButton(
                        location: k,
                      ))
                  .toList()),
        ],
      ),
    );
  }

278
  Widget _buildKegiatanTerdekatWidget(KegiatanModel kegiatanModel) {
Yoga Pratama's avatar
Yoga Pratama committed
279
    return Container(child: KegiatanTerdekatButton(kegiatan: kegiatanModel));
280
281
  }

282
  Widget _buildGoogleMap(BuildContext context) {
283
    if (currentLocation == null) {
284
      return const Center(
285
        child: CircularProgressIndicator(),
286
      );
287
288
289
290
    } else {
      return GoogleMap(
        initialCameraPosition:
            CameraPosition(target: currentLocation, zoom: cameraZoom),
291
        onMapCreated: (GoogleMapController controller) {
292
          mapController = controller;
293
        },
294
        myLocationEnabled: true,
295
        markers: markers,
296
297
298
        onCameraMove: _onCameraMove,
      );
    }
299
300
  }

301
  void _onCameraMove(CameraPosition position) {
302
    setState(() {
303
      currentLocation = position.target;
304
305
306
    });
  }

307
  void setInitialLocation() async {
308
    final position = await geolocator.getCurrentPosition(
309
310
311
312
313
        desiredAccuracy: LocationAccuracy.high);

    setState(() {
      currentLocation = LatLng(position.latitude, position.longitude);
    });
314
  }
315
316
317
318
319
320
321
322
323

  Future<String> getLokasiName(String placeId) async {
    final _places = GoogleMapsPlaces(apiKey: DotEnv().env['API_KEY']);
    var details = await _places.getDetailsByPlaceId(
      placeId,
      fields: [
        'name',
      ],
    );
324
325
    final result = details.result;
    return result == null ? 'INVALID' : result.name;
326
327
  }

328
  void _navigateToDetailFasilitasPage(
329
      BuildContext context, String placeId, int fasilitasId) async {
330
331
332
333
334
335
336
337
338
    final fetches = await Future.wait([
      KomentarRepository().fetchDetailFasilitas(placeId, fasilitasId),
      getLokasiName(placeId),
    ]);
    final KomentarModel fasilitas = fetches[0];
    final String namaLokasi = fetches[1] ?? 'INVALID';
    final lokasi = Lokasi()
      ..placeId = placeId
      ..name = namaLokasi;
339
    final fasilitasRoute = MaterialPageRoute(
340
        builder: (BuildContext context) => DetailPostPage(
341
342
343
344
345
346
347
348
349
350
351
352
353
354
              lokasi: lokasi,
              komentar: KomentarModel(
                creator: fasilitas.creator,
                dateTime: fasilitas.dateTime,
                deskripsi: fasilitas.deskripsi,
                id: fasilitas.id,
                image: fasilitas.image,
                isVerified: fasilitas.isVerified,
                namaLokasi: lokasi.name,
                tag: fasilitas.tag,
                disabilitas: fasilitas.disabilitas,
                jumlah: fasilitas.jumlah,
              ),
            ));
355
    await Navigator.of(context).push(fasilitasRoute);
356
  }
357

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  void _navigateToDetailKegiatanPage(
      BuildContext context, String placeId, int fasilitasId) async {
    final fetches = await Future.wait([
      KegiatanRepository().fetchDetailKegiatan(placeId, fasilitasId),
      getLokasiName(placeId),
    ]);
    final KegiatanModel kegiatan = fetches[0];
    final String namaLokasi = fetches[1] ?? 'INVALID';
    final lokasi = Lokasi()
      ..placeId = placeId
      ..name = namaLokasi;
    final fasilitasRoute = MaterialPageRoute(
        builder: (BuildContext context) => DetailPostKegiatanPage(
          lokasi: lokasi,
          kegiatan: KegiatanModel(
            id: kegiatan.id,
            placeId: lokasi.placeId,
            creator: kegiatan.creator,
            namaKegiatan: kegiatan.namaKegiatan,
            penyelenggara: kegiatan.penyelenggara,
            deskripsi: kegiatan.deskripsi,
379
380
            namaKontak: kegiatan.namaKontak,
            nomorKontak: kegiatan.nomorKontak,
381
            links: kegiatan.links,
382
383
            timeStart: kegiatan.timeStart,
            timeEnd: kegiatan.timeEnd,
384
            zonaWaktu: kegiatan.zonaWaktu,
385
386
387
388
389
390
            image: kegiatan.image,
          ),
        ));
    await Navigator.of(context).push(fasilitasRoute);
  }

391
392
  void initDynamicLinks() async {
    final data = await FirebaseDynamicLinks.instance.getInitialLink();
393

394
395
396
    _handleDeepLink(data);
    FirebaseDynamicLinks.instance.onLink(
        onSuccess: (PendingDynamicLinkData dynamicLink) async {
397
398
399
      _handleDeepLink(dynamicLink);
    }, onError: (OnLinkErrorException e) async {
      print('Link Failed: ${e.message}');
400
401
    });
  }
402
403
404
405
406
407
408

  void _handleDeepLink(PendingDynamicLinkData data) async {
    final deepLink = data?.link;
    if (deepLink != null) {
      final params = deepLink.queryParameters;
      final path = deepLink.pathSegments;
      final placeId = params['place_id'];
409
      final id = int.parse(params['id']);
410
411
412
413
414
      final type = params['type'];
      if (path[0] == 'link') {
        if (type == 'fasilitas') {
          _navigateToDetailFasilitasPage(context, placeId, id);
        } else if (type == 'kegiatan') {
415
          _navigateToDetailKegiatanPage(context, placeId, id);
416
        }
417
418
419
      }
    }
  }
420
}