From adaeff826fdf5ebe49edf9b5571c4dcdb9f6c8d0 Mon Sep 17 00:00:00 2001 From: kleponijo <158453666+kleponijo@users.noreply.github.com> Date: Tue, 14 Apr 2026 14:00:25 +0700 Subject: [PATCH] woowww josssjissss --- images/windy.png | Bin 0 -> 10022 bytes .../auth/blocs/sign_in_bloc/sign_in_bloc.dart | 1 + .../auth/blocs/sign_up_bloc/sign_up_bloc.dart | 10 - lib/screens/auth/views/sign_in_screen.dart | 15 +- lib/screens/auth/views/sign_up_screen.dart | 141 ++++++------ lib/screens/auth/views/welcome_screen.dart | 160 +++++++------- lib/screens/home/views/main_drawer.dart | 8 +- .../evaporasi/blocs/evaporasi_bloc.dart | 0 .../evaporasi/blocs/evaporasi_event.dart | 0 .../evaporasi/blocs/evaporasi_state.dart | 0 .../views/evaporasi.dart} | 2 +- .../wind_speed/blocs/wind_speed_bloc.dart | 45 ++-- .../wind_speed/views/wind_speed.dart | 1 - .../wind_speed/views/wind_speed_screen.dart | 10 + packages/module_repository/pubspec.lock | 205 ------------------ packages/module_repository/pubspec.yaml | 26 --- .../lib/src/firebase_monitoring_repo.dart | 11 +- .../lib/src/firebase_user_repo.dart | 5 + pubspec.lock | 16 ++ pubspec.yaml | 5 +- web/index.html | 46 ++-- 21 files changed, 256 insertions(+), 451 deletions(-) create mode 100644 images/windy.png create mode 100644 lib/screens/monitoring/evaporasi/blocs/evaporasi_bloc.dart create mode 100644 lib/screens/monitoring/evaporasi/blocs/evaporasi_event.dart create mode 100644 lib/screens/monitoring/evaporasi/blocs/evaporasi_state.dart rename lib/screens/monitoring/{evaporasi_monitoring_screen.dart => evaporasi/views/evaporasi.dart} (99%) delete mode 100644 lib/screens/monitoring/wind_speed/views/wind_speed.dart create mode 100644 lib/screens/monitoring/wind_speed/views/wind_speed_screen.dart delete mode 100644 packages/module_repository/pubspec.lock delete mode 100644 packages/module_repository/pubspec.yaml diff --git a/images/windy.png b/images/windy.png new file mode 100644 index 0000000000000000000000000000000000000000..b5389caef65dec3971ce80f7549ca706d23acc9f GIT binary patch literal 10022 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 {>*H!(_fHn!cwo%7p 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 literal 0 HcmV?d00001 diff --git a/lib/screens/auth/blocs/sign_in_bloc/sign_in_bloc.dart b/lib/screens/auth/blocs/sign_in_bloc/sign_in_bloc.dart index d9502d1..5cdc2c8 100644 --- a/lib/screens/auth/blocs/sign_in_bloc/sign_in_bloc.dart +++ b/lib/screens/auth/blocs/sign_in_bloc/sign_in_bloc.dart @@ -24,6 +24,7 @@ class SignInBloc extends Bloc { await _userRepository.signInWithGoogle(); } catch (e) { emit(SignInFailure()); + emit(SignInInitial()); } }); diff --git a/lib/screens/auth/blocs/sign_up_bloc/sign_up_bloc.dart b/lib/screens/auth/blocs/sign_up_bloc/sign_up_bloc.dart index 7da96f5..647c241 100644 --- a/lib/screens/auth/blocs/sign_up_bloc/sign_up_bloc.dart +++ b/lib/screens/auth/blocs/sign_up_bloc/sign_up_bloc.dart @@ -20,15 +20,5 @@ class SignUpBloc extends Bloc { emit(SignUpFailure(e.toString())); } }); - - on((event, emit) async { - emit(SignUpProcess()); - try { - await _userRepository.signInWithGoogle(); - emit(SignUpSuccess()); - } catch (e) { - emit(SignUpFailure(e.toString())); - } - }); } } diff --git a/lib/screens/auth/views/sign_in_screen.dart b/lib/screens/auth/views/sign_in_screen.dart index 4eedd24..84e359a 100644 --- a/lib/screens/auth/views/sign_in_screen.dart +++ b/lib/screens/auth/views/sign_in_screen.dart @@ -25,19 +25,20 @@ class _SignInScreenState extends State { Widget build(BuildContext context) { return BlocListener( listener: (context, state) { - if (state is SignInSuccess) { - setState(() { - signInRequired = false; - }); - } else if (state is SignInProcess) { + if (state is SignInProcess) { setState(() { signInRequired = true; }); - } else if (state is SignInFailure) { + } else { setState(() { signInRequired = false; - _errorMsg = 'Invalid email or password'; }); + if (state is SignInFailure) { + setState(() { + // PERUBAHAN: Pesan error lebih umum karena Google gagal belum tentu soal password + _errorMsg = 'Sign in failed. Please try again.'; + }); + } } }, child: Form( diff --git a/lib/screens/auth/views/sign_up_screen.dart b/lib/screens/auth/views/sign_up_screen.dart index a32223e..5d50a2f 100644 --- a/lib/screens/auth/views/sign_up_screen.dart +++ b/lib/screens/auth/views/sign_up_screen.dart @@ -3,10 +3,13 @@ import 'package:user_repository/user_repository.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../../../components/my_text_field.dart'; -import '../blocs/sign_up_bloc/sign_up_bloc.dart'; +import '../blocs/sign_up_bloc/sign_up_bloc.dart' as signUp; +// import '../../../blocs/authentication_bloc/authentication_bloc.dart'; +import '../blocs/sign_in_bloc/sign_in_bloc.dart' as signIn; class SignUpScreen extends StatefulWidget { - const SignUpScreen({super.key}); + final VoidCallback? onSignInTap; + const SignUpScreen({super.key, this.onSignInTap}); @override State createState() => _SignUpScreenState(); @@ -30,18 +33,26 @@ class _SignUpScreenState extends State { @override Widget build(BuildContext context) { - return BlocListener( + return BlocListener( listener: (context, state) { - if (state is SignUpSuccess) { - setState(() { - signUpRequired = false; - }); - } else if (state is SignUpProcess) { + if (state is signUp.SignUpProcess) { setState(() { signUpRequired = true; }); - } else if (state is SignUpFailure) { - return; + } else if (state is signUp.SignUpFailure) { + setState(() { + signUpRequired = false; // Matikan loading! + }); + // Tampilkan pesan error lewat Snackbar biar user tahu kenapa gagal + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.message ?? 'An error ocurred'), + backgroundColor: Colors.red), + ); + } else if (state is signUp.SignUpSuccess) { + setState(() { + signUpRequired = false; + }); } }, child: Form( @@ -181,41 +192,48 @@ class _SignUpScreenState extends State { const SizedBox(height: 18), + /// == Sign Up == /// // Button !signUpRequired - ? SizedBox( - width: MediaQuery.of(context).size.width * 0.92, - child: ElevatedButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - MyUser myUser = MyUser.empty; - myUser.email = emailController.text; - myUser.name = nameController.text; + ? Center( + child: SizedBox( + width: + MediaQuery.of(context).size.width * 0.5, + child: ElevatedButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + MyUser myUser = MyUser.empty; + myUser.email = emailController.text; + myUser.name = nameController.text; - setState(() { - context.read().add( - SignUpRequired( - myUser, - passwordController.text, - ), - ); - }); - } - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.black87, - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric( - vertical: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), + setState(() { + context.read().add( + signUp.SignUpRequired( + myUser, + passwordController.text, + ), + ); + }); + } + }, + style: TextButton.styleFrom( + backgroundColor: + Theme.of(context).colorScheme.primary, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(60), + ), + ), + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: 25, vertical: 5), + child: const Text( + 'Sign Up', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600), + ), ), - ), - child: const Text( - 'Daftar', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600), ), ), ) @@ -225,39 +243,7 @@ class _SignUpScreenState extends State { Center( child: Text('Atau'), ), - const SizedBox(height: 12), - SizedBox( - width: MediaQuery.of(context).size.width * 0.92, - child: TextButton.icon( - onPressed: () { - context - .read() - .add(GoogleSignInRequired()); - }, - icon: SizedBox( - height: 20, - width: 20, - child: Image.asset( - 'images/google-icon-logo.png', - fit: BoxFit.contain, - ), - ), - label: const Text( - 'Sign In With Google', - style: TextStyle( - color: Colors.black, - fontSize: 16, - fontWeight: FontWeight.w600), - ), - style: TextButton.styleFrom( - backgroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: const BorderSide(color: Colors.grey)), - padding: const EdgeInsets.symmetric(vertical: 16), - ), - ), - ), + const SizedBox(height: 12), Center( child: Row( @@ -266,9 +252,12 @@ class _SignUpScreenState extends State { const Text('Sudah punya akun? '), TextButton( onPressed: () { - Navigator.of(context).pop(); + widget.onSignInTap?.call(); }, - child: const Text('Login di sini'), + child: const Text( + 'Login di sini', + style: TextStyle(fontWeight: FontWeight.bold), + ), ) ], ), diff --git a/lib/screens/auth/views/welcome_screen.dart b/lib/screens/auth/views/welcome_screen.dart index 4ec3d63..2a5444c 100644 --- a/lib/screens/auth/views/welcome_screen.dart +++ b/lib/screens/auth/views/welcome_screen.dart @@ -13,90 +13,92 @@ class WelcomeScreen extends StatefulWidget { State createState() => _WelcomeScreenState(); } -class _WelcomeScreenState extends State with TickerProviderStateMixin { - late TabController tabController; +class _WelcomeScreenState extends State + with TickerProviderStateMixin { + late TabController tabController; - @override + @override void initState() { - tabController = TabController( - initialIndex: 0, - length: 2, - vsync: this - ); + tabController = TabController(initialIndex: 0, length: 2, vsync: this); super.initState(); } - @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - body: SingleChildScrollView( - child: SizedBox( - height: MediaQuery.of(context).size.height, - child: Stack( - children: [ - Align( - alignment: Alignment.center, - child: SizedBox( - height: MediaQuery.of(context).size.height / 1.8, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 50.0), - child: TabBar( - controller: tabController, - unselectedLabelColor: Theme.of(context).colorScheme.onBackground.withOpacity(0.5), - labelColor: Theme.of(context).colorScheme.onBackground, - tabs: const [ - Padding( - padding: EdgeInsets.all(12.0), - child: Text( - 'Sign In', - style: TextStyle( - fontSize: 18, - ), - ), - ), - Padding( - padding: EdgeInsets.all(12.0), - child: Text( - 'Sign Up', - style: TextStyle( - fontSize: 18, - ), - ), - ), - ], - ), - ), - Expanded( - child: TabBarView( - controller: tabController, - children: [ - BlocProvider( - create: (context) => SignInBloc( - context.read().userRepository - ), - child: const SignInScreen(), - ), - BlocProvider( - create: (context) => SignUpBloc( - context.read().userRepository - ), - child: const SignUpScreen(), - ), - ], - ) - ) - ], - ), - ), - ) - ], - ), - ), - ), - ); + return Scaffold( + backgroundColor: Colors.white, + body: SingleChildScrollView( + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Stack( + children: [ + Align( + alignment: Alignment.center, + child: SizedBox( + height: MediaQuery.of(context).size.height / 1.8, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 50.0), + child: TabBar( + controller: tabController, + unselectedLabelColor: Theme.of(context) + .colorScheme + .onBackground + .withOpacity(0.5), + labelColor: + Theme.of(context).colorScheme.onBackground, + tabs: const [ + Padding( + padding: EdgeInsets.all(12.0), + child: Text( + 'Sign In', + style: TextStyle( + fontSize: 18, + ), + ), + ), + Padding( + padding: EdgeInsets.all(12.0), + child: Text( + 'Sign Up', + style: TextStyle( + fontSize: 18, + ), + ), + ), + ], + ), + ), + Expanded( + child: TabBarView( + controller: tabController, + children: [ + BlocProvider( + create: (context) => SignInBloc(context + .read() + .userRepository), + child: const SignInScreen(), + ), + BlocProvider( + create: (context) => SignUpBloc(context + .read() + .userRepository), + child: SignUpScreen(onSignInTap: () { + tabController.animateTo( + 0); // Ini yang bikin dia pindah ke tab Login + }), + ), + ], + )) + ], + ), + ), + ) + ], + ), + ), + ), + ); } -} \ No newline at end of file +} diff --git a/lib/screens/home/views/main_drawer.dart b/lib/screens/home/views/main_drawer.dart index 4f50ed7..cc90626 100644 --- a/lib/screens/home/views/main_drawer.dart +++ b/lib/screens/home/views/main_drawer.dart @@ -35,7 +35,11 @@ class MainDrawer extends StatelessWidget { // Daftar Menu ListTile( - leading: const Icon(Icons.speed), + leading: Image.asset( + 'images/windy.png', + height: 20, + width: 20, + ), title: const Text("Wind Speed"), onTap: () { // Navigasi ke Wind Speed @@ -52,7 +56,7 @@ class MainDrawer extends StatelessWidget { height: 20, width: 20, ), - title: const Text("Udara"), + title: const Text("Tekanan Udara"), onTap: () {}, ), const Spacer(), // Dorong menu logout ke paling bawah diff --git a/lib/screens/monitoring/evaporasi/blocs/evaporasi_bloc.dart b/lib/screens/monitoring/evaporasi/blocs/evaporasi_bloc.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/screens/monitoring/evaporasi/blocs/evaporasi_event.dart b/lib/screens/monitoring/evaporasi/blocs/evaporasi_event.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/screens/monitoring/evaporasi/blocs/evaporasi_state.dart b/lib/screens/monitoring/evaporasi/blocs/evaporasi_state.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/screens/monitoring/evaporasi_monitoring_screen.dart b/lib/screens/monitoring/evaporasi/views/evaporasi.dart similarity index 99% rename from lib/screens/monitoring/evaporasi_monitoring_screen.dart rename to lib/screens/monitoring/evaporasi/views/evaporasi.dart index 3e67031..f31a02c 100644 --- a/lib/screens/monitoring/evaporasi_monitoring_screen.dart +++ b/lib/screens/monitoring/evaporasi/views/evaporasi.dart @@ -3,7 +3,7 @@ import 'package:fl_chart/fl_chart.dart'; import 'package:firebase_database/firebase_database.dart'; import 'dart:async'; import 'package:intl/intl.dart'; -import 'shared/widgets/monitoring_shared.dart'; +import '../../shared/widgets/monitoring_shared.dart'; /// EVAPORASI MONITORING SCREEN class EvaporasiMonitoringScreen extends StatefulWidget { diff --git a/lib/screens/monitoring/wind_speed/blocs/wind_speed_bloc.dart b/lib/screens/monitoring/wind_speed/blocs/wind_speed_bloc.dart index e5b929f..1ce90e6 100644 --- a/lib/screens/monitoring/wind_speed/blocs/wind_speed_bloc.dart +++ b/lib/screens/monitoring/wind_speed/blocs/wind_speed_bloc.dart @@ -2,34 +2,44 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:monitoring_repository/monitoring_repository.dart'; - +import 'package:bloc_concurrency/bloc_concurrency.dart'; part 'wind_speed_event.dart'; part 'wind_speed_state.dart'; class WindSpeedBloc extends Bloc { final MonitoringRepository _repository; - StreamSubscription? _subscription; WindSpeedBloc({required MonitoringRepository repository}) : _repository = repository, super(const WindSpeedState()) { // Handler saat aplikasi minta mulai monitoring - on((event, emit) { - _subscription?.cancel(); - _subscription = _repository - .getSensorStream( - 'anemometer/realtime', (json) => MyWindSpeed.fromJson(json)) - .listen((data) => add(_WindSpeedUpdated(data))); - }); + on( + (event, emit) async { + emit(state.copyWith(isLoading: true)); - // Handler saat ada data baru masuk (Pindahan logika dari Screen) - on<_WindSpeedUpdated>((event, emit) { - // Di sini kamu bisa tambahkan logika hitung rata-rata/grafik harian - emit(state.copyWith( - currentSpeed: event.data.speed, - isLoading: false, - )); - }); + await emit.forEach( + _repository.getSensorStream( + 'anemometer/realtime', (json) => MyWindSpeed.fromJson(json)), + onData: (data) { + // Mengambil list lama dan menambah data baru untuk grafik + final updatedSpeeds = List.from(state.dailySpeeds) + ..add(data.speed); + // Batasi jumlah data di grafik (misal cuma simpan 20 data terakhir agar tidak berat) + if (updatedSpeeds.length > 20) { + updatedSpeeds.removeAt(0); + } + + return state.copyWith( + currentSpeed: data.speed, + dailySpeeds: updatedSpeeds, // Update list grafik + isLoading: false, + ); + }, + onError: (error, stackTrace) => state.copyWith(isLoading: false), + ); // emit forEach + }, + transformer: restartable(), + ); on((event, emit) { emit(state.copyWith(selectedPeriod: event.period)); @@ -38,7 +48,6 @@ class WindSpeedBloc extends Bloc { @override Future close() { - _subscription?.cancel(); // Supaya tidak bocor memorinya return super.close(); } } diff --git a/lib/screens/monitoring/wind_speed/views/wind_speed.dart b/lib/screens/monitoring/wind_speed/views/wind_speed.dart deleted file mode 100644 index 8b13789..0000000 --- a/lib/screens/monitoring/wind_speed/views/wind_speed.dart +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/screens/monitoring/wind_speed/views/wind_speed_screen.dart b/lib/screens/monitoring/wind_speed/views/wind_speed_screen.dart new file mode 100644 index 0000000..930d4d8 --- /dev/null +++ b/lib/screens/monitoring/wind_speed/views/wind_speed_screen.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class WindSpeedScreen extends StatelessWidget { + const WindSpeedScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold(); + } +} diff --git a/packages/module_repository/pubspec.lock b/packages/module_repository/pubspec.lock deleted file mode 100644 index 58d28ea..0000000 --- a/packages/module_repository/pubspec.lock +++ /dev/null @@ -1,205 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" - source: hosted - version: "15.0.2" -sdks: - dart: ">=3.8.0-0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" diff --git a/packages/module_repository/pubspec.yaml b/packages/module_repository/pubspec.yaml deleted file mode 100644 index 66996a7..0000000 --- a/packages/module_repository/pubspec.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: module_repository -description: The Repo that handles modules -publish_to: 'none' -version: 0.0.1 - -environment: - sdk: '>=3.1.0 <4.0.0' - -dependencies: - flutter: - sdk: flutter - - # equatable: ^2.0.5 - # firebase_auth: ^4.16.0 - # cloud_firestore: ^4.9.2 - # firebase_storage: ^11.6.0 - # rxdart: ^0.27.7 - # path: ^1.8.3 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^2.0.0 - -flutter: - uses-material-design: true \ No newline at end of file diff --git a/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart b/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart index b5da549..5d19c33 100644 --- a/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart +++ b/packages/monitoring_repository/lib/src/firebase_monitoring_repo.dart @@ -17,11 +17,14 @@ class FirebaseMonitoringRepo implements MonitoringRepository { ) { /// === ambil data mentah dari firebase === /// return _db.ref(path).onValue.map((event) { - /// == ambil value-nya dan pastikan tipenya map == /// - final data = event.snapshot.value as Map? ?? {}; + final Object? value = event.snapshot.value; - /// == masukan ke dalam "pabrik" (mapper) agar jadi objek == /// - return mapper(data); + if (value is Map) { + return mapper(value); + } else { + // Jika data kosong atau bukan Map, berikan Map kosong agar mapper tidak crash + return mapper({}); + } }); } diff --git a/packages/user_repository/lib/src/firebase_user_repo.dart b/packages/user_repository/lib/src/firebase_user_repo.dart index b1b428f..62890c7 100644 --- a/packages/user_repository/lib/src/firebase_user_repo.dart +++ b/packages/user_repository/lib/src/firebase_user_repo.dart @@ -12,6 +12,7 @@ class FirebaseUserRepo implements UserRepository { FirebaseAuth? firebaseAuth, }) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance; + /// == Melakukan Implement User == /// @override Stream get user { return _firebaseAuth.authStateChanges().flatMap((firebaseUser) async* { @@ -42,6 +43,7 @@ class FirebaseUserRepo implements UserRepository { }); } + /// == Melakukan Implement Sign in == /// @override Future signIn(String email, String password) async { try { @@ -53,6 +55,7 @@ class FirebaseUserRepo implements UserRepository { } } + /// == Melakukan Implement Sign Up == /// @override Future signUp(MyUser myUser, String password) async { try { @@ -66,6 +69,7 @@ class FirebaseUserRepo implements UserRepository { } } + /// == Melakukan Implement Log Out == /// @override Future logOut() async { await _firebaseAuth.signOut(); @@ -85,6 +89,7 @@ class FirebaseUserRepo implements UserRepository { } } + /// == Sign in with Google == /// @override Future signInWithGoogle() async { try { diff --git a/pubspec.lock b/pubspec.lock index a88d640..99e4d46 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -33,6 +33,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.4" + bloc_concurrency: + dependency: "direct main" + description: + name: bloc_concurrency + sha256: "456b7a3616a7c1ceb975c14441b3f198bf57d81cb95b7c6de5cb0c60201afcd8" + url: "https://pub.dev" + source: hosted + version: "0.2.5" boolean_selector: dependency: transitive description: @@ -596,6 +604,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" string_scanner: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 15b45a0..378b697 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,6 +6,7 @@ environment: sdk: ^3.1.0 dependencies: bloc: ^8.1.0 + bloc_concurrency: ^0.2.5 cloud_firestore: ^6.1.1 cupertino_icons: ^1.0.8 equatable: ^2.0.5 @@ -19,11 +20,11 @@ dependencies: google_fonts: ^8.0.2 google_sign_in: ^7.2.0 intl: ^0.20.2 + monitoring_repository: + path: packages/monitoring_repository rxdart: ^0.27.7 user_repository: path: packages/user_repository - monitoring_repository: - path: packages/monitoring_repository dev_dependencies: flutter_lints: ^3.0.0 diff --git a/web/index.html b/web/index.html index 6438574..bc4b833 100644 --- a/web/index.html +++ b/web/index.html @@ -1,7 +1,7 @@ - + - - - + - - - + + + - - - - - + + + + + - - + + - klimatologiot - - - - - + klimatologiot + + + + + + + +