diff --git a/Habitica/res/layout/dialog_achievement_detail.xml b/Habitica/res/layout/dialog_achievement_detail.xml new file mode 100644 index 000000000..bb6805767 --- /dev/null +++ b/Habitica/res/layout/dialog_achievement_detail.xml @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt index 7ce40d956..eb998a571 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabiticaBaseApplication.kt @@ -244,7 +244,7 @@ abstract class HabiticaBaseApplication : MultiDexApplication() { } fun checkUserAuthentication(context: Context, hostConfig: HostConfig?): Boolean { - if (hostConfig?.api == null || hostConfig.api == "" || hostConfig.user == "") { + if (hostConfig?.apiKey == null || hostConfig.apiKey == "" || hostConfig.userID == "") { startActivity(IntroActivity::class.java, context) return false diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/api/HostConfig.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/api/HostConfig.kt index 95c73cfed..7fdff9ccf 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/api/HostConfig.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/api/HostConfig.kt @@ -2,10 +2,11 @@ package com.habitrpg.android.habitica.api import android.content.Context import android.content.SharedPreferences -import android.preference.PreferenceManager - +import androidx.core.content.edit import com.habitrpg.android.habitica.BuildConfig import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.helpers.KeyHelper + /** * The configuration of the host

@@ -16,11 +17,10 @@ import com.habitrpg.android.habitica.R class HostConfig { var address: String var port: String - var api: String - var user: String + var apiKey: String + var userID: String - constructor(sharedPreferences: SharedPreferences, context: Context) { - val prefs = PreferenceManager.getDefaultSharedPreferences(context) + constructor(sharedPreferences: SharedPreferences, keyHelper: KeyHelper?, context: Context) { this.port = BuildConfig.PORT if (BuildConfig.DEBUG) { this.address = BuildConfig.BASE_URL @@ -32,19 +32,41 @@ class HostConfig { this.address = context.getString(R.string.base_url) } } - this.api = prefs.getString("APIToken", null) ?: "" - this.user = prefs.getString(context.getString(R.string.SP_userID), null) ?: "" + this.userID = sharedPreferences.getString(context.getString(R.string.SP_userID), null) ?: "" + + this.apiKey = loadAPIKey(sharedPreferences, keyHelper) + } + + private fun loadAPIKey(sharedPreferences: SharedPreferences, keyHelper: KeyHelper?): String { + return if (sharedPreferences.contains(userID)) { + val encryptedKey = sharedPreferences.getString(userID, null) + if (encryptedKey?.isNotBlank() == true) { + keyHelper?.decrypt(encryptedKey) + } else { + "" + } + } else { + val key = sharedPreferences.getString("APIToken", null) + if (key?.isNotBlank() == true) { + val encryptedKey = keyHelper?.encrypt(key) + sharedPreferences.edit { + putString(userID, encryptedKey) + remove("APIToken") + } + } + key + } ?: "" } constructor(address: String, port: String, api: String, user: String) { this.address = address this.port = port - this.api = api - this.user = user + this.apiKey = api + this.userID = user } fun hasAuthentication(): Boolean { - return user.isNotEmpty() && api.isNotEmpty() + return userID.isNotEmpty() && apiKey.isNotEmpty() } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt index dcbc7e4b5..25154888f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt @@ -90,9 +90,9 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener; this.popupNotificationsManager.setApiClient(this) HabiticaBaseApplication.component?.inject(this) - crashlyticsProxy.setUserIdentifier(this.hostConfig.user) - crashlyticsProxy.setUserName(this.hostConfig.user) - Amplitude.getInstance().userId = this.hostConfig.user + crashlyticsProxy.setUserIdentifier(this.hostConfig.userID) + crashlyticsProxy.setUserName(this.hostConfig.userID) + Amplitude.getInstance().userId = this.hostConfig.userID buildRetrofit() } @@ -115,8 +115,8 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener; var builder: Request.Builder = original.newBuilder() if (this.hostConfig.hasAuthentication()) { builder = builder - .header("x-api-key", this.hostConfig.api) - .header("x-api-user", this.hostConfig.user) + .header("x-api-key", this.hostConfig.apiKey) + .header("x-api-user", this.hostConfig.userID) } builder = builder.header("x-client", "habitica-android") .header("x-user-timezoneOffset", timezoneOffset.toString()) @@ -256,7 +256,7 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener; } override fun hasAuthenticationKeys(): Boolean { - return this.hostConfig.user.isNotEmpty() && hostConfig.api.isNotEmpty() + return this.hostConfig.userID.isNotEmpty() && hostConfig.apiKey.isNotEmpty() } private fun showConnectionProblemDialog(resourceMessageString: Int) { @@ -282,11 +282,11 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener; } override fun updateAuthenticationCredentials(userID: String?, apiToken: String?) { - this.hostConfig.user = userID ?: "" - this.hostConfig.api = apiToken ?: "" - crashlyticsProxy.setUserIdentifier(this.hostConfig.user) - crashlyticsProxy.setUserName(this.hostConfig.user) - Amplitude.getInstance().userId = this.hostConfig.user + this.hostConfig.userID = userID ?: "" + this.hostConfig.apiKey = apiToken ?: "" + crashlyticsProxy.setUserIdentifier(this.hostConfig.userID) + crashlyticsProxy.setUserName(this.hostConfig.userID) + Amplitude.getInstance().userId = this.hostConfig.userID } override fun setLanguageCode(languageCode: String) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AlertDialog-Extensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AlertDialog-Extensions.kt index d4d420c11..e507c5a08 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AlertDialog-Extensions.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/AlertDialog-Extensions.kt @@ -2,7 +2,7 @@ package com.habitrpg.android.habitica.extensions import android.content.DialogInterface import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog fun HabiticaAlertDialog.addOkButton(isPrimary: Boolean = true, listener: ((HabiticaAlertDialog, Int) -> Unit)? = null) { this.addButton(R.string.ok, isPrimary, listener) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/Keyhelper.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/Keyhelper.kt new file mode 100644 index 000000000..4f2cd0b55 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/Keyhelper.kt @@ -0,0 +1,245 @@ +package com.habitrpg.android.habitica.helpers + +import android.content.Context +import android.content.SharedPreferences +import android.os.Build +import android.security.KeyPairGeneratorSpec +import android.security.keystore.KeyGenParameterSpec +import android.security.keystore.KeyProperties +import android.util.Base64 +import androidx.core.content.edit +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.IOException +import java.io.UnsupportedEncodingException +import java.math.BigInteger +import java.security.* +import java.util.* +import javax.crypto.* +import javax.crypto.spec.GCMParameterSpec +import javax.crypto.spec.SecretKeySpec +import javax.security.auth.x500.X500Principal +import javax.security.cert.CertificateException + + +class KeyHelper @Throws(NoSuchPaddingException::class, NoSuchProviderException::class, NoSuchAlgorithmException::class, InvalidAlgorithmParameterException::class, KeyStoreException::class, CertificateException::class, IOException::class) +constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore: KeyStore) { + + private val aesKeyFromKS: Key? + @Throws(NoSuchProviderException::class, NoSuchAlgorithmException::class, InvalidAlgorithmParameterException::class, KeyStoreException::class, CertificateException::class, IOException::class, UnrecoverableKeyException::class) + get() { + keyStore.load(null) + return keyStore.getKey(KEY_ALIAS, null) as? SecretKey + } + + init { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + this.generateEncryptKey(ctx) + } + this.generateRandomIV(sharedPreferences) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + try { + this.generateAESKey() + } catch (e: Exception) { + e.printStackTrace() + } + + } + } + + + @Throws(NoSuchProviderException::class, NoSuchAlgorithmException::class, InvalidAlgorithmParameterException::class, KeyStoreException::class, CertificateException::class, IOException::class) + private fun generateEncryptKey(ctx: Context) { + keyStore.load(null) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (!keyStore.containsAlias(KEY_ALIAS)) { + val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, AndroidKeyStore) + keyGenerator.init( + KeyGenParameterSpec.Builder(KEY_ALIAS, + KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + .setRandomizedEncryptionRequired(false) + .build()) + keyGenerator.generateKey() + } + } else { + if (!keyStore.containsAlias(KEY_ALIAS)) { + // Generate a key pair for encryption + val start = Calendar.getInstance() + val end = Calendar.getInstance() + end.add(Calendar.YEAR, 30) + val spec = KeyPairGeneratorSpec.Builder(ctx) + .setAlias(KEY_ALIAS) + .setSubject(X500Principal("CN=$KEY_ALIAS")) + .setSerialNumber(BigInteger.TEN) + .setStartDate(start.time) + .setEndDate(end.time) + .build() + val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, AndroidKeyStore) + kpg.initialize(spec) + kpg.generateKeyPair() + } + } + + + } + + @Throws(Exception::class) + private fun rsaEncrypt(secret: ByteArray): ByteArray { + val privateKeyEntry = keyStore.getEntry(KEY_ALIAS, null) as? KeyStore.PrivateKeyEntry + // Encrypt the text + val inputCipher = Cipher.getInstance(RSA_MODE, "AndroidOpenSSL") + inputCipher.init(Cipher.ENCRYPT_MODE, privateKeyEntry?.certificate?.publicKey) + + val outputStream = ByteArrayOutputStream() + val cipherOutputStream = CipherOutputStream(outputStream, inputCipher) + cipherOutputStream.write(secret) + cipherOutputStream.close() + + return outputStream.toByteArray() + } + + @Throws(Exception::class) + private fun rsaDecrypt(encrypted: ByteArray): ByteArray { + val privateKeyEntry = keyStore.getEntry(KEY_ALIAS, null) as? KeyStore.PrivateKeyEntry + val output = Cipher.getInstance(RSA_MODE, "AndroidOpenSSL") + output.init(Cipher.DECRYPT_MODE, privateKeyEntry?.privateKey) + val cipherInputStream = CipherInputStream( + ByteArrayInputStream(encrypted), output) + return cipherInputStream.readBytes() + } + + @Throws(Exception::class) + private fun generateAESKey() { + var enryptedKeyB64 = sharedPreferences.getString(ENCRYPTED_KEY, null) + if (enryptedKeyB64 == null) { + val key = ByteArray(16) + val secureRandom = SecureRandom() + secureRandom.nextBytes(key) + val encryptedKey = rsaEncrypt(key) + enryptedKeyB64 = Base64.encodeToString(encryptedKey, Base64.DEFAULT) + sharedPreferences.edit { + putString(ENCRYPTED_KEY, enryptedKeyB64) + } + } + } + + + @Throws(Exception::class) + private fun getSecretKey(): Key { + val enryptedKeyB64 = sharedPreferences.getString(ENCRYPTED_KEY, null) + + val encryptedKey = Base64.decode(enryptedKeyB64, Base64.DEFAULT) + val key = rsaDecrypt(encryptedKey) + return SecretKeySpec(key, "AES") + } + + @Throws(NoSuchAlgorithmException::class, NoSuchPaddingException::class, NoSuchProviderException::class, BadPaddingException::class, IllegalBlockSizeException::class, UnsupportedEncodingException::class) + fun encrypt(input: String): String { + val c: Cipher + val publicIV = sharedPreferences.getString(PUBLIC_IV, null) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + c = Cipher.getInstance(AES_MODE_M) + try { + c.init(Cipher.ENCRYPT_MODE, aesKeyFromKS, GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT))) + } catch (e: Exception) { + e.printStackTrace() + } + } else { + c = Cipher.getInstance(AES_MODE_M) + try { + c.init(Cipher.ENCRYPT_MODE, getSecretKey(), GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT))) + } catch (e: Exception) { + e.printStackTrace() + } + + } + val encodedBytes = c.doFinal(input.toByteArray(charset("UTF-8"))) + return Base64.encodeToString(encodedBytes, Base64.DEFAULT) + } + + + @Throws(NoSuchAlgorithmException::class, NoSuchPaddingException::class, NoSuchProviderException::class, BadPaddingException::class, IllegalBlockSizeException::class, UnsupportedEncodingException::class) + fun decrypt(encrypted: String): String { + val c: Cipher + val publicIV = sharedPreferences.getString(PUBLIC_IV, null) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + c = Cipher.getInstance(AES_MODE_M) + try { + c.init(Cipher.DECRYPT_MODE, aesKeyFromKS, GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT))) + } catch (e: Exception) { + e.printStackTrace() + } + } else { + c = Cipher.getInstance(AES_MODE_M) + try { + c.init(Cipher.DECRYPT_MODE, getSecretKey(), GCMParameterSpec(128, Base64.decode(publicIV, Base64.DEFAULT))) + } catch (e: Exception) { + e.printStackTrace() + } + + } + + val decodedValue = Base64.decode(encrypted.toByteArray(charset("UTF-8")), Base64.DEFAULT) + val decryptedVal = c.doFinal(decodedValue) + return String(decryptedVal) + } + + private fun generateRandomIV(sharedPreferences: SharedPreferences) { + val publicIV = sharedPreferences.getString(PUBLIC_IV, null) + + if (publicIV == null) { + val random = SecureRandom() + val generated = random.generateSeed(12) + val generatedIVstr = Base64.encodeToString(generated, Base64.DEFAULT) + sharedPreferences.edit { + putString(PUBLIC_IV, generatedIVstr) + } + } + } + + private fun getStringFromSharedPrefs(key: String): String? { + return sharedPreferences.getString(key, null) + } + + companion object { + + + private const val RSA_MODE = "RSA/ECB/PKCS1Padding" + private const val AES_MODE_M = "AES/GCM/NoPadding" + + private const val KEY_ALIAS = "KEY" + private const val AndroidKeyStore = "AndroidKeyStore" + const val ENCRYPTED_KEY = "ENCRYPTED_KEY" + const val PUBLIC_IV = "PUBLIC_IV" + private var keyHelper: KeyHelper? = null + + fun getInstance(ctx: Context, sharedPreferences: SharedPreferences, keyStore: KeyStore): KeyHelper? { + if (keyHelper == null) { + try { + keyHelper = KeyHelper(ctx, sharedPreferences, keyStore) + } catch (e: NoSuchPaddingException) { + e.printStackTrace() + } catch (e: NoSuchProviderException) { + e.printStackTrace() + } catch (e: NoSuchAlgorithmException) { + e.printStackTrace() + } catch (e: InvalidAlgorithmParameterException) { + e.printStackTrace() + } catch (e: KeyStoreException) { + e.printStackTrace() + } catch (e: CertificateException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + + } + return keyHelper + } + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt index 1b6aa3d75..d5c942446 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt @@ -12,7 +12,7 @@ import com.habitrpg.android.habitica.helpers.SoundManager import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.AvatarView -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import io.reactivex.Flowable import io.reactivex.functions.Consumer diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.java index c4a02f188..22f584285 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/ApiModule.java @@ -7,9 +7,11 @@ import com.habitrpg.android.habitica.api.HostConfig; import com.habitrpg.android.habitica.api.MaintenanceApiService; import com.habitrpg.android.habitica.data.ApiClient; import com.habitrpg.android.habitica.data.implementation.ApiClientImpl; +import com.habitrpg.android.habitica.helpers.KeyHelper; import com.habitrpg.android.habitica.helpers.PopupNotificationsManager; import com.habitrpg.android.habitica.proxy.CrashlyticsProxy; +import javax.annotation.Nullable; import javax.inject.Singleton; import dagger.Module; @@ -23,8 +25,8 @@ public class ApiModule { @Provides @Singleton - public HostConfig providesHostConfig(SharedPreferences sharedPreferences, Context context) { - return new HostConfig(sharedPreferences, context); + public HostConfig providesHostConfig(SharedPreferences sharedPreferences, @Nullable KeyHelper keyHelper, Context context) { + return new HostConfig(sharedPreferences, keyHelper, context); } @Provides diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java index 741e47e60..fb9582190 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.java @@ -4,6 +4,7 @@ import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; + import androidx.preference.PreferenceManager; import com.habitrpg.android.habitica.R; @@ -14,12 +15,17 @@ import com.habitrpg.android.habitica.executors.PostExecutionThread; import com.habitrpg.android.habitica.executors.ThreadExecutor; import com.habitrpg.android.habitica.executors.UIThread; import com.habitrpg.android.habitica.helpers.AppConfigManager; +import com.habitrpg.android.habitica.helpers.KeyHelper; import com.habitrpg.android.habitica.helpers.SoundFileLoader; import com.habitrpg.android.habitica.helpers.SoundManager; import com.habitrpg.android.habitica.helpers.TaskAlarmManager; import com.habitrpg.android.habitica.helpers.TaskFilterHelper; import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager; +import java.security.KeyStore; +import java.security.KeyStoreException; + +import javax.annotation.Nullable; import javax.inject.Named; import javax.inject.Singleton; @@ -49,6 +55,26 @@ public class AppModule { return PreferenceManager.getDefaultSharedPreferences(context); } + @Provides + @Nullable + KeyStore provideKeyStore() { + try { + return KeyStore.getInstance("AndroidKeyStore"); + } catch (KeyStoreException e) { + e.printStackTrace(); + } + return null; + } + + @Provides + @Nullable + KeyHelper provideKeyHelper(Context context, SharedPreferences sharedPreferences, @Nullable KeyStore keyStore) { + if (keyStore == null) { + return null; + } + return KeyHelper.Companion.getInstance(context, sharedPreferences, keyStore); + } + @Provides @Named(NAMED_USER_ID) public String providesUserID(SharedPreferences sharedPreferences) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/prefs/scanner/IntentIntegrator.java b/Habitica/src/main/java/com/habitrpg/android/habitica/prefs/scanner/IntentIntegrator.java index 28b07caef..88456e490 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/prefs/scanner/IntentIntegrator.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/prefs/scanner/IntentIntegrator.java @@ -28,7 +28,7 @@ import android.util.Log; import androidx.fragment.app.Fragment; -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog; +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog; import java.util.Arrays; import java.util.Collection; diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt index bea3c2952..41ed4202f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt @@ -11,7 +11,7 @@ import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.components.AppComponent import com.habitrpg.android.habitica.events.ShowConnectionProblemEvent import com.habitrpg.android.habitica.helpers.LanguageHelper -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.disposables.CompositeDisposable import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeFormActivity.kt index b13048821..fc7399041 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeFormActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeFormActivity.kt @@ -27,7 +27,7 @@ import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.adapter.social.challenges.ChallengeTasksRecyclerViewAdapter import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import io.reactivex.Flowable import io.reactivex.functions.Consumer diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ClassSelectionActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ClassSelectionActivity.kt index 14383c78d..85ab51190 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ClassSelectionActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ClassSelectionActivity.kt @@ -20,7 +20,7 @@ import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.user.* import com.habitrpg.android.habitica.ui.AvatarView import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import io.reactivex.functions.Consumer import javax.inject.Inject diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt index ce2abff05..a71672a03 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt @@ -32,7 +32,7 @@ import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.helpers.MarkdownParser import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.SnackbarDisplayType import io.reactivex.Flowable diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftIAPActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftIAPActivity.kt index 9c2a7f529..1b52f7fbc 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftIAPActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftIAPActivity.kt @@ -24,7 +24,7 @@ import com.habitrpg.android.habitica.proxy.CrashlyticsProxy import com.habitrpg.android.habitica.ui.AvatarView import com.habitrpg.android.habitica.ui.helpers.bindOptionalView import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.social.UsernameLabel import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionView import io.reactivex.functions.Consumer diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.kt index 6fc758ec2..60c38dd1b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.kt @@ -44,12 +44,13 @@ import com.habitrpg.android.habitica.extensions.addCloseButton import com.habitrpg.android.habitica.extensions.addOkButton import com.habitrpg.android.habitica.extensions.notNull import com.habitrpg.android.habitica.helpers.AmplitudeManager +import com.habitrpg.android.habitica.helpers.KeyHelper import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.auth.UserAuthResponse import com.habitrpg.android.habitica.prefs.scanner.IntentIntegrator import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.login.LockableScrollView import com.habitrpg.android.habitica.ui.views.login.LoginBackgroundView import io.reactivex.Flowable @@ -75,6 +76,9 @@ class LoginActivity : BaseActivity(), Consumer { lateinit var hostConfig: HostConfig @Inject internal lateinit var userRepository: UserRepository + @Inject + @JvmField + var keyHelper: KeyHelper? = null private var isRegistering: Boolean = false private var isShowingForm: Boolean = false @@ -302,7 +306,11 @@ class LoginActivity : BaseActivity(), Consumer { val prefs = PreferenceManager.getDefaultSharedPreferences(this) prefs.edit { putString(getString(R.string.SP_address), adr) - putString(getString(R.string.SP_APIToken), key) + if (keyHelper != null) { + putString(user, keyHelper?.encrypt(key)) + } else { + putString(getString(R.string.SP_APIToken), key) + } putString(getString(R.string.SP_userID), user) } startMainActivity() @@ -337,7 +345,11 @@ class LoginActivity : BaseActivity(), Consumer { private fun saveTokens(api: String, user: String) { this.apiClient.updateAuthenticationCredentials(user, api) sharedPrefs.edit { - putString(getString(R.string.SP_APIToken), api) + if (keyHelper != null) { + putString(user, keyHelper?.encrypt(api)) + } else { + putString(getString(R.string.SP_APIToken), api) + } putString(getString(R.string.SP_userID), user) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt index 0c8eaa977..736e0ea58 100755 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt @@ -58,7 +58,7 @@ import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil import com.habitrpg.android.habitica.ui.helpers.bindOptionalView import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.SnackbarDisplayType @@ -206,7 +206,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16f, resources.displayMetrics) avatarWithBars.setPadding(px.toInt(), statusBarHeight, px.toInt(), 0) - compositeSubscription.add(userRepository.getUser(hostConfig.user) + compositeSubscription.add(userRepository.getUser(hostConfig.userID) .subscribe(Consumer { newUser -> this@MainActivity.user = newUser this@MainActivity.setUserData() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt index 478fab56e..ea1d2b3a0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt @@ -75,7 +75,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - compositeSubscription.add(userRepository.getUser(hostConfig.user) + compositeSubscription.add(userRepository.getUser(hostConfig.userID) .subscribe(Consumer { this.onUserReceived(it) }, RxErrorHandler.handleEmptyError())) val additionalData = HashMap() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt index 171a88292..96410db0d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt @@ -34,7 +34,7 @@ import com.habitrpg.android.habitica.models.tasks.HabitResetOption import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.tasks.form.* import io.reactivex.functions.Consumer import io.realm.RealmList diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/AchievementsAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/AchievementsAdapter.kt index 661d2a643..f8ec1ebfe 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/AchievementsAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/AchievementsAdapter.kt @@ -12,6 +12,7 @@ import com.habitrpg.android.habitica.models.QuestAchievement import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.helpers.bindOptionalView import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.views.dialogs.AchievementDetailDialog class AchievementsAdapter: RecyclerView.Adapter() { @@ -71,7 +72,7 @@ class AchievementsAdapter: RecyclerView.Adapter() { } } - class AchievementViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { + class AchievementViewHolder(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener { private var achievement: Achievement? = null private val achievementContainer: ViewGroup? by bindOptionalView(R.id.achievement_container) @@ -80,6 +81,10 @@ class AchievementsAdapter: RecyclerView.Adapter() { private val achievementTitleView: TextView by bindView(R.id.achievement_title) private val achievementDescriptionView: TextView? by bindOptionalView(R.id.achievement_description) + init { + itemView.setOnClickListener(this) + } + fun bind(achievement: Achievement) { this.achievement = achievement val iconName = if (achievement.earned) { @@ -98,6 +103,12 @@ class AchievementsAdapter: RecyclerView.Adapter() { } achievementContainer?.clipToOutline = true } + + override fun onClick(v: View?) { + achievement?.let { + AchievementDetailDialog(it, itemView.context).show() + } + } } class QuestAchievementViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt index 41f311401..3eefa7c3f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/CustomizationRecyclerViewAdapter.kt @@ -14,7 +14,7 @@ import com.habitrpg.android.habitica.models.inventory.Customization import com.habitrpg.android.habitica.models.inventory.CustomizationSet import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import io.reactivex.BackpressureStrategy import io.reactivex.Flowable diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/AchievementProfileAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/AchievementProfileAdapter.kt index 63ef0f33b..a7a7fb7a5 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/AchievementProfileAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/AchievementProfileAdapter.kt @@ -18,7 +18,7 @@ import com.habitrpg.android.habitica.ui.AvatarView import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog class AchievementProfileAdapter : RecyclerView.Adapter() { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AchievementsFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AchievementsFragment.kt index 671a2f723..f19b3cf50 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AchievementsFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AchievementsFragment.kt @@ -30,7 +30,7 @@ class AchievementsFragment: BaseMainFragment(), SwipeRefreshLayout.OnRefreshList private var menuID: Int = 0 private lateinit var adapter: AchievementsAdapter private val layoutManager = GridLayoutManager(activity, 2) - private var useGridLayout = true + private var useGridLayout = false set(value) { field = value adapter.useGridLayout = value @@ -48,6 +48,9 @@ class AchievementsFragment: BaseMainFragment(), SwipeRefreshLayout.OnRefreshList hidesToolbar = true super.onCreateView(inflater, container, savedInstanceState) adapter = AchievementsAdapter() + + onRefresh() + return inflater.inflate(R.layout.fragment_refresh_recyclerview, container, false) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/StatsFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/StatsFragment.kt index df64a24e1..4ce6dc688 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/StatsFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/StatsFragment.kt @@ -18,7 +18,7 @@ import com.habitrpg.android.habitica.helpers.UserStatComputer import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.modules.AppModule -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.stats.BulkAllocateStatsDialog import io.reactivex.functions.Consumer diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt index a447a4a1b..e82f0eab6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/SubscriptionFragment.kt @@ -25,7 +25,7 @@ import com.habitrpg.android.habitica.ui.activities.GiftIAPActivity import com.habitrpg.android.habitica.ui.helpers.bindOptionalView import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionDetailsView import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionView diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxFragment.kt index 557972b0c..b94670444 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxFragment.kt @@ -20,7 +20,7 @@ import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.AvatarView import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.social.UsernameLabel import io.reactivex.functions.Consumer import io.realm.RealmResults diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt index e95fc3ebf..e53add645 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt @@ -27,7 +27,7 @@ import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.helpers.MarkdownParser import com.habitrpg.android.habitica.ui.helpers.bindOptionalView import com.habitrpg.android.habitica.ui.helpers.resetViews -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.functions.Consumer import javax.inject.Inject import javax.inject.Named diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/TavernDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/TavernDetailFragment.kt index 9f6f9e662..ae88d67e0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/TavernDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/TavernDetailFragment.kt @@ -26,7 +26,7 @@ import com.habitrpg.android.habitica.models.social.Group import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.fragments.BaseFragment -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.social.UsernameLabel import io.reactivex.functions.Consumer import kotlinx.android.synthetic.main.fragment_tavern_detail.* diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt index 549440ba2..340a3664c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt @@ -29,7 +29,7 @@ import com.habitrpg.android.habitica.ui.activities.FullProfileActivity import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.MarkdownParser import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaEmojiTextView import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.social.UsernameLabel diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt index 9015e8c82..d6a78435d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt @@ -23,7 +23,7 @@ import com.habitrpg.android.habitica.ui.fragments.BaseFragment import com.habitrpg.android.habitica.ui.fragments.inventory.items.ItemRecyclerFragment import com.habitrpg.android.habitica.ui.helpers.* import com.habitrpg.android.habitica.ui.viewmodels.PartyViewModel -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.social.OldQuestProgressView import io.reactivex.functions.Consumer import javax.inject.Inject diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.kt index 4eb2032a1..786639b75 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.kt @@ -22,7 +22,7 @@ import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.resetViews import com.habitrpg.android.habitica.ui.viewmodels.GroupViewType import com.habitrpg.android.habitica.ui.viewmodels.PartyViewModel -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.functions.Consumer import java.util.* diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/AchievementDetailDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/AchievementDetailDialog.kt new file mode 100644 index 000000000..a1ba22e5f --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/AchievementDetailDialog.kt @@ -0,0 +1,33 @@ +package com.habitrpg.android.habitica.ui.views.dialogs + +import android.content.Context +import android.view.LayoutInflater +import android.widget.TextView +import com.facebook.drawee.view.SimpleDraweeView +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.extensions.addCloseButton +import com.habitrpg.android.habitica.models.Achievement +import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils + +class AchievementDetailDialog(val achievement: Achievement, context: Context): HabiticaAlertDialog(context) { + + private var iconView: SimpleDraweeView? + private var descriptionView: TextView? + + init { + val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater + val view = inflater?.inflate(R.layout.dialog_achievement_detail, null) + iconView = view?.findViewById(R.id.icon_view) + descriptionView = view?.findViewById(R.id.description_view) + setAdditionalContentView(view) + setTitle(achievement.title) + descriptionView?.text = achievement.text + val iconName = if (achievement.earned) { + achievement.icon + "2x" + } else { + "achievement-unearned2x" + } + DataBindingUtils.loadImage(iconView, iconName) + addCloseButton(true) + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaAlertDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaAlertDialog.kt similarity index 99% rename from Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaAlertDialog.kt rename to Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaAlertDialog.kt index e56e84559..a8fcd5bb4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaAlertDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaAlertDialog.kt @@ -1,4 +1,4 @@ -package com.habitrpg.android.habitica.ui.views +package com.habitrpg.android.habitica.ui.views.dialogs import android.content.Context import android.view.LayoutInflater diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt index cfe0d6752..5dcbf629f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/insufficientCurrency/InsufficientCurrencyDialog.kt @@ -5,7 +5,7 @@ import android.view.LayoutInflater import android.widget.ImageView import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog /** * Created by phillip on 27.09.17. diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt index 71af57414..27c32505d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt @@ -25,6 +25,7 @@ import com.habitrpg.android.habitica.models.shops.ShopItem import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.* +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientGemsDialog import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientGoldDialog import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientHourglassesDialog diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt index c0f1e472d..28358a747 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/social/QuestProgressView.kt @@ -28,6 +28,7 @@ import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.helpers.MarkdownParser import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.* +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt index 7762d872e..d594b75f2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt @@ -18,8 +18,8 @@ import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.tasks.ChecklistItem import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.ui.helpers.bindColor -import com.habitrpg.android.habitica.ui.views.HabiticaAlertDialog import com.habitrpg.android.habitica.ui.views.HabiticaEmojiTextView +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer