From f1d53ffa4af2e88754f78fab20b3b94e3d76ed4a Mon Sep 17 00:00:00 2001
From: "Moch. Sofyan Firdaus" <13521083@std.stei.itb.ac.id>
Date: Wed, 3 Apr 2024 22:24:54 +0700
Subject: [PATCH] feat: add auto logout background service

---
 app/build.gradle.kts                          |  3 +
 .../com/onionsquad/bondoman/MainActivity.kt   |  3 +
 .../bondoman/auth/AutoLogoutWorker.kt         | 58 +++++++++++++++++++
 .../bondoman/ui/login/LoginActivity.kt        |  8 +++
 .../bondoman/ui/settings/SettingsFragment.kt  | 10 ++--
 gradle/libs.versions.toml                     |  2 +
 6 files changed, 79 insertions(+), 5 deletions(-)
 create mode 100644 app/src/main/java/com/onionsquad/bondoman/auth/AutoLogoutWorker.kt

diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 24cf5ec..036f3e8 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -55,4 +55,7 @@ dependencies {
     implementation(libs.retrofit2.converter.gson)
     implementation(libs.retrofit2.converter.scalars)
     implementation(libs.okhttp3)
+
+    // Work
+    implementation(libs.androidx.work.runtime)
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/MainActivity.kt b/app/src/main/java/com/onionsquad/bondoman/MainActivity.kt
index a6ad2b9..5e8bc1e 100644
--- a/app/src/main/java/com/onionsquad/bondoman/MainActivity.kt
+++ b/app/src/main/java/com/onionsquad/bondoman/MainActivity.kt
@@ -8,6 +8,7 @@ import androidx.navigation.ui.AppBarConfiguration
 import androidx.navigation.ui.setupActionBarWithNavController
 import androidx.navigation.ui.setupWithNavController
 import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.onionsquad.bondoman.auth.AutoLogoutWorker
 import com.onionsquad.bondoman.auth.SessionManager
 import com.onionsquad.bondoman.databinding.ActivityMainBinding
 import com.onionsquad.bondoman.ui.login.LoginActivity
@@ -19,6 +20,8 @@ class MainActivity : AppCompatActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
+        AutoLogoutWorker.start(this)
+
         val sessionManager = SessionManager(this)
         if (sessionManager.fetchAuthToken() == null) {
             sendToLoginActivity()
diff --git a/app/src/main/java/com/onionsquad/bondoman/auth/AutoLogoutWorker.kt b/app/src/main/java/com/onionsquad/bondoman/auth/AutoLogoutWorker.kt
new file mode 100644
index 0000000..bbf7a22
--- /dev/null
+++ b/app/src/main/java/com/onionsquad/bondoman/auth/AutoLogoutWorker.kt
@@ -0,0 +1,58 @@
+package com.onionsquad.bondoman.auth
+
+import android.content.Context
+import android.util.Log
+import androidx.work.ExistingWorkPolicy
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkManager
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import java.time.Instant
+import java.util.concurrent.TimeUnit
+import kotlin.math.max
+
+
+class AutoLogoutWorker(
+    private val context: Context,
+    private val workerParameters: WorkerParameters
+) : Worker(context, workerParameters) {
+
+    override fun doWork(): Result {
+        Log.d(this::class.java.simpleName, "Proceed auto logout")
+        val sessionManager = SessionManager(context)
+        sessionManager.deleteAuthToken()
+        return Result.success()
+    }
+
+    companion object {
+        fun start(context: Context) {
+            Log.d(AutoLogoutWorker::class.java.simpleName, "Starting auto logout worker")
+            val sessionManager = SessionManager(context)
+            val token = sessionManager.fetchAuthToken()
+            if (token != null) {
+                val duration = max(0, token.exp - Instant.now().epochSecond)
+                Log.d(AutoLogoutWorker::class.java.simpleName, "Proceed to logout in $duration secs")
+                val workRequest = OneTimeWorkRequestBuilder<AutoLogoutWorker>()
+                    .setInitialDelay(duration, TimeUnit.SECONDS)
+                    .build()
+                WorkManager
+                    .getInstance(context)
+                    .enqueueUniqueWork(
+                        AutoLogoutWorker::class.java.simpleName,
+                        ExistingWorkPolicy.REPLACE,
+                        workRequest
+                    )
+            } else {
+                stop(context)
+            }
+        }
+
+        fun stop(context: Context) {
+            Log.d(AutoLogoutWorker::class.java.simpleName, "Stopping auto logout worker")
+            WorkManager
+                .getInstance(context)
+                .cancelUniqueWork(AutoLogoutWorker::class.java.simpleName)
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/login/LoginActivity.kt b/app/src/main/java/com/onionsquad/bondoman/ui/login/LoginActivity.kt
index 3eace85..b756280 100644
--- a/app/src/main/java/com/onionsquad/bondoman/ui/login/LoginActivity.kt
+++ b/app/src/main/java/com/onionsquad/bondoman/ui/login/LoginActivity.kt
@@ -12,11 +12,18 @@ import android.view.View
 import android.view.inputmethod.EditorInfo
 import android.widget.EditText
 import android.widget.Toast
+import androidx.work.ExistingWorkPolicy
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.PeriodicWorkRequestBuilder
+import androidx.work.WorkManager
 import com.onionsquad.bondoman.MainActivity
 import com.onionsquad.bondoman.databinding.ActivityLoginBinding
 
 import com.onionsquad.bondoman.R
+import com.onionsquad.bondoman.auth.AutoLogoutWorker
 import com.onionsquad.bondoman.auth.SessionManager
+import java.time.Instant
+import java.util.concurrent.TimeUnit
 
 class LoginActivity : AppCompatActivity() {
 
@@ -56,6 +63,7 @@ class LoginActivity : AppCompatActivity() {
                     }
                     if (loginResult.success != null) {
                         sessionManager.saveAuthToken(loginResult.success)
+                        AutoLogoutWorker.start(this@LoginActivity)
                         showLoginSuccess()
                         sendToMainActivity()
                     }
diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/settings/SettingsFragment.kt b/app/src/main/java/com/onionsquad/bondoman/ui/settings/SettingsFragment.kt
index 8599805..37c78c8 100644
--- a/app/src/main/java/com/onionsquad/bondoman/ui/settings/SettingsFragment.kt
+++ b/app/src/main/java/com/onionsquad/bondoman/ui/settings/SettingsFragment.kt
@@ -7,9 +7,9 @@ import android.view.View
 import android.view.ViewGroup
 import android.widget.Toast
 import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
 import androidx.navigation.fragment.findNavController
 import com.onionsquad.bondoman.R
+import com.onionsquad.bondoman.auth.AutoLogoutWorker
 import com.onionsquad.bondoman.auth.SessionManager
 import com.onionsquad.bondoman.databinding.FragmentSettingsBinding
 
@@ -25,15 +25,14 @@ class SettingsFragment : Fragment() {
     ): View {
         _binding = FragmentSettingsBinding.inflate(inflater, container, false)
 
-        val sessionManager = SessionManager(requireContext())
-
         binding.apply {
             logoutButton.setOnClickListener {
                 val alertBuilder = AlertDialog.Builder(requireContext())
                 alertBuilder.setTitle(R.string.title_alert_logout)
                 alertBuilder.setMessage(R.string.message_alert_logout)
                 alertBuilder.setPositiveButton(R.string.yes) { _, _ ->
-                    logout(sessionManager)
+                    AutoLogoutWorker.stop(requireContext())
+                    logout()
                 }
                 alertBuilder.setNegativeButton(R.string.no) { dialog, _ ->
                     dialog.cancel()
@@ -50,7 +49,8 @@ class SettingsFragment : Fragment() {
         _binding = null
     }
 
-    private fun logout(sessionManager: SessionManager) {
+    private fun logout() {
+        val sessionManager = SessionManager(requireContext())
         sessionManager.deleteAuthToken()
         Toast.makeText(requireContext(), R.string.log_out_success, Toast.LENGTH_SHORT).show()
         findNavController().popBackStack(R.id.navigation_transaction, true)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 29c47e5..f97c463 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -15,6 +15,7 @@ navigationUiKtx = "2.6.0"
 retrofit = "2.11.0"
 okhttp3 = "4.12.0"
 annotation = "1.7.1"
+work = "2.9.0"
 
 [libraries]
 androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -33,6 +34,7 @@ retrofit2-converter-scalars = { group = "com.squareup.retrofit2", name = "conver
 retrofit2-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
 okhttp3 = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp3"  }
 androidx-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotation" }
+androidx-work-runtime = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "work" }
 
 [plugins]
 androidApplication = { id = "com.android.application", version.ref = "agp" }
-- 
GitLab