diff --git a/.gitignore b/.gitignore index 03c8052..a35d909 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ android/build/ android/app/build/ android/local.properties config/firebase-service-account.json +.* +!.gitignore diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index d77d34f..e2b756e 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -13,8 +13,8 @@ android { applicationId = "com.devlab.app" minSdk = 26 targetSdk = 37 - versionCode = 14 - versionName = "1.8.2" + versionCode = 15 + versionName = "1.8.3" } buildTypes { diff --git a/android/app/src/main/java/com/devlab/app/data/model/Notification.kt b/android/app/src/main/java/com/devlab/app/data/model/Notification.kt index 1258ee0..2a8a564 100644 --- a/android/app/src/main/java/com/devlab/app/data/model/Notification.kt +++ b/android/app/src/main/java/com/devlab/app/data/model/Notification.kt @@ -8,4 +8,5 @@ data class AppNotification( val type: String = "info", val is_read: Int = 0, val created_at: String = "", + val created_at_timestamp: Long = 0, ) diff --git a/android/app/src/main/java/com/devlab/app/service/NotificationForegroundService.kt b/android/app/src/main/java/com/devlab/app/service/NotificationForegroundService.kt index d4e02b0..5866e36 100644 --- a/android/app/src/main/java/com/devlab/app/service/NotificationForegroundService.kt +++ b/android/app/src/main/java/com/devlab/app/service/NotificationForegroundService.kt @@ -99,7 +99,7 @@ class NotificationForegroundService : android.app.Service() { if (!response.success) return val newNotifications = response.data.filter { note -> - val noteTime = parseTime(note.created_at) + val noteTime = note.created_at_timestamp * 1000L noteTime > lastCheck && note.is_read == 0 } @@ -108,19 +108,7 @@ class NotificationForegroundService : android.app.Service() { for (notification in newNotifications) { NotificationHelper.showNotification(this, notification) } - lastCheck = newNotifications.maxOf { parseTime(it.created_at) } - } - } - - private fun parseTime(time: String?): Long { - if (time == null) return 0L - return try { - val sdf = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.US).apply { - timeZone = java.util.TimeZone.getTimeZone("UTC") - } - sdf.parse(time)?.time ?: 0L - } catch (_: Exception) { - 0L + lastCheck = newNotifications.maxOf { it.created_at_timestamp * 1000L } } } diff --git a/android/app/src/main/java/com/devlab/app/ui/notifications/NotificationsScreen.kt b/android/app/src/main/java/com/devlab/app/ui/notifications/NotificationsScreen.kt index fe743e1..725d03d 100644 --- a/android/app/src/main/java/com/devlab/app/ui/notifications/NotificationsScreen.kt +++ b/android/app/src/main/java/com/devlab/app/ui/notifications/NotificationsScreen.kt @@ -219,7 +219,7 @@ private fun NotificationItem( Row(verticalAlignment = Alignment.CenterVertically) { Text( - text = formatTime(notification.created_at), + text = formatTime(notification.created_at_timestamp * 1000L), style = MaterialTheme.typography.labelSmall, color = Grey500 ) @@ -240,27 +240,17 @@ private fun NotificationItem( } } -private fun formatTime(timestamp: String?): String { - if (timestamp == null) return "" - return try { - val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).apply { - timeZone = TimeZone.getTimeZone("UTC") +private fun formatTime(millis: Long): String { + if (millis <= 0) return "" + val now = System.currentTimeMillis() + val diff = now - millis + return when { + diff < 60_000 -> "Just now" + diff < 3600_000 -> "${diff / 60_000}m ago" + diff < 86400_000 -> "${diff / 3600_000}h ago" + else -> { + val sdf = SimpleDateFormat("MMM d, HH:mm", Locale.US) + sdf.format(Date(millis)) } - val date = sdf.parse(timestamp) ?: return timestamp - val now = Calendar.getInstance() - val then = Calendar.getInstance().apply { - this.time = date - } - - val diff = now.timeInMillis - then.timeInMillis - when { - diff < 60_000 -> "Just now" - diff < 3600_000 -> "${diff / 60_000}m ago" - diff < 86400_000 -> "${diff / 3600_000}h ago" - else -> { - val out = SimpleDateFormat("MMM d, HH:mm", Locale.US) - out.format(date) - } - } - } catch (_: Exception) { timestamp } + } } diff --git a/android/app/src/main/java/com/devlab/app/util/NotificationHelper.kt b/android/app/src/main/java/com/devlab/app/util/NotificationHelper.kt index ae44543..95cecf0 100644 --- a/android/app/src/main/java/com/devlab/app/util/NotificationHelper.kt +++ b/android/app/src/main/java/com/devlab/app/util/NotificationHelper.kt @@ -113,19 +113,8 @@ object NotificationHelper { markReadPendingIntent ) .setAutoCancel(true) - .setWhen(parseTime(notification.created_at)) + .setWhen(if (notification.created_at_timestamp > 0) notification.created_at_timestamp * 1000L else System.currentTimeMillis()) NotificationManagerCompat.from(context).notify(notification.id, built.build()) } - - private fun parseTime(time: String?): Long { - if (time == null) return System.currentTimeMillis() - return try { - java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.US).apply { - timeZone = java.util.TimeZone.getTimeZone("UTC") - }.parse(time)?.time ?: System.currentTimeMillis() - } catch (_: Exception) { - System.currentTimeMillis() - } - } } diff --git a/android/app/src/main/java/com/devlab/app/util/NotificationPoller.kt b/android/app/src/main/java/com/devlab/app/util/NotificationPoller.kt index d76bf0b..82e6e6c 100644 --- a/android/app/src/main/java/com/devlab/app/util/NotificationPoller.kt +++ b/android/app/src/main/java/com/devlab/app/util/NotificationPoller.kt @@ -3,7 +3,6 @@ package com.devlab.app.util import android.content.Context import android.util.Log import com.devlab.app.data.api.RetrofitClient -import com.devlab.app.data.model.AppNotification import kotlinx.coroutines.* class NotificationPoller(private val context: Context) { @@ -56,7 +55,7 @@ class NotificationPoller(private val context: Context) { onCountChanged?.invoke(_unreadCount) val newNotes = response.data.filter { note -> - val noteTime = parseTime(note.created_at) + val noteTime = note.created_at_timestamp * 1000L noteTime > lastCheck && note.is_read == 0 } @@ -65,20 +64,10 @@ class NotificationPoller(private val context: Context) { } if (newNotes.isNotEmpty()) { - lastCheck = newNotes.maxOf { parseTime(it.created_at) } + lastCheck = newNotes.maxOf { it.created_at_timestamp * 1000L } } } } catch (_: Exception) { } } } - - private fun parseTime(time: String?): Long { - if (time == null) return 0L - return try { - val sdf = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.US).apply { - timeZone = java.util.TimeZone.getTimeZone("UTC") - } - sdf.parse(time)?.time ?: 0L - } catch (_: Exception) { 0L } - } } diff --git a/android/app/src/main/java/com/devlab/app/worker/NotificationWorker.kt b/android/app/src/main/java/com/devlab/app/worker/NotificationWorker.kt index 1780a79..8450817 100644 --- a/android/app/src/main/java/com/devlab/app/worker/NotificationWorker.kt +++ b/android/app/src/main/java/com/devlab/app/worker/NotificationWorker.kt @@ -4,7 +4,6 @@ import android.content.Context import android.util.Log import androidx.work.* import com.devlab.app.data.api.RetrofitClient -import com.devlab.app.data.model.AppNotification import com.devlab.app.util.NotificationHelper import com.devlab.app.util.PreferencesManager import kotlinx.coroutines.Dispatchers @@ -40,7 +39,7 @@ class NotificationWorker( Log.d("NotificationWorker", "Got ${response.data.size} notifications, unread: ${response.unread_count}") val newNotifications = response.data.filter { note -> - val noteTime = parseTime(note.created_at) + val noteTime = note.created_at_timestamp * 1000L noteTime > lastCheck && note.is_read == 0 } @@ -51,7 +50,7 @@ class NotificationWorker( } val maxTime = newNotifications.maxOfOrNull { - parseTime(it.created_at) + it.created_at_timestamp * 1000L } ?: now prefs.setLastNotificationCheck( @@ -71,18 +70,6 @@ class NotificationWorker( } } - private fun parseTime(time: String?): Long { - if (time == null) return 0L - return try { - val sdf = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.US).apply { - timeZone = java.util.TimeZone.getTimeZone("UTC") - } - sdf.parse(time)?.time ?: 0L - } catch (_: Exception) { - 0L - } - } - companion object { private const val WORK_NAME = "notification_check" diff --git a/public/sysadmin.apk b/public/sysadmin.apk index f7ee935..490a157 100644 Binary files a/public/sysadmin.apk and b/public/sysadmin.apk differ diff --git a/src/Controllers/ApiController.php b/src/Controllers/ApiController.php index 71a2579..0121573 100755 --- a/src/Controllers/ApiController.php +++ b/src/Controllers/ApiController.php @@ -701,6 +701,7 @@ class ApiController $data = array_map(function ($n) { $n['time_ago'] = time_ago($n['created_at'] ?? ''); + $n['created_at_timestamp'] = $n['created_at'] ? strtotime($n['created_at']) : 0; return $n; }, $result['data']);