-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
introduce bloc for profile contact state management
- Loading branch information
Showing
11 changed files
with
413 additions
and
225 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
extensions: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,74 @@ | ||
import 'package:animated_theme_switcher/animated_theme_switcher.dart'; | ||
import 'package:flutter/foundation.dart'; | ||
// Copyright 2024 Lukas Grossberger | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_localizations/flutter_localizations.dart'; | ||
import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
import 'package:flutter_translate/flutter_translate.dart'; | ||
import 'package:form_builder_validators/form_builder_validators.dart'; | ||
import 'package:hydrated_bloc/hydrated_bloc.dart'; | ||
import 'package:path_provider/path_provider.dart'; | ||
|
||
import 'router/router.dart'; | ||
import 'tick.dart'; | ||
import 'contact_list.dart'; | ||
import 'contact_page.dart'; | ||
import 'map.dart'; | ||
import 'profile.dart'; | ||
import 'updates.dart'; | ||
|
||
class VeilidChatApp extends ConsumerWidget { | ||
const VeilidChatApp({ | ||
required this.theme, | ||
super.key, | ||
}); | ||
|
||
final ThemeData theme; | ||
class CoagulateApp extends StatelessWidget { | ||
@override | ||
Widget build(BuildContext context) => MaterialApp( | ||
title: 'Coagulate', | ||
theme: ThemeData( | ||
primarySwatch: Colors.blue, | ||
), | ||
home: CoagulateAppView(), | ||
// https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments | ||
routes: { | ||
ContactPage.routeName: (context) => const ContactPage(), | ||
}, | ||
); | ||
} | ||
|
||
class CoagulateAppView extends StatefulWidget { | ||
@override | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
final router = ref.watch(routerProvider); | ||
final localizationDelegate = LocalizedApp.of(context).delegate; | ||
_CoagulateAppViewState createState() => _CoagulateAppViewState(); | ||
} | ||
|
||
class _CoagulateAppViewState extends State<CoagulateAppView> { | ||
int _selectedIndex = 0; | ||
|
||
return ThemeProvider( | ||
initTheme: theme, | ||
builder: (_, theme) => LocalizationProvider( | ||
state: LocalizationProvider.of(context).state, | ||
child: BackgroundTicker( | ||
builder: (context) => MaterialApp.router( | ||
debugShowCheckedModeBanner: false, | ||
routerConfig: router, | ||
title: translate('app.title'), | ||
theme: theme, | ||
localizationsDelegates: [ | ||
GlobalMaterialLocalizations.delegate, | ||
GlobalWidgetsLocalizations.delegate, | ||
FormBuilderLocalizations.delegate, | ||
localizationDelegate | ||
], | ||
supportedLocales: localizationDelegate.supportedLocales, | ||
locale: localizationDelegate.currentLocale, | ||
)), | ||
)); | ||
void _onItemTapped(int index) { | ||
setState(() { | ||
_selectedIndex = index; | ||
}); | ||
} | ||
|
||
@override | ||
void debugFillProperties(DiagnosticPropertiesBuilder properties) { | ||
super.debugFillProperties(properties); | ||
properties.add(DiagnosticsProperty<ThemeData>('theme', theme)); | ||
} | ||
Widget build(BuildContext context) => Scaffold( | ||
body: [ | ||
ProfilePage(), | ||
UpdatesPage(), | ||
ContactListPage(), | ||
MapPage(), | ||
].elementAt(_selectedIndex), | ||
bottomNavigationBar: BottomNavigationBar( | ||
items: const [ | ||
BottomNavigationBarItem( | ||
icon: Icon(Icons.person), | ||
label: 'Profile', | ||
), | ||
BottomNavigationBarItem( | ||
icon: Icon(Icons.update), | ||
label: 'Updates', | ||
), | ||
BottomNavigationBarItem( | ||
icon: Icon(Icons.contacts), | ||
label: 'Contacts', | ||
), | ||
BottomNavigationBarItem( | ||
icon: Icon(Icons.map), | ||
label: 'Map', | ||
), | ||
], | ||
currentIndex: _selectedIndex, | ||
unselectedItemColor: Colors.black, | ||
selectedItemColor: Colors.deepPurpleAccent, | ||
onTap: _onItemTapped, | ||
), | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import 'package:equatable/equatable.dart'; | ||
import 'package:hydrated_bloc/hydrated_bloc.dart'; | ||
import 'package:json_annotation/json_annotation.dart'; | ||
import 'package:flutter_contacts/flutter_contacts.dart'; | ||
|
||
part 'profile_contact_cubit.g.dart'; | ||
part 'profile_contact_state.dart'; | ||
|
||
// TODO: Add contact refresh as listener via | ||
// FlutterContacts.addListener(() => print('Contact DB changed')); | ||
|
||
class ProfileContactCubit extends HydratedCubit<ProfileContactState> { | ||
ProfileContactCubit() : super(ProfileContactState()); | ||
|
||
// TODO: Separate the emits out? | ||
Future<void> updateContact() async { | ||
print('emitting loading'); | ||
emit(state.copyWith(status: ProfileContactStatus.loading)); | ||
|
||
if (state.profileContact == null) { | ||
print('emitting unavailable'); | ||
emit(state.copyWith(status: ProfileContactStatus.unavailable)); | ||
return; | ||
} | ||
|
||
print('emitting success'); | ||
emit(state.copyWith( | ||
status: ProfileContactStatus.success, | ||
profileContact: | ||
await FlutterContacts.getContact(state.profileContact!.id))); | ||
} | ||
|
||
void setContact(Contact? contact) { | ||
emit(state.copyWith( | ||
status: (contact == null) | ||
? ProfileContactStatus.unavailable | ||
: ProfileContactStatus.success, | ||
profileContact: contact)); | ||
} | ||
|
||
@override | ||
ProfileContactState fromJson(Map<String, dynamic> json) => | ||
ProfileContactState.fromJson(json); | ||
|
||
@override | ||
Map<String, dynamic> toJson(ProfileContactState state) => state.toJson(); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
part of 'profile_contact_cubit.dart'; | ||
|
||
enum ProfileContactStatus { initial, loading, success, unavailable } | ||
|
||
extension ProfileContactStatusX on ProfileContactStatus { | ||
bool get isInitial => this == ProfileContactStatus.initial; | ||
bool get isLoading => this == ProfileContactStatus.loading; | ||
bool get isSuccess => this == ProfileContactStatus.success; | ||
bool get isUnavailable => this == ProfileContactStatus.unavailable; | ||
} | ||
|
||
@JsonSerializable() | ||
final class ProfileContactState extends Equatable { | ||
ProfileContactState({ | ||
this.status = ProfileContactStatus.initial, | ||
this.profileContact, | ||
}); | ||
|
||
factory ProfileContactState.fromJson(Map<String, dynamic> json) => | ||
_$ProfileContactStateFromJson(json); | ||
|
||
final ProfileContactStatus status; | ||
final Contact? profileContact; | ||
|
||
ProfileContactState copyWith( | ||
{ProfileContactStatus? status, Contact? profileContact}) => | ||
ProfileContactState( | ||
status: status ?? this.status, | ||
profileContact: profileContact ?? this.profileContact, | ||
); | ||
|
||
Map<String, dynamic> toJson() => _$ProfileContactStateToJson(this); | ||
|
||
@override | ||
List<Object?> get props => [status, profileContact]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,87 +1,15 @@ | ||
// Copyright 2024 Lukas Grossberger | ||
|
||
import 'package:change_case/change_case.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_contacts/flutter_contacts.dart'; | ||
import 'package:shared_preferences/shared_preferences.dart'; | ||
|
||
import 'contact_list.dart'; | ||
import 'contact_page.dart'; | ||
import 'map.dart'; | ||
import 'updates.dart'; | ||
import 'profile.dart'; | ||
|
||
void main() { | ||
runApp(MyApp()); | ||
} | ||
|
||
class MyApp extends StatelessWidget { | ||
@override | ||
Widget build(BuildContext context) => MaterialApp( | ||
title: 'Navigation App', | ||
theme: ThemeData( | ||
primarySwatch: Colors.blue, | ||
), | ||
home: MyHomePage(), | ||
// https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments | ||
routes: { | ||
ContactPage.routeName: (context) => ContactPage(), | ||
}, | ||
); | ||
} | ||
|
||
class MyHomePage extends StatefulWidget { | ||
@override | ||
_MyHomePageState createState() => _MyHomePageState(); | ||
} | ||
|
||
class _MyHomePageState extends State<MyHomePage> { | ||
int _selectedIndex = 0; | ||
static const _bottomNavigationItems = [ | ||
BottomNavigationBarItem( | ||
icon: Icon(Icons.person), | ||
label: 'Profile', | ||
), | ||
BottomNavigationBarItem( | ||
icon: Icon(Icons.update), | ||
label: 'Updates', | ||
), | ||
BottomNavigationBarItem( | ||
icon: Icon(Icons.contacts), | ||
label: 'Contacts', | ||
), | ||
BottomNavigationBarItem( | ||
icon: Icon(Icons.map), | ||
label: 'Map', | ||
), | ||
]; | ||
|
||
static final List<Widget> _widgetOptions = <Widget>[ | ||
ProfilePage(), | ||
UpdatesPage(), | ||
ContactListPage(), | ||
MapPage(), | ||
]; | ||
|
||
void _onItemTapped(int index) { | ||
setState(() { | ||
_selectedIndex = index; | ||
}); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) => Scaffold( | ||
// appBar: AppBar( | ||
// title: Text(_bottomNavigationItems.elementAt(_selectedIndex).label!), | ||
// ), | ||
body: _widgetOptions.elementAt(_selectedIndex), | ||
// bottomSheet: TabBar(tabs: [Text("Hi")]), | ||
bottomNavigationBar: BottomNavigationBar( | ||
items: _bottomNavigationItems, | ||
currentIndex: _selectedIndex, | ||
unselectedItemColor: Colors.black, | ||
selectedItemColor: Colors.deepPurpleAccent, | ||
onTap: _onItemTapped, | ||
), | ||
); | ||
import 'package:hydrated_bloc/hydrated_bloc.dart'; | ||
import 'package:path_provider/path_provider.dart'; | ||
|
||
import 'app.dart'; | ||
import 'profile_contact_bloc_observer.dart'; | ||
|
||
void main() async { | ||
WidgetsFlutterBinding.ensureInitialized(); | ||
Bloc.observer = const ProfilecontactBlocObserver(); | ||
HydratedBloc.storage = await HydratedStorage.build( | ||
storageDirectory: await getApplicationDocumentsDirectory()); | ||
runApp(CoagulateApp()); | ||
} |
Oops, something went wrong.