Skip to content

Commit

Permalink
feat: add backend connection to my tasks screen
Browse files Browse the repository at this point in the history
* feat: add backend connection to my tasks screen

* fix: move close of modal to correct scope

* chore: revert change to config

* fix: fix imports
  • Loading branch information
DasProffi authored Feb 2, 2024
1 parent b2b3a50 commit bd71acb
Show file tree
Hide file tree
Showing 20 changed files with 332 additions and 31 deletions.
7 changes: 7 additions & 0 deletions apps/impulse/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,13 @@ packages:
relative: true
source: path
version: "0.0.1"
helpwave_util:
dependency: "direct overridden"
description:
path: "../../packages/helpwave_util"
relative: true
source: path
version: "0.0.1"
helpwave_widget:
dependency: "direct main"
description:
Expand Down
1 change: 0 additions & 1 deletion apps/tasks/lib/components/assignee_select.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class AssigneeSelect extends StatelessWidget {
return ListTile(
onTap: () {
assigneeSelectController.changeAssignee(user.id).then((value) {
Navigator.pop(context);
onChanged(user);
});
},
Expand Down
35 changes: 22 additions & 13 deletions apps/tasks/lib/components/task_bottom_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,7 @@ class _TaskBottomSheetState extends State<TaskBottomSheet> {
title: Consumer<TaskController>(
builder: (context, taskController, child) => ClickableTextEdit(
initialValue: taskController.task.name,
onChanged: (value) {
taskController.updateTask((task) {
task.name = value;
});
},
onUpdated: taskController.changeName,
textAlign: TextAlign.center,
textStyle: TextStyle(
color: Theme.of(context).colorScheme.secondary,
Expand Down Expand Up @@ -193,7 +189,7 @@ class _TaskBottomSheetState extends State<TaskBottomSheet> {
),
child: AssigneeSelect(
onChanged: (assignee) {
taskController.changeAssignee(assigneeId: assignee.id);
taskController.changeAssignee(assignee.id).then((value) => Navigator.of(context).pop());
},
),
),
Expand Down Expand Up @@ -233,9 +229,10 @@ class _TaskBottomSheetState extends State<TaskBottomSheet> {
valueWidget: Builder(builder: (context) {
DateTime? dueDate = taskController.task.dueDate;
if (dueDate != null) {
String date = "${dueDate.day.toString().padLeft(2, "0")}.${dueDate.month.toString()
.padLeft(2, "0")}.${dueDate.year.toString().padLeft(4, "0")}";
String time = "${dueDate.hour.toString().padLeft(2, "0")}:${dueDate.minute.toString().padLeft(2, "0")}";
String date =
"${dueDate.day.toString().padLeft(2, "0")}.${dueDate.month.toString().padLeft(2, "0")}.${dueDate.year.toString().padLeft(4, "0")}";
String time =
"${dueDate.hour.toString().padLeft(2, "0")}:${dueDate.minute.toString().padLeft(2, "0")}";
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
Expand All @@ -261,7 +258,7 @@ class _TaskBottomSheetState extends State<TaskBottomSheet> {
label: context.localization!.visibility,
valueWidget: VisibilitySelect(
isPublicVisible: taskController.task.isPublicVisible,
onChanged: (value) => taskController.changeIsPublic(isPublic: value),
onChanged: taskController.changeIsPublic,
isCreating: taskController.isCreating,
textStyle: editableValueTextStyle(context),
),
Expand All @@ -275,11 +272,23 @@ class _TaskBottomSheetState extends State<TaskBottomSheet> {
),
const SizedBox(height: distanceTiny),
Consumer<TaskController>(
builder: (_, taskController, __) => LoadingAndErrorWidget.pulsing(
builder: (_, taskController, __) => LoadingAndErrorWidget(
state: taskController.state,
child: TextFormField(
loadingWidget: PulsingContainer(
width: MediaQuery.of(context).size.width,
height: 25 * 6, // 25px per line
),
errorWidget: PulsingContainer(
width: MediaQuery.of(context).size.width,
height: 25 * 6,
// 25px per line
maxOpacity: 1,
minOpacity: 1,
color: negativeColor,
),
child: TextFormFieldWithTimer(
initialValue: taskController.task.notes,
onChanged: taskController.changeNotes,
onUpdate: taskController.changeNotes,
maxLines: 6,
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(paddingMedium),
Expand Down
7 changes: 6 additions & 1 deletion apps/tasks/lib/components/task_expansion_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
import 'package:helpwave_theme/constants.dart';
import 'package:helpwave_widget/bottom_sheets.dart';
import 'package:helpwave_widget/shapes.dart';
import 'package:provider/provider.dart';
import 'package:tasks/components/task_bottom_sheet.dart';
import 'package:tasks/components/task_card.dart';
import '../controllers/my_tasks_controller.dart';
import '../dataclasses/task.dart';

/// A [ExpansionTile] for showing a [List] of [Task]s
Expand Down Expand Up @@ -55,7 +57,10 @@ class TaskExpansionTile extends StatelessWidget {
context.pushModal(
context: context,
builder: (context) => TaskBottomSheet(task: task, patient: task.patient),
);
).then((_) {
MyTasksController controller = Provider.of<MyTasksController>(context, listen: false);
controller.load();
});
},
child: TaskCard(
task: task,
Expand Down
1 change: 1 addition & 0 deletions apps/tasks/lib/controllers/my_tasks_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class MyTasksController extends ChangeNotifier {
var patients = await PatientService().getPatientList(wardId: CurrentWardService().currentWard?.wardId);
List<Patient>allPatients = patients.all;

_tasks = [];
// TODO use the already given information by the later updated getPatientList
for(Patient patient in allPatients) {
List<Task> tasks = await TaskService().getTasksByPatient(patientId: patient.id);
Expand Down
63 changes: 48 additions & 15 deletions apps/tasks/lib/controllers/task_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,24 @@ class TaskController extends ChangeNotifier {
notifyListeners();
}

// Used to trigger the notify call without having to copy or save the Task locally
updateTask(void Function(TaskWithPatient task) transformer) {
transformer(task);
/// Used to trigger the notify call without having to copy or save the Task locally
updateTask(void Function(TaskWithPatient task) updateTransform, void Function(TaskWithPatient task) revertTransform) {
updateTransform(task);
if (!isCreating) {
TaskService().updateTask(task).then((value) {
if (value) {
state = LoadingState.loaded;
} else {
throw Error();
}
}).catchError((error, stackTrace) {
revertTransform(task);
errorMessage = error.toString();
state = LoadingState.error;
});
} else {
state = LoadingState.loaded;
}
state = LoadingState.loaded;
}

Expand All @@ -55,9 +70,7 @@ class TaskController extends ChangeNotifier {
/// A function to load the [Task]
load() async {
state = LoadingState.loading;
await TaskService()
.getTask(id: task.id)
.then((value) {
await TaskService().getTask(id: task.id).then((value) {
task = value;
state = LoadingState.loaded;
}).catchError((error, stackTrace) {
Expand All @@ -69,20 +82,40 @@ class TaskController extends ChangeNotifier {
/// Changes the Assignee
///
/// Without a backend request as we expect this to be done in the [AssigneeSelectController]
Future<void> changeAssignee({required String assigneeId}) async {
task.assignee = assigneeId;
notifyListeners();
Future<void> changeAssignee(String assigneeId) async {
String? old = task.assignee;
updateTask((task) {
task.assignee = assigneeId;
}, (task) {
task.assignee = old;
});
}

Future<void> changeName(String name) async {
String oldName = task.name;
updateTask((task) {
task.name = name;
}, (task) {
task.name = oldName;
});
}

Future<void> changeIsPublic({required bool isPublic}) async {
// TODO backend request
Future<void> changeIsPublic(bool isPublic) async {
task.isPublicVisible = isPublic;
notifyListeners();
bool old = task.isPublicVisible;
updateTask((task) {
task.isPublicVisible = isPublic;
}, (task) {
task.isPublicVisible = old;
});
}

Future<void> changeNotes(String notes) async {
// TODO backend request when appropriate
task.notes = notes;
notifyListeners();
String oldNotes = notes;
updateTask((task) {
task.notes = notes;
}, (task) {
task.notes = oldNotes;
});
}
}
18 changes: 18 additions & 0 deletions apps/tasks/lib/services/task_svc.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:grpc/grpc.dart';
import 'package:helpwave_proto_dart/google/protobuf/timestamp.pb.dart';
import 'package:helpwave_proto_dart/proto/services/task_svc/v1/task_svc.pbgrpc.dart';
import 'package:tasks/dataclasses/patient.dart';
import 'package:tasks/dataclasses/subtask.dart';
Expand Down Expand Up @@ -159,4 +160,21 @@ class TaskService {

return response.isInitialized();
}

Future<bool> updateTask(Task task) async {
UpdateTaskRequest request = UpdateTaskRequest(
id: task.id,
name: task.name,
description: task.notes,
dueAt: task.dueDate != null ? Timestamp.fromDateTime(task.dueDate!) : null,
public: task.isPublicVisible,
);

UpdateTaskResponse response = await taskService.updateTask(
request,
options: CallOptions(metadata: GRPCClientService().getTaskServiceMetaData()),
);

return response.isInitialized();
}
}
7 changes: 7 additions & 0 deletions apps/tasks/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ packages:
relative: true
source: path
version: "0.0.1"
helpwave_util:
dependency: "direct overridden"
description:
path: "../../packages/helpwave_util"
relative: true
source: path
version: "0.0.1"
helpwave_widget:
dependency: "direct main"
description:
Expand Down
30 changes: 30 additions & 0 deletions packages/helpwave_util/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
10 changes: 10 additions & 0 deletions packages/helpwave_util/.metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: 18a827f3933c19f51862dde3fa472197683249d6
channel: stable

project_type: package
3 changes: 3 additions & 0 deletions packages/helpwave_util/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 0.0.1

* TODO: Describe initial release.
15 changes: 15 additions & 0 deletions packages/helpwave_util/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Features

#### Time
- TimedValueUpdater: For updating a value after <X> seconds

## Getting started

Add the package to your `pubspec.yaml`

## Usage

Import the widget that you want to use:
e.g. `import 'package:helpwave_utils/time.dart';`

## Additional information
4 changes: 4 additions & 0 deletions packages/helpwave_util/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
50 changes: 50 additions & 0 deletions packages/helpwave_util/lib/src/time/timed_value_updater.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import 'dart:async';

/// A Class for updating a value and returning it after [timeToCallback] amount of seconds
///
/// WARNING: must be disposed
class TimedValueUpdater<T> {

/// The call
final void Function(T value) callback;

/// The Duration until the [callback] is called after a update
final Duration timeToCallback;

/// The current value, which will be returned by the [callback]
T _value;

/// The timer for the callback
Timer? _timer;

T get value => this._value;

set value(T newValue) {
this._value = newValue;
_timer?.cancel();
resetTimer();
}

TimedValueUpdater(this._value, {
required this.callback,
this.timeToCallback = const Duration(seconds: 3),
});

/// Resets the update timer, when the value was just updated
void resetTimer() {
_timer = Timer.periodic(this.timeToCallback, (_) => this.callback(_value));
}

/// Cancels the [Timer]
void cancelTimer({bool isNotifying = false}) {
if(isNotifying){
this.callback(_value);
}
_timer?.cancel();
}

/// Should be called when the object holding this is disposed
void dispose({bool isNotifying = false}) {
cancelTimer(isNotifying: isNotifying);
}
}
1 change: 1 addition & 0 deletions packages/helpwave_util/lib/time.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'src/time/timed_value_updater.dart';
21 changes: 21 additions & 0 deletions packages/helpwave_util/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: helpwave_util
description: A package containing helpwave's utility classes
version: 0.0.1
homepage: https://github.com/helpwave/mobile-app

publish_to: none

environment:
sdk: '>=3.1.0'
flutter: ">=3.13.0"

dependencies:
flutter:
sdk: flutter

dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0

flutter:
Loading

0 comments on commit bd71acb

Please sign in to comment.