Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hlm 2094 fix project sync dialog #159

Merged
merged 10 commits into from
May 9, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,19 @@ class BoundaryBloc extends Bloc<BoundaryEvent, BoundaryState> {
super.initialState, {
required this.boundaryRepository,
}) {
on(_handleReset);
on(_handleSearch);
on(_handleSelect);
on(_handleSubmit);
}

Future<void> _handleReset(
BoundaryResetEvent event,
BoundaryEmitter emit,
) async {
emit(const BoundaryState());
}

FutureOr<void> _handleSearch(
BoundarySearchEvent event,
BoundaryEmitter emit,
Expand Down Expand Up @@ -100,6 +108,8 @@ class BoundaryBloc extends Bloc<BoundaryEvent, BoundaryState> {

@freezed
class BoundaryEvent with _$BoundaryEvent {
const factory BoundaryEvent.reset() = BoundaryResetEvent;

const factory BoundaryEvent.search({required String code}) =
BoundarySearchEvent;

Expand Down
200 changes: 112 additions & 88 deletions apps/health_campaign_field_worker_app/lib/blocs/project/project.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class ProjectBloc extends Bloc<ProjectEvent, ProjectState> {
required this.productVariantLocalRepository,
required this.productVariantRemoteRepository,
}) : localSecureStore = localSecureStore ?? LocalSecureStore.instance,
super(const ProjectsEmptyState()) {
super(const ProjectState()) {
on(_handleProjectInit);
on(_handleProjectSelection);
}
Expand All @@ -99,77 +99,107 @@ class ProjectBloc extends Bloc<ProjectEvent, ProjectState> {
ProjectInitializeEvent event,
ProjectEmitter emit,
) async {
emit(const ProjectLoadingState());
emit(const ProjectState(
loading: true,
projects: [],
selectedProject: null,
));

final connectivityResult = await (Connectivity().checkConnectivity());

switch (connectivityResult) {
case ConnectivityResult.wifi:
case ConnectivityResult.mobile:
final userObject = await localSecureStore.userRequestModel;
final uuid = userObject?.uuid;
AppLogger.instance.info(
'Connectivity Result: $connectivityResult',
title: 'ProjectBloc',
);

List<ProjectStaffModel> projectStaffList =
await projectStaffRemoteRepository.search(
ProjectStaffSearchModel(staffId: uuid),
);
final isOnline = connectivityResult == ConnectivityResult.wifi ||
connectivityResult == ConnectivityResult.mobile;

projectStaffList.removeDuplicates((e) => e.id);

if (projectStaffList.isEmpty) {
emit(const ProjectsEmptyState());
} else {
List<ProjectModel> projects = [];

for (final projectStaff in projectStaffList) {
await projectStaffLocalRepository.create(
projectStaff,
createOpLog: false,
);

final staffProjects = await projectRemoteRepository.search(
ProjectSearchModel(
id: projectStaff.projectId,
tenantId: projectStaff.tenantId,
),
);

projects.addAll(staffProjects);
}

projects.removeDuplicates((e) => e.id);

for (final project in projects) {
await projectLocalRepository.create(
project,
createOpLog: false,
);
}

if (projects.isNotEmpty) {
await _loadProjectFacilities(projects);
await _loadProductVariants(projects);
await _loadServiceDefinition(projects);
}

emit(ProjectSelectionFetchedState(projects: projects));
}
break;
default:
final projects = await projectLocalRepository.search(
ProjectSearchModel(
tenantId: envConfig.variables.tenantId,
),
);
if (isOnline) {
await _loadOnline(emit);
} else {
await _loadOffline(emit);
}
}

final selectedProject = await localSecureStore.selectedProject;
emit(
ProjectSelectionFetchedState(
projects: projects,
selectedProject: selectedProject,
),
);
FutureOr<void> _loadOnline(ProjectEmitter emit) async {
final userObject = await localSecureStore.userRequestModel;
final uuid = userObject?.uuid;

List<ProjectStaffModel> projectStaffList =
await projectStaffRemoteRepository.search(
ProjectStaffSearchModel(staffId: uuid),
);

projectStaffList.removeDuplicates((e) => e.id);

if (projectStaffList.isEmpty) {
emit(const ProjectState(
projects: [],
loading: false,
selectedProject: null,
));

return;
}

List<ProjectModel> projects = [];

for (final projectStaff in projectStaffList) {
await projectStaffLocalRepository.create(
projectStaff,
createOpLog: false,
);

final staffProjects = await projectRemoteRepository.search(
ProjectSearchModel(
id: projectStaff.projectId,
tenantId: projectStaff.tenantId,
),
);

projects.addAll(staffProjects);
}

projects.removeDuplicates((e) => e.id);

for (final project in projects) {
await projectLocalRepository.create(
project,
createOpLog: false,
);
}

if (projects.isNotEmpty) {
await _loadProjectFacilities(projects);
await _loadProductVariants(projects);
await _loadServiceDefinition(projects);
}

emit(ProjectState(
projects: projects,
loading: false,
selectedProject: projects.length == 1 ? projects.first : null,
));
}

FutureOr<void> _loadOffline(ProjectEmitter emit) async {
final projects = await projectLocalRepository.search(
ProjectSearchModel(
tenantId: envConfig.variables.tenantId,
),
);

projects.removeDuplicates((element) => element.id);

final selectedProject = await localSecureStore.selectedProject;
emit(
ProjectState(
loading: false,
projects: projects,
selectedProject: selectedProject,
),
);
}

FutureOr<void> _loadProjectFacilities(List<ProjectModel> projects) async {
Expand Down Expand Up @@ -262,6 +292,8 @@ class ProjectBloc extends Bloc<ProjectEvent, ProjectState> {
ProjectSelectProjectEvent event,
ProjectEmitter emit,
) async {
emit(state.copyWith(loading: true));

final List<BoundaryModel> boundaries =
await boundaryRemoteRepository.search(
BoundarySearchModel(
Expand All @@ -270,23 +302,12 @@ class ProjectBloc extends Bloc<ProjectEvent, ProjectState> {
),
);

await boundaryLocalRepository.bulkCreate(boundaries);
await localSecureStore.setSelectedProject(event.model);

await state.maybeMap(
orElse: () {
return;
},
fetched: (value) async {
final initial = DateTime.now();
await boundaryLocalRepository.bulkCreate(boundaries);
final end = DateTime.now();
AppLogger.instance.debug(
'${end.difference(initial).inMilliseconds}',
title: 'Boundary Duration',
);
emit(value.copyWith(selectedProject: event.model));
},
);
emit(state.copyWith(
selectedProject: event.model,
loading: false,
));
}
}

Expand All @@ -300,14 +321,17 @@ class ProjectEvent with _$ProjectEvent {

@freezed
class ProjectState with _$ProjectState {
const factory ProjectState.uninitialized() = ProjectUninitializedState;
const ProjectState._();

const factory ProjectState.loading() = ProjectLoadingState;
const factory ProjectState({
@Default([]) List<ProjectModel> projects,
ProjectModel? selectedProject,
@Default(false) bool loading,
}) = _ProjectState;

const factory ProjectState.empty() = ProjectsEmptyState;
bool get isEmpty => projects.isEmpty;

const factory ProjectState.fetched({
required List<ProjectModel> projects,
ProjectModel? selectedProject,
}) = ProjectSelectionFetchedState;
bool get isNotEmpty => !isEmpty;

bool get hasSelectedProject => selectedProject != null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ class AuthenticatedPageWrapper extends StatelessWidget {
actions: [
BlocBuilder<BoundaryBloc, BoundaryState>(
builder: (ctx, state) {
BoundaryModel? selectedBoundary;
try {
selectedBoundary = ctx.boundary;
} catch (_) {
debugPrint('');
final selectedBoundary = ctx.boundaryOrNull;

if (selectedBoundary == null) {
return const SizedBox.shrink();
}
final boundaryName =
selectedBoundary?.name ?? selectedBoundary?.code;
if (boundaryName == null) return const SizedBox.shrink();

final boundaryName = selectedBoundary.name ??
selectedBoundary.code ??
'No boundary name';

final theme = Theme.of(context);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,26 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import '../blocs/boundary/boundary.dart';
import '../models/data_model.dart';

class BoundarySelectionPage extends StatelessWidget {
class BoundarySelectionPage extends StatefulWidget {
const BoundarySelectionPage({Key? key}) : super(key: key);

@override
State<BoundarySelectionPage> createState() => _BoundarySelectionPageState();
}

class _BoundarySelectionPageState extends State<BoundarySelectionPage> {
bool shouldPop = false;

@override
Widget build(BuildContext context) {
return BlocBuilder<BoundaryBloc, BoundaryState>(
builder: (context, state) {
final selectedBoundary = state.selectedBoundaryMap.entries
.lastWhereOrNull((element) => element.value != null);

return WillPopScope(
onWillPop: () async {
return selectedBoundary != null;
},
child: Scaffold(
return WillPopScope(
onWillPop: () async => shouldPop,
child: BlocBuilder<BoundaryBloc, BoundaryState>(
builder: (context, state) {
final selectedBoundary = state.selectedBoundaryMap.entries
.lastWhereOrNull((element) => element.value != null);

return Scaffold(
body: Builder(
builder: (context) {
if (state.loading) {
Expand Down Expand Up @@ -97,11 +102,19 @@ class BoundarySelectionPage extends StatelessWidget {
child: DigitElevatedButton(
onPressed: selectedBoundary == null
? null
: () {
: () async {
setState(() {
shouldPop = true;
});

context.read<BoundaryBloc>().add(
const BoundarySubmitEvent(),
);
context.router.pop();

Future.delayed(
const Duration(milliseconds: 100),
() => context.router.pop(),
);
},
child: const Text('Submit'),
),
Expand All @@ -111,9 +124,9 @@ class BoundarySelectionPage extends StatelessWidget {
);
},
),
),
);
},
);
},
),
);
}
}
Loading