Skip to content

Commit

Permalink
✨ add support for clients
Browse files Browse the repository at this point in the history
  • Loading branch information
BirjuVachhani committed Aug 7, 2024
1 parent 6e5807f commit a347260
Show file tree
Hide file tree
Showing 23 changed files with 494 additions and 66 deletions.
16 changes: 14 additions & 2 deletions lib/api/toggl_api_service.chopper.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion lib/api/toggl_api_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';

import '../model/project.dart';
import '../model/time_entry.dart';
import '../model/toggl_client.dart';
import '../model/user.dart';
import '../model/workspace.dart';
import '../resources/keys.dart';
Expand Down Expand Up @@ -36,13 +37,16 @@ abstract class TogglApiService extends ChopperService {
@Get(path: '/me')
Future<Response<User>> getProfile();

@Get(path: '/me/time_entries')
@Get(path: '/me/time_entries?meta=true')
Future<Response<List<TimeEntry>>> getTimeEntries(
@Query('start_date') String startDate, @Query('end_date') String endDate);

@Get(path: '/workspaces')
Future<Response<List<Workspace>>> getAllWorkspaces();

@Get(path: '/me/clients')
Future<Response<List<TogglClient>>> getAllClients();

@Get(path: '/me/projects')
Future<Response<List<Project>>> getAllProjects();

Expand Down Expand Up @@ -110,6 +114,7 @@ Map<Type, Object Function(Map<String, dynamic>)> registry = {
User: User.fromJson,
Workspace: Workspace.fromJson,
Project: Project.fromJson,
TogglClient: TogglClient.fromJson,
TimeEntry: TimeEntry.fromJson,
Map<String, dynamic>: (Map<String, dynamic> json) => json,
};
5 changes: 5 additions & 0 deletions lib/model/project.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class Project with EquatableMixin {
final String? currency;
final bool recurring;
final int? wid;
@JsonKey(name: 'client_id')
final int? clientId;
final int? cid;

Project({
required this.id,
Expand All @@ -42,6 +45,8 @@ class Project with EquatableMixin {
required this.currency,
this.recurring = false,
this.wid,
this.clientId,
this.cid,
});

factory Project.fromJson(Map<String, dynamic> json) =>
Expand Down
10 changes: 7 additions & 3 deletions lib/model/project.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion lib/model/time_entry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class TimeEntry with EquatableMixin {
@JsonKey(name: 'server_deleted_at', fromJson: deletedFromJson)
final bool isDeleted;
final bool isRunning;
@JsonKey(name: 'client_name')
final String? clientName;

TimeEntryType get type => TimeEntryType.fromBool(billable);

Expand All @@ -81,6 +83,7 @@ class TimeEntry with EquatableMixin {
required this.billable,
required this.isDeleted,
this.isRunning = false,
this.clientName,
});

@visibleForTesting
Expand All @@ -99,7 +102,8 @@ class TimeEntry with EquatableMixin {
wid = -1,
pid = -1,
billable = false,
isRunning = false;
isRunning = false,
clientName = null;

/// CopyWith
TimeEntry copyWith({
Expand All @@ -118,6 +122,7 @@ class TimeEntry with EquatableMixin {
bool? billable,
bool? isDeleted,
bool? isRunning,
String? clientName,
}) {
return TimeEntry(
id: id ?? this.id,
Expand All @@ -135,6 +140,7 @@ class TimeEntry with EquatableMixin {
billable: billable ?? this.billable,
isDeleted: isDeleted ?? this.isDeleted,
isRunning: isRunning ?? this.isRunning,
clientName: clientName ?? this.clientName,
);
}

Expand All @@ -160,5 +166,8 @@ class TimeEntry with EquatableMixin {
wid,
pid,
billable,
isDeleted,
isRunning,
clientName,
];
}
21 changes: 12 additions & 9 deletions lib/model/time_entry.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions lib/model/toggl_client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';

import '../utils/json_converters.dart';

part 'toggl_client.g.dart';

@JsonSerializable()
class TogglClient with EquatableMixin {
final int id;
final String name;
final int wid;
final bool archived;
@JsonKey(name: 'at')
@DateTimeConverter()
final DateTime createdAt;

@JsonKey(name: 'creator_id')
final int creatorId;

TogglClient({
required this.id,
required this.name,
required this.wid,
required this.archived,
required this.createdAt,
required this.creatorId,
});

factory TogglClient.fromJson(Map<String, dynamic> json) {
return _$TogglClientFromJson(json);
}

Map<String, dynamic> toJson() => _$TogglClientToJson(this);

@override
List<Object?> get props => [id];
}
26 changes: 26 additions & 0 deletions lib/model/toggl_client.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions lib/model/user.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions lib/model/workspace.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 42 additions & 16 deletions lib/pages/home/home_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import 'package:screwdriver/screwdriver.dart';

import '../../api/toggl_api_service.dart';
import '../../model/day_entry.dart';
import '../../model/project.dart';
import '../../model/time_entry.dart';
import '../../model/toggl_client.dart';
import '../../model/user.dart';
import '../../model/workspace.dart';
import '../../resources/keys.dart';
import '../../utils/app_icon_manager.dart';
import '../../utils/extensions.dart';
Expand Down Expand Up @@ -336,27 +339,50 @@ abstract class _HomeStore with Store {
void processTimeEntries(List<TimeEntry> entries) {
log('Processing time entries...');

final int? projectId = getProjectFromStorage()?.id;
final int? workspaceId = getWorkspaceFromStorage()?.id;
final Project? project = getProjectFromStorage();
final TogglClient? client = getClientFromStorage();
final Workspace? workspace = getWorkspaceFromStorage();

final TimeEntryType selectedTimeEntryType = TimeEntryType.values.byName(
settingsBox.get(HiveKeys.entryType,
defaultValue: TimeEntryType.all.name));

List<TimeEntry> filtered = entries.where((item) {
if (item.projectId == projectId && item.workspaceId == workspaceId) {
return true;
}
if (workspaceId != null && item.workspaceId != workspaceId) {
log('Skipping entry [${item.id}]: ${item.description} because workspaceId does not match!');
return false;
}
if (projectId != null && item.projectId != projectId) {
log('Skipping entry [${item.id}]: ${item.description} because projectId does not match!');
return false;
}
return true;
}).where((entry) {
List<TimeEntry> filtered = [...entries];
if (workspace != null && workspace.id != -1) {
// filter by workspace.
filtered = filtered
.where((entry) =>
entry.workspaceId == workspace.id || entry.wid == workspace.id)
.toList();
}
if (client != null && client.id != -1) {
// filter by client.
filtered =
filtered.where((entry) => entry.clientName == client.name).toList();
}
if (project != null && project.id != -1) {
// filter by client.
filtered =
filtered.where((entry) => entry.projectId == project.id).toList();
}

// List<TimeEntry> filtered = entries.where((item) {
// // when a specific project is selected.
// if (item.projectId == project?.id && item.workspaceId == workspace.id) {
// return true;
// }
// if (workspace != null && item.workspaceId != workspace.id) {
// log('Skipping entry [${item.id}]: ${item.description} because workspaceId does not match!');
// return false;
// }
// if (project != null && item.projectId != project.id) {
// log('Skipping entry [${item.id}]: ${item.description} because projectId does not match!');
// return false;
// }
// return true;
// }).toList();

filtered = filtered.where((entry) {
if (selectedTimeEntryType.isAll) return true;
if (entry.type == selectedTimeEntryType) return true;
log('Skipping entry [${entry.id}]: ${entry.description} because entry type does not match!');
Expand Down
Loading

0 comments on commit a347260

Please sign in to comment.