diff --git a/images/atmosfer.png b/images/atmosfer.png new file mode 100644 index 0000000..9b5815c Binary files /dev/null and b/images/atmosfer.png differ diff --git a/images/google-icon-logo.png b/images/google-icon-logo.png new file mode 100644 index 0000000..1253984 Binary files /dev/null and b/images/google-icon-logo.png differ diff --git a/lib/blocs/monitoring_bloc/monitoring_bloc.dart b/lib/blocs/monitoring_bloc/monitoring_bloc.dart index 9d83ea7..8b13789 100644 --- a/lib/blocs/monitoring_bloc/monitoring_bloc.dart +++ b/lib/blocs/monitoring_bloc/monitoring_bloc.dart @@ -1,50 +1 @@ -import 'dart:async'; -import 'package:bloc/bloc.dart'; -import 'package:equatable/equatable.dart'; -import 'package:firebase_database/firebase_database.dart'; - -part 'monitoring_event.dart'; -part 'monitoring_state.dart'; - -class MonitoringBloc extends Bloc { - final DatabaseReference _realtimeRef = - FirebaseDatabase.instance.ref('anemometer/realtime'); - StreamSubscription? _realtimeSub; - - MonitoringBloc() : super(const MonitoringState.initial()) { - on(_onLoadMonitoringData); - on(_onMonitoringDataUpdated); - } - - void _onLoadMonitoringData( - LoadMonitoringData event, Emitter emit) { - emit(const MonitoringState.loading()); - - // Start listening to realtime data - _realtimeSub = _realtimeRef.onValue.listen((event) { - final data = event.snapshot.value; - if (data is Map) { - final speed = (data['kecepatan'] ?? 0).toDouble(); - final timestamp = data['timestamp'] ?? 0; - final waktu = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); - - add(MonitoringDataUpdated(speed: speed, timestamp: waktu)); - } - }); - } - - void _onMonitoringDataUpdated( - MonitoringDataUpdated event, Emitter emit) { - emit(MonitoringState.loaded( - currentSpeed: event.speed, - lastUpdateTime: event.timestamp, - )); - } - - @override - Future close() { - _realtimeSub?.cancel(); - return super.close(); - } -} diff --git a/lib/blocs/monitoring_bloc/monitoring_event.dart b/lib/blocs/monitoring_bloc/monitoring_event.dart index e93e753..8b13789 100644 --- a/lib/blocs/monitoring_bloc/monitoring_event.dart +++ b/lib/blocs/monitoring_bloc/monitoring_event.dart @@ -1,25 +1 @@ -part of 'monitoring_bloc.dart'; -sealed class MonitoringEvent extends Equatable { - const MonitoringEvent(); - - @override - List get props => []; -} - -class LoadMonitoringData extends MonitoringEvent { - const LoadMonitoringData(); -} - -class MonitoringDataUpdated extends MonitoringEvent { - final double speed; - final DateTime timestamp; - - const MonitoringDataUpdated({ - required this.speed, - required this.timestamp, - }); - - @override - List get props => [speed, timestamp]; -} diff --git a/lib/blocs/monitoring_bloc/monitoring_state.dart b/lib/blocs/monitoring_bloc/monitoring_state.dart index 9e28f38..8b13789 100644 --- a/lib/blocs/monitoring_bloc/monitoring_state.dart +++ b/lib/blocs/monitoring_bloc/monitoring_state.dart @@ -1,34 +1 @@ -part of 'monitoring_bloc.dart'; -class MonitoringState extends Equatable { - final MonitoringStatus status; - final double? currentSpeed; - final DateTime? lastUpdateTime; - - const MonitoringState._({ - this.status = MonitoringStatus.initial, - this.currentSpeed, - this.lastUpdateTime, - }); - - const MonitoringState.initial() : this._(); - - const MonitoringState.loading() : this._(status: MonitoringStatus.loading); - - const MonitoringState.loaded({ - required double currentSpeed, - required DateTime lastUpdateTime, - }) : this._( - status: MonitoringStatus.loaded, - currentSpeed: currentSpeed, - lastUpdateTime: lastUpdateTime, - ); - - const MonitoringState.error(String message) - : this._(status: MonitoringStatus.error); - - @override - List get props => [status, currentSpeed, lastUpdateTime]; -} - -enum MonitoringStatus { initial, loading, loaded, error } diff --git a/lib/screens/auth/views/sign_in_screen.dart b/lib/screens/auth/views/sign_in_screen.dart index f687089..4eedd24 100644 --- a/lib/screens/auth/views/sign_in_screen.dart +++ b/lib/screens/auth/views/sign_in_screen.dart @@ -124,19 +124,22 @@ class _SignInScreenState extends State { )), ) : const CircularProgressIndicator(), + + /// ======= Tombol Login Google ======= /// const SizedBox(height: 20), SizedBox( width: MediaQuery.of(context).size.width * 0.5, child: TextButton.icon( onPressed: () { + // == Mengirim event login Google ke Bloc == // context.read().add(GoogleSignInRequired()); }, - icon: const Text( - 'G', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.blue, + icon: SizedBox( + height: 20, + width: 20, + child: Image.asset( + 'images/google-icon-logo.png', + fit: BoxFit.contain, ), ), label: const Text( diff --git a/lib/screens/auth/views/sign_up_screen.dart b/lib/screens/auth/views/sign_up_screen.dart index 32b70e5..a32223e 100644 --- a/lib/screens/auth/views/sign_up_screen.dart +++ b/lib/screens/auth/views/sign_up_screen.dart @@ -234,16 +234,16 @@ class _SignUpScreenState extends State { .read() .add(GoogleSignInRequired()); }, - icon: const Text( - 'G', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.blue, + icon: SizedBox( + height: 20, + width: 20, + child: Image.asset( + 'images/google-icon-logo.png', + fit: BoxFit.contain, ), ), label: const Text( - 'Daftar dengan Google', + 'Sign In With Google', style: TextStyle( color: Colors.black, fontSize: 16, diff --git a/lib/screens/home/views/home_screen.dart b/lib/screens/home/views/home_screen.dart index 2831845..007c2ff 100644 --- a/lib/screens/home/views/home_screen.dart +++ b/lib/screens/home/views/home_screen.dart @@ -1,10 +1,66 @@ import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../blocs/authentication_bloc/authentication_bloc.dart'; +import 'main_drawer.dart'; class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { - return Scaffold(); + return Scaffold( + drawer: const MainDrawer(), + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0.5, // Kasih sedikit bayangan tipis agar elegan + centerTitle: false, + leading: Builder( + builder: (context) => IconButton( + icon: const Icon(Icons.menu, + color: Colors.black), // Ikon garis 3 horizontal + onPressed: () { + // ini kodenya untuk membuka: + Scaffold.of(context).openDrawer(); + }, + )), + title: Row( + children: [ + // Ganti dengan Image.asset jika sudah ada logo + const Icon(Icons.cloud_queue, color: Colors.blue, size: 28), + const SizedBox(width: 10), + Text( + "Klimatologi", + style: GoogleFonts.rubik( + color: Colors.black, + fontWeight: FontWeight.bold, + fontSize: 20, + ), + ), + ], + ), + actions: [ + IconButton( + icon: const Icon(Icons.notifications_none, color: Colors.black), + onPressed: () { + // Aksi notifikasi + }, + ), + IconButton( + icon: const Icon(Icons.logout, color: Colors.black), + onPressed: () { + // Trigger Logout di AuthenticationBloc kamu + context + .read() + .add(AuthenticationLogoutRequested()); + }, + ), + const SizedBox(width: 8), + ], + ), + body: const Center( + child: Text("body home page"), + ), + ); } } diff --git a/lib/screens/home/views/main_drawer.dart b/lib/screens/home/views/main_drawer.dart new file mode 100644 index 0000000..4f50ed7 --- /dev/null +++ b/lib/screens/home/views/main_drawer.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../blocs/authentication_bloc/authentication_bloc.dart'; + +class MainDrawer extends StatelessWidget { + const MainDrawer({super.key}); + + @override + Widget build(BuildContext context) { + return Drawer( + child: Column( + children: [ + // Bagian Header (Tempat Nama/Email) + BlocBuilder( + builder: (context, state) { + // Mengambil email user dari Bloc Global + String userEmail = state.user?.email ?? "Guest"; + String userName = + userEmail.split('@')[0]; // Ambil depan email saja + + return UserAccountsDrawerHeader( + decoration: const BoxDecoration(color: Colors.blue), + currentAccountPicture: const CircleAvatar( + backgroundColor: Colors.white, + child: Icon(Icons.person, size: 40, color: Colors.blue), + ), + accountName: Text( + userName, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + accountEmail: Text(userEmail), + ); + }, + ), + + // Daftar Menu + ListTile( + leading: const Icon(Icons.speed), + title: const Text("Wind Speed"), + onTap: () { + // Navigasi ke Wind Speed + }, + ), + ListTile( + leading: const Icon(Icons.water_drop), + title: const Text("Evaporasi"), + onTap: () {}, + ), + ListTile( + leading: Image.asset( + 'images/atmosfer.png', + height: 20, + width: 20, + ), + title: const Text("Udara"), + onTap: () {}, + ), + const Spacer(), // Dorong menu logout ke paling bawah + const Divider(), + ListTile( + leading: const Icon(Icons.logout, color: Colors.red), + title: const Text("Logout", style: TextStyle(color: Colors.red)), + onTap: () { + context + .read() + .add(AuthenticationLogoutRequested()); + }, + ), + const SizedBox(height: 20), + ], + ), + ); + } +} diff --git a/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart b/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart index 142ed18..b5da549 100644 --- a/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart +++ b/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart @@ -1,6 +1,6 @@ -import 'dart:developer'; +// import 'dart:developer'; import 'dart:async'; -import 'package:rxdart/rxdart.dart'; +// import 'package:rxdart/rxdart.dart'; import 'package:firebase_database/firebase_database.dart'; import 'package:monitoring_repository/monitoring_repository.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index a9c35a5..15b45a0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,5 +31,5 @@ dev_dependencies: sdk: flutter flutter: uses-material-design: true - # assets: - # - assets/images/ + assets: + - images/