Skip to content

Commit 654b849

Browse files
authored
Merge pull request #13 from CoderJava/hotfix/perbaikan-timer-yang-tidak-sync
Hotfix - Perbaikan timer yang tidak sync
2 parents 4398792 + 310bed8 commit 654b849

File tree

5 files changed

+135
-30
lines changed

5 files changed

+135
-30
lines changed
18.6 KB
Loading

lib/core/util/images.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class BaseIconTray {
99
class BaseImage {
1010
static const _path = 'assets/images';
1111
static const imagePlaceholder = '$_path/image_placeholder.jpeg';
12+
static const imageFileNotFound = '$_path/image_file_not_found.png';
1213
}
1314

1415
class BaseAnimation {

lib/core/util/widget_helper.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import 'dart:io';
2+
import 'dart:math';
23

4+
import 'package:dipantau_desktop_client/core/util/enum/global_variable.dart';
35
import 'package:dipantau_desktop_client/core/util/helper.dart';
6+
import 'package:dipantau_desktop_client/core/util/shared_preferences_manager.dart';
47
import 'package:dipantau_desktop_client/feature/presentation/page/splash/splash_page.dart';
58
import 'package:dipantau_desktop_client/injection_container.dart';
69
import 'package:easy_localization/easy_localization.dart';
710
import 'package:flutter/material.dart';
11+
import 'package:flutter/services.dart';
812
import 'package:go_router/go_router.dart';
913
import 'package:path_provider/path_provider.dart';
1014

@@ -182,4 +186,27 @@ class WidgetHelper {
182186
},
183187
);
184188
}
189+
190+
Future<File> getImageFileFromAssets(String path) async {
191+
final byteData = await rootBundle.load(path);
192+
193+
final directoryPath = await getDirectoryApp('screenshot');
194+
var userId = sharedPreferencesManager.getString(SharedPreferencesManager.keyUserId) ?? '';
195+
final random = Random();
196+
if (userId.isEmpty) {
197+
userId = random.nextInt(100).toString();
198+
}
199+
final strRandomNumber = random.nextInt(100).toString();
200+
201+
final now = DateTime.now();
202+
final timeInMillis = now.millisecondsSinceEpoch;
203+
final timeInSeconds = Duration(milliseconds: timeInMillis).inSeconds;
204+
final pathString = '${timeInSeconds}_${userId}_${strRandomNumber}_1.jpg';
205+
final file = File('$directoryPath/$pathString');
206+
207+
await file.create(recursive: true);
208+
await file.writeAsBytes(byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
209+
210+
return file;
211+
}
185212
}

lib/feature/presentation/page/home/home_page.dart

Lines changed: 87 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
6969
final notificationHelper = sl<NotificationHelper>();
7070
final intervalScreenshot = 60 * 5; // 300 detik (5 menit)
7171
final listTrackLocal = <Track>[];
72+
final listPathStartScreenshots = <String?>[];
7273

7374
var isWindowVisible = true;
7475
var userId = '';
@@ -84,6 +85,7 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
8485
DateTime? startTime;
8586
DateTime? finishTime;
8687
DateTime? infoDateTime;
88+
DateTime? now;
8789

8890
@override
8991
void setState(VoidCallback fn) {
@@ -596,7 +598,8 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
596598
}
597599

598600
if (isPermissionScreenRecordingGranted!) {
599-
final isPermissionAccessibilityGranted = await platformChannelHelper.checkPermissionAccessibility();
601+
final isPermissionAccessibilityGranted =
602+
await platformChannelHelper.checkPermissionAccessibility();
600603
if (mounted && isPermissionAccessibilityGranted != null && !isPermissionAccessibilityGranted) {
601604
widgetHelper.showDialogPermissionAccessibility(context);
602605
return;
@@ -618,8 +621,8 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
618621
} else {
619622
isTimerStart = false;
620623
itemTask.trackedInSeconds = valueNotifierTaskTracked.value;
621-
finishTime = DateTime.now();
622624
stopTimer();
625+
finishTime = DateTime.now();
623626
doTakeScreenshot(startTime, finishTime);
624627
selectedTask = null;
625628
}
@@ -1004,13 +1007,28 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
10041007
platformChannelHelper.startEventChannel().listen((Object? event) {
10051008
if (event != null) {
10061009
if (event is String) {
1007-
isHaveActivity = true;
1010+
final strEvent = event.toLowerCase();
1011+
if (strEvent == 'triggered') {
1012+
// update flag activity menjadi true
1013+
isHaveActivity = true;
1014+
} else if (strEvent == 'screen_is_locked') {
1015+
// auto stop timer dan ambil screenshot-nya
1016+
isTimerStart = false;
1017+
stopTimer();
1018+
finishTime = DateTime.now();
1019+
doTakeScreenshot(startTime, finishTime, isForceStop: true);
1020+
selectedTask = null;
1021+
setState(() {});
1022+
} else if (strEvent == 'screen_is_unlocked') {
1023+
// muat ulang datanya setelah user unlock screen
1024+
doLoadData();
1025+
}
10081026
}
10091027
}
10101028
});
10111029
}
10121030

1013-
void doTakeScreenshot(DateTime? startTime, DateTime? finishTime) async {
1031+
void doTakeScreenshot(DateTime? startTime, DateTime? finishTime, {bool isForceStop = false}) async {
10141032
var percentActivity = 0.0;
10151033
if (counterActivity > 0 && countTimerInSeconds > 0) {
10161034
percentActivity = (counterActivity / countTimerInSeconds) * 100;
@@ -1065,28 +1083,35 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
10651083

10661084
final activity = percentActivity.round();
10671085

1068-
final listPathScreenshots = await platformChannelHelper.doTakeScreenshot();
1069-
final isPermissionScreenRecordingGranted = await platformChannelHelper.checkPermissionScreenRecording();
1070-
if (isPermissionScreenRecordingGranted != null && !isPermissionScreenRecordingGranted) {
1071-
debugPrint('screen recording not granted');
1072-
notificationHelper.showPermissionScreenRecordingIssuedNotification();
1073-
valueNotifierTotalTracked.value -= durationInSeconds;
1074-
valueNotifierTaskTracked.value -= durationInSeconds;
1075-
isTimerStart = false;
1076-
stopTimer();
1077-
selectedTask = null;
1078-
setState(() {});
1079-
return;
1080-
} else if (listPathScreenshots.isEmpty) {
1081-
debugPrint('list path screenshots is empty');
1082-
valueNotifierTotalTracked.value -= durationInSeconds;
1083-
valueNotifierTaskTracked.value -= durationInSeconds;
1084-
isTimerStart = false;
1085-
stopTimer();
1086-
selectedTask = null;
1087-
setState(() {});
1088-
return;
1086+
final listPathScreenshots = <String?>[];
1087+
String files;
1088+
if (!isForceStop) {
1089+
listPathScreenshots.clear();
1090+
listPathScreenshots.addAll(await platformChannelHelper.doTakeScreenshot());
1091+
final isPermissionScreenRecordingGranted = await platformChannelHelper.checkPermissionScreenRecording();
1092+
if ((isPermissionScreenRecordingGranted != null && !isPermissionScreenRecordingGranted) ||
1093+
listPathScreenshots.isEmpty) {
1094+
stopTimer();
1095+
isTimerStart = false;
1096+
selectedTask = null;
1097+
setState(() {});
1098+
final fileDefaultScreenshot = await widgetHelper.getImageFileFromAssets(BaseImage.imageFileNotFound);
1099+
listPathScreenshots.add(fileDefaultScreenshot.path);
1100+
}
1101+
} else {
1102+
listPathScreenshots.clear();
1103+
if (listPathStartScreenshots.isNotEmpty) {
1104+
listPathScreenshots.addAll(listPathStartScreenshots);
1105+
} else {
1106+
stopTimer();
1107+
isTimerStart = false;
1108+
selectedTask = null;
1109+
setState(() {});
1110+
final fileDefaultScreenshot = await widgetHelper.getImageFileFromAssets(BaseImage.imageFileNotFound);
1111+
listPathScreenshots.add(fileDefaultScreenshot.path);
1112+
}
10891113
}
1114+
10901115
listPathScreenshots.removeWhere((element) => element == null || element.isEmpty);
10911116
if (listPathScreenshots.isNotEmpty) {
10921117
final firstElement = listPathScreenshots.first ?? '';
@@ -1105,7 +1130,7 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
11051130
);
11061131
}
11071132
}
1108-
final files = listPathScreenshots.join(',');
1133+
files = listPathScreenshots.join(',');
11091134

11101135
final isShowScreenshotNotification =
11111136
sharedPreferencesManager.getBool(SharedPreferencesManager.keyIsEnableScreenshotNotification) ?? false;
@@ -1149,8 +1174,42 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
11491174
void startTimer() {
11501175
countTimeReminderTrackInSeconds = 0;
11511176
stopTimer();
1152-
timeTrack = Timer.periodic(const Duration(seconds: 1), (_) {
1153-
increaseTimerTray();
1177+
1178+
now = DateTime.now();
1179+
platformChannelHelper.checkPermissionScreenRecording().then((isGranted) async {
1180+
if (isGranted != null && isGranted) {
1181+
final listPathScreenshots = await platformChannelHelper.doTakeScreenshot();
1182+
if (listPathScreenshots.isNotEmpty) {
1183+
listPathStartScreenshots.clear();
1184+
listPathStartScreenshots.addAll(listPathScreenshots);
1185+
}
1186+
}
1187+
});
1188+
timeTrack = Timer.periodic(const Duration(milliseconds: 1), (timer) {
1189+
// intervalnya dibuat milliseconds agar bisa mengikuti dengan date time device-nya.
1190+
final newNow = DateTime.now();
1191+
final newNowDate = DateTime(
1192+
newNow.year,
1193+
newNow.month,
1194+
newNow.day,
1195+
newNow.hour,
1196+
newNow.minute,
1197+
newNow.second,
1198+
);
1199+
if (now != null) {
1200+
final nowDate = DateTime(
1201+
now!.year,
1202+
now!.month,
1203+
now!.day,
1204+
now!.hour,
1205+
now!.minute,
1206+
now!.second,
1207+
);
1208+
if (!nowDate.isAtSameMomentAs(newNowDate)) {
1209+
now = newNowDate;
1210+
increaseTimerTray();
1211+
}
1212+
}
11541213
});
11551214
}
11561215

macos/Runner/AppDelegate.swift

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import FlutterMacOS
44
@NSApplicationMain
55
class AppDelegate: FlutterAppDelegate, FlutterStreamHandler {
66
private var eventSink: FlutterEventSink?
7+
private let dnc = DistributedNotificationCenter.default()
78

89
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
910
// Set quit while window is minimized
1011
// return true
1112
return false
1213
}
1314

14-
1515
override func applicationDidFinishLaunching(_ notification: Notification) {
1616
let controller: FlutterViewController = mainFlutterWindow?.contentViewController as! FlutterViewController
1717
let channel = FlutterMethodChannel.init(name: "dipantau/channel", binaryMessenger: controller.engine.binaryMessenger)
@@ -41,7 +41,7 @@ class AppDelegate: FlutterAppDelegate, FlutterStreamHandler {
4141
result(true)
4242
}
4343
} else if ("check_permission_accessibility" == call.method) {
44-
var hasAccessibility = AXIsProcessTrusted()
44+
let hasAccessibility = AXIsProcessTrusted()
4545
if (hasAccessibility) {
4646
result(true)
4747
} else {
@@ -100,6 +100,7 @@ class AppDelegate: FlutterAppDelegate, FlutterStreamHandler {
100100
func onListen(withArguments arguments: Any?, eventSink: @escaping FlutterEventSink) -> FlutterError? {
101101
self.eventSink = eventSink
102102
setActivityListener()
103+
setScreenLockedListener()
103104
return nil
104105
}
105106

@@ -108,6 +109,23 @@ class AppDelegate: FlutterAppDelegate, FlutterStreamHandler {
108109
return nil
109110
}
110111

112+
func setScreenLockedListener() {
113+
dnc.addObserver(forName: .init("com.apple.screenIsLocked"), object: nil, queue: .main) { _ in
114+
guard let eventSink = self.eventSink else {
115+
return
116+
}
117+
118+
eventSink("screen_is_locked")
119+
}
120+
dnc.addObserver(forName: .init("com.apple.screenIsUnlocked"), object: nil, queue: .main) { _ in
121+
guard let eventSink = self.eventSink else {
122+
return
123+
}
124+
125+
eventSink("screen_is_unlocked")
126+
}
127+
}
128+
111129
func setActivityListener() {
112130
NSEvent.addGlobalMonitorForEvents(matching: [NSEvent.EventTypeMask.keyDown, NSEvent.EventTypeMask.leftMouseDown, NSEvent.EventTypeMask.rightMouseDown, NSEvent.EventTypeMask.leftMouseDragged, NSEvent.EventTypeMask.rightMouseDragged], handler: {(event: NSEvent) in
113131
guard let eventSink = self.eventSink else {

0 commit comments

Comments
 (0)