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

Issue/541 properties bottom sheets #545

Draft
wants to merge 23 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
29c6692
chore: move service APIs to the service package
DasProffi Sep 12, 2024
ae7722a
feat: draft for offline mode
DasProffi Sep 15, 2024
f97d8c6
fix: fix some errors
DasProffi Sep 15, 2024
5a5b2d9
feat: use offline mode api
DasProffi Sep 15, 2024
777e858
feat: draft for loading change notifier
DasProffi Sep 16, 2024
a075918
feat: update all controllers
DasProffi Sep 17, 2024
fe095c1
feat: update bottom sheets to handle nested navigation
DasProffi Sep 18, 2024
a1d8dc9
feat: make navigator generic
DasProffi Sep 18, 2024
91c5361
feat: update user bottom sheet and setting bottom sheet
DasProffi Sep 19, 2024
59888d5
feat: add organization bottom sheet
DasProffi Sep 19, 2024
930200f
feat: add wards bottom sheet
DasProffi Sep 19, 2024
820b26c
feat: add organization_members_bottom_sheet
DasProffi Sep 24, 2024
9a5bc10
feat: add draft for room and bed screen
DasProffi Oct 2, 2024
bee92a2
feat: update room overview bottomsheet
DasProffi Oct 2, 2024
1d70bfb
feat: add add bed button
DasProffi Oct 2, 2024
24dc8aa
feat: add TaskTemplate bottom sheets
DasProffi Oct 4, 2024
f0dfca8
feat: add draft for properties service
DasProffi Oct 9, 2024
ff7781f
feat: complete property api clients and fix various bugs
DasProffi Oct 9, 2024
20e9857
feat: add properties screen
DasProffi Oct 21, 2024
c3bf68f
feat: add property screen base
DasProffi Oct 21, 2024
0d31e35
feat: add translations
DasProffi Oct 22, 2024
b2d72b7
feat: add option to skip login with fake data
DasProffi Oct 22, 2024
65862de
Merge remote-tracking branch 'origin/issue/541-properties_bottom_shee…
DasProffi Oct 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 0 additions & 50 deletions apps/tasks/lib/components/assignee_select.dart

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:helpwave_localization/localization.dart';
import 'package:helpwave_service/user.dart';
import 'package:helpwave_widget/bottom_sheets.dart';
import 'package:helpwave_widget/content_selection.dart';

/// A [BottomSheet] for selecting a assignee
class AssigneeSelectBottomSheet extends StatelessWidget {
/// The callback when the assignee should be changed
///
/// Null if the assignee should be removed
final Function(User? assignee) onChanged;

final FutureOr<List<User>> users;

final String? selectedId;

const AssigneeSelectBottomSheet({super.key, required this.onChanged, required this.users, this.selectedId});

@override
Widget build(BuildContext context) {
return BottomSheetBase(
header: BottomSheetHeader(
titleText: context.localization!.assignee,
),
onClosing: () => {},
child: Column(
children: [
TextButton(
child: Text(context.localization!.remove),
onPressed: () => onChanged(null),
),
const SizedBox(height: 10),
SingleChildScrollView(
child: ListSelect(
items: users,
onSelect: onChanged,
builder: (context, user, select) => ListTile(
onTap: select,
leading: CircleAvatar(
foregroundColor: Colors.blue, backgroundImage: NetworkImage(user.profileUrl.toString())),
title: Text(user.nickName,
style: TextStyle(decoration: user.id == selectedId ? TextDecoration.underline : null)),
),
),
),
],
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:helpwave_localization/localization.dart';
import 'package:helpwave_service/user.dart';
import 'package:helpwave_theme/constants.dart';
import 'package:helpwave_theme/util.dart';
import 'package:helpwave_widget/bottom_sheets.dart';
import 'package:helpwave_widget/lists.dart';
import 'package:helpwave_widget/loading.dart';
import 'package:helpwave_widget/navigation.dart';
import 'package:helpwave_widget/text_input.dart';
import 'package:helpwave_widget/widgets.dart';
import 'package:provider/provider.dart';
import 'package:tasks/components/bottom_sheet_pages/organization_members_bottom_sheet.dart';
import 'package:tasks/components/bottom_sheet_pages/properties_bottom_sheet.dart';
import 'package:tasks/components/bottom_sheet_pages/wards_bottom_sheet_page.dart';
import 'package:tasks/screens/settings_screen.dart';

class OrganizationBottomSheetPage extends StatelessWidget {
final String organizationId;

const OrganizationBottomSheetPage({super.key, required this.organizationId});

@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => OrganizationController(Organization.empty(organizationId)),
child: Consumer<OrganizationController>(builder: (context, controller, _) {
return BottomSheetPage(
header: BottomSheetHeader.navigation(
context,
title: LoadingAndErrorWidget.pulsing(
state: controller.state,
child: Text(
controller.organization.combinedName,
style: const TextStyle(fontWeight: FontWeight.w800, fontSize: 16),
),
),
),
child: Flexible(
child: LoadingAndErrorWidget(
state: controller.state,
child: ListView(
shrinkWrap: true,
children: [
const SizedBox(height: distanceMedium),
Text(context.localization!.shortName, style: context.theme.textTheme.titleMedium),
const SizedBox(height: distanceTiny),
TextFormFieldWithTimer(
initialValue: controller.organization.shortName,
onUpdate: (value) => controller.update(shortName: value),
),
const SizedBox(height: distanceMedium),
Text(context.localization!.longName, style: context.theme.textTheme.titleMedium),
const SizedBox(height: distanceTiny),
TextFormFieldWithTimer(
initialValue: controller.organization.longName,
onUpdate: (value) => controller.update(longName: value),
),
const SizedBox(height: distanceMedium),
Text(context.localization!.contactEmail, style: context.theme.textTheme.titleMedium),
const SizedBox(height: distanceTiny),
TextFormFieldWithTimer(
initialValue: controller.organization.email,
// TODO validation
onUpdate: (value) => controller.update(email: value),
),
const SizedBox(height: distanceMedium),
Text(context.localization!.settings, style: context.theme.textTheme.titleMedium),
const SizedBox(height: distanceTiny),
RoundedListTiles(
children: [
NavigationListTile(
icon: Icons.house_rounded,
title: context.localization!.wards,
onTap: () {
NavigationStackController.of(context)
.push(WardsBottomSheetPage(organizationId: organizationId));
},
),
NavigationListTile(
icon: Icons.person,
title: context.localization!.members,
onTap: () {
NavigationStackController.of(context)
.push(OrganizationMembersBottomSheetPage(organizationId: organizationId));
},
),
NavigationListTile(
icon: Icons.label,
title: context.localization!.properties,
onTap: () {
NavigationStackController.of(context).push(const PropertiesBottomSheet());
},
)
],
),
const SizedBox(height: distanceMedium),
Text(context.localization!.dangerZone, style: context.theme.textTheme.titleMedium),
Text(
context.localization!.organizationDangerZoneDescription,
style: TextStyle(color: context.theme.hintColor),
),
PressableText(
text: "${context.localization!.delete} ${context.localization!.organization}",
style: const TextStyle(color: Colors.red, fontWeight: FontWeight.w700), // TODO get from theme
onPressed: () {
// TODO show modal and delete organization
},
),
],
),
),
),
);
}),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import 'package:flutter/material.dart';
import 'package:helpwave_localization/localization.dart';
import 'package:helpwave_service/auth.dart';
import 'package:helpwave_service/user.dart';
import 'package:helpwave_theme/constants.dart';
import 'package:helpwave_theme/util.dart';
import 'package:helpwave_widget/bottom_sheets.dart';
import 'package:helpwave_widget/lists.dart';
import 'package:helpwave_widget/loading.dart';
import 'package:provider/provider.dart';

class OrganizationMembersBottomSheetPage extends StatelessWidget {
final String organizationId;

const OrganizationMembersBottomSheetPage({super.key, required this.organizationId});

@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => OrganizationMemberController(organizationId),
child: BottomSheetPage(
header: BottomSheetHeader.navigation(
context,
title: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(context.localization!.members, style: context.theme.textTheme.titleMedium),
Text(CurrentWardService().currentWard?.organizationName ?? "",
style: TextStyle(color: context.theme.hintColor)),
],
),
trailing: BottomSheetAction(
icon: Icons.add,
onPressed: () {
// TODO show dialog
},
),
),
child: Flexible(
child: ListView(
children: [
Consumer<OrganizationMemberController>(builder: (context, controller, child) {
return LoadingAndErrorWidget(
state: controller.state,
child: RoundedListTiles(
children: controller.members
.map(
(member) => ListTile(
leading: Icon(
Icons.person_rounded,
color: context.theme.colorScheme.primary,
),
title: Text(member.name, style: const TextStyle(fontWeight: FontWeight.w700),),
subtitle: Text(member.email, style: TextStyle(color: context.theme.hintColor),),
trailing: IconButton(
onPressed: () {
controller.removeMember(organizationId: organizationId, userId: member.id);
},
icon: const Icon(
Icons.remove,
color: Colors.red, // TODO use theme
),
),
),
)
.toList(),
),
);
}),
Padding(
padding: const EdgeInsets.only(top: distanceMedium, bottom: distanceTiny),
child: Text(
context.localization!.invitations,
style: context.theme.textTheme.titleMedium,
),
),
Consumer<OrganizationMemberController>(builder: (context, controller, child) {
return LoadingAndErrorWidget(
state: controller.state,
child: RoundedListTiles(
children: controller.invitations
.map(
(invitation) => ListTile(
leading: Icon(
Icons.email_rounded,
color: context.theme.colorScheme.primary,
),
title: Text(invitation.email),
trailing: IconButton(
onPressed: () {
controller.revokeInvitation(invitationId: invitation.id);
},
icon: const Icon(
Icons.remove,
color: Colors.red, // TODO use theme
),
),
),
)
.toList(),
),
);
}),
],
),
),
),
);
}
}
Loading
Loading