diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 24cf5ec87aa93da3b6eb68f368f4b276a57dd745..036f3e83ee280797b2d2fa82b2ce2f1c2ec52912 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 a6ad2b9fb755fc340a1eb96c21c88a0dc4708055..5e8bc1e29afe9cefe2d3a0afa6402a29c6d29fab 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 0000000000000000000000000000000000000000..bbf7a225b6c8024633518557dbfff5b6b2eaa713 --- /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 3eace85f0832e12fce0cf2201091ba1bdfeb9c3b..b756280b2e8f04b7a4eef3d57e7614828c682d4b 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 ca0aa81d6383bd4a0fccad0625fca1b9176f558b..37c78c8c5c0b91cfcb6ee44ff9bbde80ab9e6751 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 @@ -1,14 +1,15 @@ package com.onionsquad.bondoman.ui.settings +import android.app.AlertDialog import android.os.Bundle import android.view.LayoutInflater 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 @@ -24,14 +25,19 @@ class SettingsFragment : Fragment() { ): View { _binding = FragmentSettingsBinding.inflate(inflater, container, false) - val sessionManager = SessionManager(requireContext()) - binding.apply { logoutButton.setOnClickListener { - sessionManager.deleteAuthToken() - Toast.makeText(requireContext(), "Log out success", Toast.LENGTH_SHORT).show() - findNavController().popBackStack(R.id.navigation_transaction, true) - requireActivity().recreate() + val alertBuilder = AlertDialog.Builder(requireContext()) + alertBuilder.setTitle(R.string.title_alert_logout) + alertBuilder.setMessage(R.string.message_alert_logout) + alertBuilder.setPositiveButton(R.string.yes) { _, _ -> + AutoLogoutWorker.stop(requireContext()) + logout() + } + alertBuilder.setNegativeButton(R.string.no) { dialog, _ -> + dialog.cancel() + } + alertBuilder.show() } } @@ -42,4 +48,12 @@ class SettingsFragment : Fragment() { super.onDestroyView() _binding = null } + + 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) + requireActivity().recreate() + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dfc80c0ba927362dd53849ff4c5986dcce5d03f0..311f02b1f84e12b270a1b2d85afadf307f9caa25 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -13,4 +13,9 @@ <string name="login_failed">"Login failed"</string> <string name="preference_file_key">BondomanSharedPrefs</string> <string name="action_sign_out">Sign out</string> + <string name="title_alert_logout">Confirm sign out</string> + <string name="message_alert_logout">Are you sure you want to sign out?</string> + <string name="log_out_success">Log out success</string> + <string name="yes">Yes</string> + <string name="no">No</string> </resources> \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 29c47e56b19e76de706812cbc86d529a727fa6b8..f97c4635183e36d7327b23cd0961282b2fec0b66 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" }