mirror of
https://github.com/rafaelvcaetano/melonDS-android.git
synced 2025-02-17 04:08:26 +00:00
Add RetroAchievements settings
This commit is contained in:
parent
796e967058
commit
1090f5c259
@ -9,20 +9,27 @@ class AndroidRAUserAuthStore(private val sharedPreferences: SharedPreferences) :
|
||||
|
||||
private companion object {
|
||||
const val USERNAME_KEY = "ra_username"
|
||||
const val USERNAME_TOKEN = "ra_token"
|
||||
const val TOKEN_KEY = "ra_token"
|
||||
}
|
||||
|
||||
override suspend fun storeUserAuth(userAuth: RAUserAuth) {
|
||||
sharedPreferences.edit {
|
||||
putString(USERNAME_KEY, userAuth.username)
|
||||
putString(USERNAME_TOKEN, userAuth.token)
|
||||
putString(TOKEN_KEY, userAuth.token)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getUserAuth(): RAUserAuth? {
|
||||
val username = sharedPreferences.getString(USERNAME_KEY, null) ?: return null
|
||||
val token = sharedPreferences.getString(USERNAME_TOKEN, null) ?: return null
|
||||
val token = sharedPreferences.getString(TOKEN_KEY, null) ?: return null
|
||||
|
||||
return RAUserAuth(username, token)
|
||||
}
|
||||
|
||||
override suspend fun clearUserAuth() {
|
||||
sharedPreferences.edit {
|
||||
remove(USERNAME_KEY)
|
||||
remove(TOKEN_KEY)
|
||||
}
|
||||
}
|
||||
}
|
@ -4,28 +4,34 @@ import androidx.room.*
|
||||
import me.magnum.melonds.database.entities.retroachievements.*
|
||||
|
||||
@Dao
|
||||
interface RAAchievementsDao {
|
||||
abstract class RAAchievementsDao {
|
||||
|
||||
@Query("SELECT * FROM ra_game_set_metadata WHERE game_id = :gameId")
|
||||
suspend fun getGameSetMetadata(gameId: Long): RAGameSetMetadata?
|
||||
abstract suspend fun getGameSetMetadata(gameId: Long): RAGameSetMetadata?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun updateGameSetMetadata(gameSetMetadata: RAGameSetMetadata)
|
||||
abstract suspend fun updateGameSetMetadata(gameSetMetadata: RAGameSetMetadata)
|
||||
|
||||
@Query("UPDATE ra_game_set_metadata SET last_user_data_updated = NULL")
|
||||
protected abstract suspend fun clearAllGameSetMetadataLastUserDataUpdate()
|
||||
|
||||
@Query("SELECT * FROM ra_achievement WHERE game_id = :gameId")
|
||||
suspend fun getGameAchievements(gameId: Long): List<RAAchievementEntity>
|
||||
abstract suspend fun getGameAchievements(gameId: Long): List<RAAchievementEntity>
|
||||
|
||||
@Query("SELECT * FROM ra_achievement WHERE id = :achievementId")
|
||||
abstract suspend fun getAchievement(achievementId: Long): RAAchievementEntity?
|
||||
|
||||
@Query("DELETE FROM ra_achievement WHERE game_id = :gameId")
|
||||
suspend fun deleteGameAchievements(gameId: Long)
|
||||
protected abstract suspend fun deleteGameAchievements(gameId: Long)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertGameAchievements(achievements: List<RAAchievementEntity>)
|
||||
protected abstract suspend fun insertGameAchievements(achievements: List<RAAchievementEntity>)
|
||||
|
||||
@Upsert
|
||||
suspend fun updateGameData(gameData: RAGameEntity)
|
||||
protected abstract suspend fun updateGameData(gameData: RAGameEntity)
|
||||
|
||||
@Transaction
|
||||
suspend fun updateGameData(gameId: Long, achievements: List<RAAchievementEntity>, richPresencePatch: String?) {
|
||||
open suspend fun updateGameData(gameId: Long, achievements: List<RAAchievementEntity>, richPresencePatch: String?) {
|
||||
deleteGameAchievements(gameId)
|
||||
insertGameAchievements(achievements)
|
||||
|
||||
@ -34,50 +40,60 @@ interface RAAchievementsDao {
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM ra_game WHERE game_id = :gameId")
|
||||
suspend fun getGame(gameId: Long): RAGameEntity?
|
||||
abstract suspend fun getGame(gameId: Long): RAGameEntity?
|
||||
|
||||
@Query("SELECT * FROM ra_user_achievement WHERE game_id = :gameId AND is_unlocked = 1")
|
||||
suspend fun getGameUserUnlockedAchievements(gameId: Long): List<RAUserAchievementEntity>
|
||||
abstract suspend fun getGameUserUnlockedAchievements(gameId: Long): List<RAUserAchievementEntity>
|
||||
|
||||
@Query("DELETE FROM ra_user_achievement WHERE game_id = :gameId")
|
||||
suspend fun deleteGameUserUnlockedAchievements(gameId: Long)
|
||||
protected abstract suspend fun deleteGameUserUnlockedAchievements(gameId: Long)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun addUserAchievement(userAchievement: RAUserAchievementEntity)
|
||||
abstract suspend fun addUserAchievement(userAchievement: RAUserAchievementEntity)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertGameUserUnlockedAchievements(userAchievements: List<RAUserAchievementEntity>)
|
||||
protected abstract suspend fun insertGameUserUnlockedAchievements(userAchievements: List<RAUserAchievementEntity>)
|
||||
|
||||
@Transaction
|
||||
suspend fun updateGameUserUnlockedAchievements(gameId: Long, userAchievements: List<RAUserAchievementEntity>) {
|
||||
open suspend fun updateGameUserUnlockedAchievements(gameId: Long, userAchievements: List<RAUserAchievementEntity>) {
|
||||
deleteGameUserUnlockedAchievements(gameId)
|
||||
insertGameUserUnlockedAchievements(userAchievements)
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM ra_achievement WHERE id = :achievementId")
|
||||
suspend fun getAchievement(achievementId: Long): RAAchievementEntity?
|
||||
@Query("DELETE FROM ra_user_achievement")
|
||||
protected abstract suspend fun deleteAllUserUnlockedAchievements()
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun addPendingAchievementSubmission(pendingAchievementSubmission: RAPendingAchievementSubmissionEntity)
|
||||
abstract suspend fun addPendingAchievementSubmission(pendingAchievementSubmission: RAPendingAchievementSubmissionEntity)
|
||||
|
||||
@Query("SELECT * FROM ra_pending_achievement_award")
|
||||
suspend fun getPendingAchievementSubmissions(): List<RAPendingAchievementSubmissionEntity>
|
||||
abstract suspend fun getPendingAchievementSubmissions(): List<RAPendingAchievementSubmissionEntity>
|
||||
|
||||
@Delete
|
||||
suspend fun removePendingAchievementSubmission(pendingAchievementSubmission: RAPendingAchievementSubmissionEntity)
|
||||
abstract suspend fun removePendingAchievementSubmission(pendingAchievementSubmission: RAPendingAchievementSubmissionEntity)
|
||||
|
||||
@Query("DELETE FROM ra_pending_achievement_award")
|
||||
protected abstract suspend fun deleteAllPendingAchievementSubmissions()
|
||||
|
||||
@Query("DELETE FROM ra_game_hash_library")
|
||||
suspend fun deleteGameHashLibrary()
|
||||
abstract suspend fun deleteGameHashLibrary()
|
||||
|
||||
@Insert
|
||||
suspend fun insertGameHashLibrary(hashLibrary: List<RAGameHashEntity>)
|
||||
abstract suspend fun insertGameHashLibrary(hashLibrary: List<RAGameHashEntity>)
|
||||
|
||||
@Query("SELECT * FROM ra_game_hash_library WHERE game_hash = :gameHash")
|
||||
suspend fun getGameHashEntity(gameHash: String): RAGameHashEntity?
|
||||
abstract suspend fun getGameHashEntity(gameHash: String): RAGameHashEntity?
|
||||
|
||||
@Transaction
|
||||
suspend fun updateGameHashLibrary(hashLibrary: List<RAGameHashEntity>) {
|
||||
open suspend fun updateGameHashLibrary(hashLibrary: List<RAGameHashEntity>) {
|
||||
deleteGameHashLibrary()
|
||||
insertGameHashLibrary(hashLibrary)
|
||||
}
|
||||
|
||||
@Transaction
|
||||
open suspend fun deleteAllAchievementUserData() {
|
||||
clearAllGameSetMetadataLastUserDataUpdate()
|
||||
deleteAllUserUnlockedAchievements()
|
||||
deleteAllPendingAchievementSubmissions()
|
||||
}
|
||||
}
|
@ -2,10 +2,13 @@ package me.magnum.melonds.domain.repositories
|
||||
|
||||
import me.magnum.melonds.domain.model.retroachievements.RAUserAchievement
|
||||
import me.magnum.rcheevosapi.model.RAAchievement
|
||||
import me.magnum.rcheevosapi.model.RAUserAuth
|
||||
|
||||
interface RetroAchievementsRepository {
|
||||
suspend fun isUserAuthenticated(): Boolean
|
||||
suspend fun getUserAuthentication(): RAUserAuth?
|
||||
suspend fun login(username: String, password: String): Result<Unit>
|
||||
suspend fun logout()
|
||||
suspend fun getGameUserAchievements(gameHash: String): Result<List<RAUserAchievement>>
|
||||
suspend fun getGameRichPresencePatch(gameHash: String): String?
|
||||
suspend fun getAchievement(achievementId: Long): Result<RAAchievement?>
|
||||
|
@ -50,6 +50,8 @@ interface SettingsRepository {
|
||||
fun getTouchHapticFeedbackStrength(): Int
|
||||
fun getSoftInputOpacity(): Int
|
||||
|
||||
fun isRetroAchievementsRichPresenceEnabled(): Boolean
|
||||
|
||||
fun areCheatsEnabled(): Boolean
|
||||
|
||||
fun observeTheme(): Observable<Theme>
|
||||
|
@ -12,12 +12,14 @@ import me.magnum.melonds.database.entities.retroachievements.RAPendingAchievemen
|
||||
import me.magnum.melonds.database.entities.retroachievements.RAUserAchievementEntity
|
||||
import me.magnum.melonds.domain.model.retroachievements.RAUserAchievement
|
||||
import me.magnum.melonds.domain.repositories.RetroAchievementsRepository
|
||||
import me.magnum.melonds.domain.repositories.SettingsRepository
|
||||
import me.magnum.melonds.impl.mappers.retroachievements.mapToEntity
|
||||
import me.magnum.melonds.impl.mappers.retroachievements.mapToModel
|
||||
import me.magnum.rcheevosapi.RAApi
|
||||
import me.magnum.rcheevosapi.RAUserAuthStore
|
||||
import me.magnum.rcheevosapi.model.RAAchievement
|
||||
import me.magnum.rcheevosapi.model.RAGameId
|
||||
import me.magnum.rcheevosapi.model.RAUserAuth
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -26,6 +28,7 @@ class AndroidRetroAchievementsRepository(
|
||||
private val raApi: RAApi,
|
||||
private val achievementsDao: RAAchievementsDao,
|
||||
private val raUserAuthStore: RAUserAuthStore,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val sharedPreferences: SharedPreferences,
|
||||
private val context: Context,
|
||||
) : RetroAchievementsRepository {
|
||||
@ -39,10 +42,19 @@ class AndroidRetroAchievementsRepository(
|
||||
return raUserAuthStore.getUserAuth() != null
|
||||
}
|
||||
|
||||
override suspend fun getUserAuthentication(): RAUserAuth? {
|
||||
return raUserAuthStore.getUserAuth()
|
||||
}
|
||||
|
||||
override suspend fun login(username: String, password: String): Result<Unit> {
|
||||
return raApi.login(username, password)
|
||||
}
|
||||
|
||||
override suspend fun logout() {
|
||||
achievementsDao.deleteAllAchievementUserData()
|
||||
raUserAuthStore.clearUserAuth()
|
||||
}
|
||||
|
||||
override suspend fun getGameUserAchievements(gameHash: String): Result<List<RAUserAchievement>> {
|
||||
val gameIdResult = getGameIdFromGameHash(gameHash)
|
||||
if (gameIdResult.isFailure) {
|
||||
@ -80,6 +92,10 @@ class AndroidRetroAchievementsRepository(
|
||||
}
|
||||
|
||||
override suspend fun getGameRichPresencePatch(gameHash: String): String? {
|
||||
if (!settingsRepository.isRetroAchievementsRichPresenceEnabled()) {
|
||||
return null
|
||||
}
|
||||
|
||||
val gameId = getGameIdFromGameHash(gameHash).getOrNull() ?: return null
|
||||
return achievementsDao.getGame(gameId.id)?.richPresencePatch
|
||||
}
|
||||
|
@ -366,6 +366,10 @@ class SharedPreferencesSettingsRepository(
|
||||
return preferences.getInt("input_opacity", 50)
|
||||
}
|
||||
|
||||
override fun isRetroAchievementsRichPresenceEnabled(): Boolean {
|
||||
return preferences.getBoolean("ra_rich_presence", true)
|
||||
}
|
||||
|
||||
override fun areCheatsEnabled(): Boolean {
|
||||
return preferences.getBoolean("cheats_enabled", false)
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package me.magnum.melonds.ui.common
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import me.magnum.melonds.R
|
||||
|
||||
class LoadingDialog(context: Context) : Dialog(context) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.dialog_loading)
|
||||
setCancelable(false)
|
||||
setCanceledOnTouchOutside(false)
|
||||
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package me.magnum.melonds.ui.settings
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import me.magnum.melonds.domain.repositories.RetroAchievementsRepository
|
||||
import me.magnum.melonds.ui.settings.model.RetroAchievementsAccountState
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class RetroAchievementsSettingsViewModel @Inject constructor(
|
||||
private val retroAchievementsRepository: RetroAchievementsRepository,
|
||||
): ViewModel() {
|
||||
|
||||
private val _accountState = MutableStateFlow<RetroAchievementsAccountState>(RetroAchievementsAccountState.Unknown)
|
||||
val accountState by lazy {
|
||||
viewModelScope.launch {
|
||||
updateLoggedInState()
|
||||
}
|
||||
_accountState.asStateFlow()
|
||||
}
|
||||
|
||||
private val _loggingIn = MutableStateFlow(false)
|
||||
val loggingIn = _loggingIn.asStateFlow()
|
||||
|
||||
private val _loginErrorEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
val loginErrorEvent = _loginErrorEvent.asSharedFlow()
|
||||
|
||||
fun logoutFromRetroAchievements() {
|
||||
viewModelScope.launch {
|
||||
retroAchievementsRepository.logout()
|
||||
_accountState.value = RetroAchievementsAccountState.LoggedOut
|
||||
}
|
||||
}
|
||||
|
||||
fun login(username: String, password: String) {
|
||||
viewModelScope.launch {
|
||||
_loggingIn.value = true
|
||||
retroAchievementsRepository.login(username, password)
|
||||
.onSuccess {
|
||||
updateLoggedInState()
|
||||
}
|
||||
.onFailure {
|
||||
_loginErrorEvent.tryEmit(Unit)
|
||||
}
|
||||
_loggingIn.value = false
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateLoggedInState() {
|
||||
val userAuth = retroAchievementsRepository.getUserAuthentication()
|
||||
if (userAuth == null) {
|
||||
_accountState.value = RetroAchievementsAccountState.LoggedOut
|
||||
} else {
|
||||
_accountState.value = RetroAchievementsAccountState.LoggedIn(userAuth.username)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
package me.magnum.melonds.ui.settings.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import kotlinx.coroutines.launch
|
||||
import me.magnum.melonds.R
|
||||
import me.magnum.melonds.databinding.DialogRetroachievementsLoginBinding
|
||||
import me.magnum.melonds.ui.common.LoadingDialog
|
||||
import me.magnum.melonds.ui.settings.PreferenceFragmentTitleProvider
|
||||
import me.magnum.melonds.ui.settings.RetroAchievementsSettingsViewModel
|
||||
import me.magnum.melonds.ui.settings.model.RetroAchievementsAccountState
|
||||
|
||||
class RetroAchievementsPreferencesFragment : PreferenceFragmentCompat(), PreferenceFragmentTitleProvider {
|
||||
|
||||
private val viewModel by activityViewModels<RetroAchievementsSettingsViewModel>()
|
||||
|
||||
private lateinit var accountPreference: Preference
|
||||
|
||||
private var loginProgressDialog: LoadingDialog? = null
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.pref_retroachievements, rootKey)
|
||||
|
||||
accountPreference = findPreference("ra_login")!!
|
||||
accountPreference.setOnPreferenceClickListener {
|
||||
val accountState = viewModel.accountState.value
|
||||
when (accountState) {
|
||||
is RetroAchievementsAccountState.LoggedIn -> showLogoutConfirmationDialog()
|
||||
RetroAchievementsAccountState.LoggedOut -> showLoginDialog()
|
||||
RetroAchievementsAccountState.Unknown -> {
|
||||
// Do nothing until a proper state is known
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel.accountState.collect {
|
||||
when (it) {
|
||||
is RetroAchievementsAccountState.LoggedIn -> {
|
||||
accountPreference.title = getString(R.string.retroachievements_logout)
|
||||
accountPreference.summary = getString(R.string.retroachievements_login_status, it.accountName)
|
||||
}
|
||||
RetroAchievementsAccountState.LoggedOut -> {
|
||||
accountPreference.title = getString(R.string.login_with_retro_achievements)
|
||||
accountPreference.summary = getString(R.string.retroachievements_login_summary)
|
||||
}
|
||||
RetroAchievementsAccountState.Unknown -> {
|
||||
accountPreference.title = getString(R.string.ellipsis)
|
||||
accountPreference.summary = getString(R.string.ellipsis)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel.loggingIn.collect { loggingIn ->
|
||||
loginProgressDialog = if (loggingIn) {
|
||||
LoadingDialog(requireContext()).apply {
|
||||
show()
|
||||
}
|
||||
} else {
|
||||
loginProgressDialog?.dismiss()
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
viewModel.loginErrorEvent.collect {
|
||||
Toast.makeText(requireContext(), R.string.retro_achievements_login_error_short, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLoginDialog() {
|
||||
val binding = DialogRetroachievementsLoginBinding.inflate(LayoutInflater.from(context))
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.login_with_retro_achievements)
|
||||
.setView(binding.root)
|
||||
.setPositiveButton(R.string.login) { dialog, _ ->
|
||||
viewModel.login(
|
||||
binding.textUsername.text?.toString() ?: "",
|
||||
binding.textPassword.text?.toString() ?: "",
|
||||
)
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun showLogoutConfirmationDialog() {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.retroachievements_logout)
|
||||
.setMessage(R.string.retroachievements_logout_confirmation)
|
||||
.setPositiveButton(R.string.retroachievements_logout) { dialog, _ ->
|
||||
viewModel.logoutFromRetroAchievements()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun getTitle() = getString(R.string.retroachievements)
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package me.magnum.melonds.ui.settings.model
|
||||
|
||||
sealed class RetroAchievementsAccountState {
|
||||
object Unknown : RetroAchievementsAccountState()
|
||||
object LoggedOut : RetroAchievementsAccountState()
|
||||
data class LoggedIn(val accountName: String) : RetroAchievementsAccountState()
|
||||
}
|
5
app/src/main/res/drawable/ic_trophy.xml
Normal file
5
app/src/main/res/drawable/ic_trophy.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19,5h-2V3H7v2H5C3.9,5 3,5.9 3,7v1c0,2.55 1.92,4.63 4.39,4.94c0.63,1.5 1.98,2.63 3.61,2.96V19H7v2h10v-2h-4v-3.1c1.63,-0.33 2.98,-1.46 3.61,-2.96C19.08,12.63 21,10.55 21,8V7C21,5.9 20.1,5 19,5zM5,8V7h2v3.82C5.84,10.4 5,9.3 5,8zM19,8c0,1.3 -0.84,2.4 -2,2.82V7h2V8z"/>
|
||||
</vector>
|
11
app/src/main/res/layout/dialog_loading.xml
Normal file
11
app/src/main/res/layout/dialog_loading.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true" />
|
||||
</FrameLayout>
|
26
app/src/main/res/layout/dialog_retroachievements_login.xml
Normal file
26
app/src/main/res/layout/dialog_retroachievements_login.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingStart="?attr/dialogPreferredPadding"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding"
|
||||
android:orientation="vertical">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/text_username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/username"
|
||||
android:inputType="text"
|
||||
android:autofillHints="username" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/text_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:hint="@string/password"
|
||||
android:inputType="textPassword"
|
||||
android:autofillHints="password" />
|
||||
</LinearLayout>
|
@ -17,6 +17,7 @@
|
||||
<string name="update">Update</string>
|
||||
<string name="close">Close</string>
|
||||
<string name="play">Play</string>
|
||||
<string name="ellipsis">…</string>
|
||||
|
||||
<string name="version_alpha">Alpha</string>
|
||||
<string name="version_beta">Beta</string>
|
||||
@ -191,6 +192,10 @@
|
||||
<string name="vibrate_on_touch">Vibrate on touch</string>
|
||||
<string name="vibration_strength">Vibration strength</string>
|
||||
<string name="soft_input_opacity">Soft input opacity</string>
|
||||
<string name="retroachievements">RetroAchievements</string> <!-- Keep words together because this is the official name -->
|
||||
<string name="retroachievements_summary">Login & manage RetroAchievements integration</string> <!-- Keep words together because this is the official name -->
|
||||
<string name="enable_rich_presence">Enable rich presence</string>
|
||||
<string name="rich_presence_summary">Allows other RetroAchievement users to see what you are playing</string>
|
||||
<string name="cheats">Cheats</string>
|
||||
<string name="cheats_summary">Enable & import cheat codes</string>
|
||||
<string name="enable_cheats">Enable cheats</string>
|
||||
@ -294,7 +299,12 @@
|
||||
<string name="retro_achievements_login_description">Login with RetroAchievements to view achievements that you can unlock while playing this game!</string>
|
||||
<string name="login_with_retro_achievements">Login with RetroAchievements</string>
|
||||
<string name="login">Login</string>
|
||||
<string name="retroachievements_login_summary">Login with RetroAchievements to unlock achievements while playing!</string>
|
||||
<string name="retroachievements_login_status">Logged in as %1$s</string>
|
||||
<string name="retroachievements_logout">Logout</string>
|
||||
<string name="retroachievements_logout_confirmation">Are you sure you want to logout from RetroAchievements? You won\'t be able to unlock achievements while playing.</string>
|
||||
<string name="retro_achievements_login_error">There was a problem when trying to login. Make sure that your username and password are correct, and that you are connected to the internet</string>
|
||||
<string name="retro_achievements_login_error_short">There was a problem when trying to login</string>
|
||||
<string name="retro_achievements_load_error">There was a problem when trying to load the achievements for this game. Make sure you are connected to the internet and try again later</string>
|
||||
<string name="retro_achievements_no_achievements">No RetroAchievements were found for this game</string>
|
||||
<string name="username">Username</string>
|
||||
|
@ -43,6 +43,12 @@
|
||||
app:icon="@drawable/ic_input"
|
||||
android:fragment="me.magnum.melonds.ui.settings.fragments.InputPreferencesFragment" />
|
||||
|
||||
<Preference
|
||||
android:title="@string/retroachievements"
|
||||
android:summary="@string/retroachievements_summary"
|
||||
app:icon="@drawable/ic_trophy"
|
||||
android:fragment="me.magnum.melonds.ui.settings.fragments.RetroAchievementsPreferencesFragment" />
|
||||
|
||||
<Preference
|
||||
android:title="@string/cheats"
|
||||
android:summary="@string/cheats_summary"
|
||||
|
16
app/src/main/res/xml/pref_retroachievements.xml
Normal file
16
app/src/main/res/xml/pref_retroachievements.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<Preference
|
||||
android:key="ra_login"
|
||||
android:title="@string/login_with_retro_achievements"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="ra_rich_presence"
|
||||
android:title="@string/enable_rich_presence"
|
||||
android:summary="@string/rich_presence_summary"
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="true" />
|
||||
</PreferenceScreen>
|
@ -5,4 +5,5 @@ import me.magnum.rcheevosapi.model.RAUserAuth
|
||||
interface RAUserAuthStore {
|
||||
suspend fun storeUserAuth(userAuth: RAUserAuth)
|
||||
suspend fun getUserAuth(): RAUserAuth?
|
||||
suspend fun clearUserAuth()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user