woowww josssjissss

This commit is contained in:
kleponijo 2026-04-14 14:00:25 +07:00
parent 1239b39e30
commit adaeff826f
21 changed files with 256 additions and 451 deletions

BIN
images/windy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -24,6 +24,7 @@ class SignInBloc extends Bloc<SignInEvent, SignInState> {
await _userRepository.signInWithGoogle(); await _userRepository.signInWithGoogle();
} catch (e) { } catch (e) {
emit(SignInFailure()); emit(SignInFailure());
emit(SignInInitial());
} }
}); });

View File

@ -20,15 +20,5 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
emit(SignUpFailure(e.toString())); emit(SignUpFailure(e.toString()));
} }
}); });
on<GoogleSignInRequired>((event, emit) async {
emit(SignUpProcess());
try {
await _userRepository.signInWithGoogle();
emit(SignUpSuccess());
} catch (e) {
emit(SignUpFailure(e.toString()));
}
});
} }
} }

View File

@ -25,19 +25,20 @@ class _SignInScreenState extends State<SignInScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocListener<SignInBloc, SignInState>( return BlocListener<SignInBloc, SignInState>(
listener: (context, state) { listener: (context, state) {
if (state is SignInSuccess) { if (state is SignInProcess) {
setState(() {
signInRequired = false;
});
} else if (state is SignInProcess) {
setState(() { setState(() {
signInRequired = true; signInRequired = true;
}); });
} else if (state is SignInFailure) { } else {
setState(() { setState(() {
signInRequired = false; 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( child: Form(

View File

@ -3,10 +3,13 @@ import 'package:user_repository/user_repository.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../components/my_text_field.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 { class SignUpScreen extends StatefulWidget {
const SignUpScreen({super.key}); final VoidCallback? onSignInTap;
const SignUpScreen({super.key, this.onSignInTap});
@override @override
State<SignUpScreen> createState() => _SignUpScreenState(); State<SignUpScreen> createState() => _SignUpScreenState();
@ -30,18 +33,26 @@ class _SignUpScreenState extends State<SignUpScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocListener<SignUpBloc, SignUpState>( return BlocListener<signUp.SignUpBloc, signUp.SignUpState>(
listener: (context, state) { listener: (context, state) {
if (state is SignUpSuccess) { if (state is signUp.SignUpProcess) {
setState(() {
signUpRequired = false;
});
} else if (state is SignUpProcess) {
setState(() { setState(() {
signUpRequired = true; signUpRequired = true;
}); });
} else if (state is SignUpFailure) { } else if (state is signUp.SignUpFailure) {
return; 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( child: Form(
@ -181,41 +192,48 @@ class _SignUpScreenState extends State<SignUpScreen> {
const SizedBox(height: 18), const SizedBox(height: 18),
/// == Sign Up == ///
// Button // Button
!signUpRequired !signUpRequired
? SizedBox( ? Center(
width: MediaQuery.of(context).size.width * 0.92, child: SizedBox(
child: ElevatedButton( width:
onPressed: () { MediaQuery.of(context).size.width * 0.5,
if (_formKey.currentState!.validate()) { child: ElevatedButton(
MyUser myUser = MyUser.empty; onPressed: () {
myUser.email = emailController.text; if (_formKey.currentState!.validate()) {
myUser.name = nameController.text; MyUser myUser = MyUser.empty;
myUser.email = emailController.text;
myUser.name = nameController.text;
setState(() { setState(() {
context.read<SignUpBloc>().add( context.read<signUp.SignUpBloc>().add(
SignUpRequired( signUp.SignUpRequired(
myUser, myUser,
passwordController.text, passwordController.text,
), ),
); );
}); });
} }
}, },
style: ElevatedButton.styleFrom( style: TextButton.styleFrom(
backgroundColor: Colors.black87, backgroundColor:
foregroundColor: Colors.white, Theme.of(context).colorScheme.primary,
padding: const EdgeInsets.symmetric( foregroundColor: Colors.white,
vertical: 16), shape: RoundedRectangleBorder(
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(60),
borderRadius: BorderRadius.circular(8), ),
),
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<SignUpScreen> {
Center( Center(
child: Text('Atau'), child: Text('Atau'),
), ),
const SizedBox(height: 12),
SizedBox(
width: MediaQuery.of(context).size.width * 0.92,
child: TextButton.icon(
onPressed: () {
context
.read<SignUpBloc>()
.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), const SizedBox(height: 12),
Center( Center(
child: Row( child: Row(
@ -266,9 +252,12 @@ class _SignUpScreenState extends State<SignUpScreen> {
const Text('Sudah punya akun? '), const Text('Sudah punya akun? '),
TextButton( TextButton(
onPressed: () { 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),
),
) )
], ],
), ),

View File

@ -13,90 +13,92 @@ class WelcomeScreen extends StatefulWidget {
State<WelcomeScreen> createState() => _WelcomeScreenState(); State<WelcomeScreen> createState() => _WelcomeScreenState();
} }
class _WelcomeScreenState extends State<WelcomeScreen> with TickerProviderStateMixin { class _WelcomeScreenState extends State<WelcomeScreen>
late TabController tabController; with TickerProviderStateMixin {
late TabController tabController;
@override @override
void initState() { void initState() {
tabController = TabController( tabController = TabController(initialIndex: 0, length: 2, vsync: this);
initialIndex: 0,
length: 2,
vsync: this
);
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: SingleChildScrollView( body: SingleChildScrollView(
child: SizedBox( child: SizedBox(
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
child: Stack( child: Stack(
children: [ children: [
Align( Align(
alignment: Alignment.center, alignment: Alignment.center,
child: SizedBox( child: SizedBox(
height: MediaQuery.of(context).size.height / 1.8, height: MediaQuery.of(context).size.height / 1.8,
child: Column( child: Column(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 50.0), padding: const EdgeInsets.symmetric(horizontal: 50.0),
child: TabBar( child: TabBar(
controller: tabController, controller: tabController,
unselectedLabelColor: Theme.of(context).colorScheme.onBackground.withOpacity(0.5), unselectedLabelColor: Theme.of(context)
labelColor: Theme.of(context).colorScheme.onBackground, .colorScheme
tabs: const [ .onBackground
Padding( .withOpacity(0.5),
padding: EdgeInsets.all(12.0), labelColor:
child: Text( Theme.of(context).colorScheme.onBackground,
'Sign In', tabs: const [
style: TextStyle( Padding(
fontSize: 18, padding: EdgeInsets.all(12.0),
), child: Text(
), 'Sign In',
), style: TextStyle(
Padding( fontSize: 18,
padding: EdgeInsets.all(12.0), ),
child: Text( ),
'Sign Up', ),
style: TextStyle( Padding(
fontSize: 18, padding: EdgeInsets.all(12.0),
), child: Text(
), 'Sign Up',
), style: TextStyle(
], fontSize: 18,
), ),
), ),
Expanded( ),
child: TabBarView( ],
controller: tabController, ),
children: [ ),
BlocProvider<SignInBloc>( Expanded(
create: (context) => SignInBloc( child: TabBarView(
context.read<AuthenticationBloc>().userRepository controller: tabController,
), children: [
child: const SignInScreen(), BlocProvider<SignInBloc>(
), create: (context) => SignInBloc(context
BlocProvider<SignUpBloc>( .read<AuthenticationBloc>()
create: (context) => SignUpBloc( .userRepository),
context.read<AuthenticationBloc>().userRepository child: const SignInScreen(),
), ),
child: const SignUpScreen(), BlocProvider<SignUpBloc>(
), create: (context) => SignUpBloc(context
], .read<AuthenticationBloc>()
) .userRepository),
) child: SignUpScreen(onSignInTap: () {
], tabController.animateTo(
), 0); // Ini yang bikin dia pindah ke tab Login
), }),
) ),
], ],
), ))
), ],
), ),
); ),
)
],
),
),
),
);
} }
} }

View File

@ -35,7 +35,11 @@ class MainDrawer extends StatelessWidget {
// Daftar Menu // Daftar Menu
ListTile( ListTile(
leading: const Icon(Icons.speed), leading: Image.asset(
'images/windy.png',
height: 20,
width: 20,
),
title: const Text("Wind Speed"), title: const Text("Wind Speed"),
onTap: () { onTap: () {
// Navigasi ke Wind Speed // Navigasi ke Wind Speed
@ -52,7 +56,7 @@ class MainDrawer extends StatelessWidget {
height: 20, height: 20,
width: 20, width: 20,
), ),
title: const Text("Udara"), title: const Text("Tekanan Udara"),
onTap: () {}, onTap: () {},
), ),
const Spacer(), // Dorong menu logout ke paling bawah const Spacer(), // Dorong menu logout ke paling bawah

View File

@ -3,7 +3,7 @@ import 'package:fl_chart/fl_chart.dart';
import 'package:firebase_database/firebase_database.dart'; import 'package:firebase_database/firebase_database.dart';
import 'dart:async'; import 'dart:async';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'shared/widgets/monitoring_shared.dart'; import '../../shared/widgets/monitoring_shared.dart';
/// EVAPORASI MONITORING SCREEN /// EVAPORASI MONITORING SCREEN
class EvaporasiMonitoringScreen extends StatefulWidget { class EvaporasiMonitoringScreen extends StatefulWidget {

View File

@ -2,34 +2,44 @@ import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:monitoring_repository/monitoring_repository.dart'; import 'package:monitoring_repository/monitoring_repository.dart';
import 'package:bloc_concurrency/bloc_concurrency.dart';
part 'wind_speed_event.dart'; part 'wind_speed_event.dart';
part 'wind_speed_state.dart'; part 'wind_speed_state.dart';
class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> { class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
final MonitoringRepository _repository; final MonitoringRepository _repository;
StreamSubscription? _subscription;
WindSpeedBloc({required MonitoringRepository repository}) WindSpeedBloc({required MonitoringRepository repository})
: _repository = repository, : _repository = repository,
super(const WindSpeedState()) { super(const WindSpeedState()) {
// Handler saat aplikasi minta mulai monitoring // Handler saat aplikasi minta mulai monitoring
on<WatchWindSpeedStarted>((event, emit) { on<WatchWindSpeedStarted>(
_subscription?.cancel(); (event, emit) async {
_subscription = _repository emit(state.copyWith(isLoading: true));
.getSensorStream(
'anemometer/realtime', (json) => MyWindSpeed.fromJson(json))
.listen((data) => add(_WindSpeedUpdated(data)));
});
// Handler saat ada data baru masuk (Pindahan logika dari Screen) await emit.forEach<MyWindSpeed>(
on<_WindSpeedUpdated>((event, emit) { _repository.getSensorStream(
// Di sini kamu bisa tambahkan logika hitung rata-rata/grafik harian 'anemometer/realtime', (json) => MyWindSpeed.fromJson(json)),
emit(state.copyWith( onData: (data) {
currentSpeed: event.data.speed, // Mengambil list lama dan menambah data baru untuk grafik
isLoading: false, final updatedSpeeds = List<double>.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<WindSpeedPeriodChanged>((event, emit) { on<WindSpeedPeriodChanged>((event, emit) {
emit(state.copyWith(selectedPeriod: event.period)); emit(state.copyWith(selectedPeriod: event.period));
@ -38,7 +48,6 @@ class WindSpeedBloc extends Bloc<WindSpeedEvent, WindSpeedState> {
@override @override
Future<void> close() { Future<void> close() {
_subscription?.cancel(); // Supaya tidak bocor memorinya
return super.close(); return super.close();
} }
} }

View File

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class WindSpeedScreen extends StatelessWidget {
const WindSpeedScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold();
}
}

View File

@ -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"

View File

@ -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

View File

@ -17,11 +17,14 @@ class FirebaseMonitoringRepo implements MonitoringRepository {
) { ) {
/// === ambil data mentah dari firebase === /// /// === ambil data mentah dari firebase === ///
return _db.ref(path).onValue.map((event) { return _db.ref(path).onValue.map((event) {
/// == ambil value-nya dan pastikan tipenya map == /// final Object? value = event.snapshot.value;
final data = event.snapshot.value as Map<dynamic, dynamic>? ?? {};
/// == masukan ke dalam "pabrik" (mapper) agar jadi objek == /// if (value is Map) {
return mapper(data); return mapper(value);
} else {
// Jika data kosong atau bukan Map, berikan Map kosong agar mapper tidak crash
return mapper({});
}
}); });
} }

View File

@ -12,6 +12,7 @@ class FirebaseUserRepo implements UserRepository {
FirebaseAuth? firebaseAuth, FirebaseAuth? firebaseAuth,
}) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance; }) : _firebaseAuth = firebaseAuth ?? FirebaseAuth.instance;
/// == Melakukan Implement User == ///
@override @override
Stream<MyUser?> get user { Stream<MyUser?> get user {
return _firebaseAuth.authStateChanges().flatMap((firebaseUser) async* { return _firebaseAuth.authStateChanges().flatMap((firebaseUser) async* {
@ -42,6 +43,7 @@ class FirebaseUserRepo implements UserRepository {
}); });
} }
/// == Melakukan Implement Sign in == ///
@override @override
Future<void> signIn(String email, String password) async { Future<void> signIn(String email, String password) async {
try { try {
@ -53,6 +55,7 @@ class FirebaseUserRepo implements UserRepository {
} }
} }
/// == Melakukan Implement Sign Up == ///
@override @override
Future<MyUser> signUp(MyUser myUser, String password) async { Future<MyUser> signUp(MyUser myUser, String password) async {
try { try {
@ -66,6 +69,7 @@ class FirebaseUserRepo implements UserRepository {
} }
} }
/// == Melakukan Implement Log Out == ///
@override @override
Future<void> logOut() async { Future<void> logOut() async {
await _firebaseAuth.signOut(); await _firebaseAuth.signOut();
@ -85,6 +89,7 @@ class FirebaseUserRepo implements UserRepository {
} }
} }
/// == Sign in with Google == ///
@override @override
Future<void> signInWithGoogle() async { Future<void> signInWithGoogle() async {
try { try {

View File

@ -33,6 +33,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.1.4" 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: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -596,6 +604,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" 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: string_scanner:
dependency: transitive dependency: transitive
description: description:

View File

@ -6,6 +6,7 @@ environment:
sdk: ^3.1.0 sdk: ^3.1.0
dependencies: dependencies:
bloc: ^8.1.0 bloc: ^8.1.0
bloc_concurrency: ^0.2.5
cloud_firestore: ^6.1.1 cloud_firestore: ^6.1.1
cupertino_icons: ^1.0.8 cupertino_icons: ^1.0.8
equatable: ^2.0.5 equatable: ^2.0.5
@ -19,11 +20,11 @@ dependencies:
google_fonts: ^8.0.2 google_fonts: ^8.0.2
google_sign_in: ^7.2.0 google_sign_in: ^7.2.0
intl: ^0.20.2 intl: ^0.20.2
monitoring_repository:
path: packages/monitoring_repository
rxdart: ^0.27.7 rxdart: ^0.27.7
user_repository: user_repository:
path: packages/user_repository path: packages/user_repository
monitoring_repository:
path: packages/monitoring_repository
dev_dependencies: dev_dependencies:
flutter_lints: ^3.0.0 flutter_lints: ^3.0.0

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<!-- <!--
If you are serving your web app in a path other than the root, change the If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from. href value below to reflect the base path you are serving from.
@ -14,25 +14,31 @@
This is a placeholder for base href that will be replaced by the value of This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`. the `--base-href` argument provided to `flutter build`.
--> -->
<base href="$FLUTTER_BASE_HREF"> <base href="$FLUTTER_BASE_HREF" />
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta content="IE=Edge" http-equiv="X-UA-Compatible" />
<meta name="description" content="A new Flutter project."> <meta name="description" content="A new Flutter project." />
<!-- iOS meta tags & icons --> <!-- iOS meta tags & icons -->
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="klimatologiot"> <meta name="apple-mobile-web-app-title" content="klimatologiot" />
<link rel="apple-touch-icon" href="icons/Icon-192.png"> <link rel="apple-touch-icon" href="icons/Icon-192.png" />
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/> <link rel="icon" type="image/png" href="favicon.png" />
<title>klimatologiot</title> <title>klimatologiot</title>
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json" />
</head>
<body> <!-- Google -->
<script src="flutter_bootstrap.js" async></script> <meta
</body> name="google-signin-client_id"
content="219079385989-8hkp1kg2pprs5k269s4c08r6rpdj1gjd.apps.googleusercontent.com"
/>
</head>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
</html> </html>