diff --git a/.gitignore b/.gitignore index bee931d87037fd7d9aef70a806c8ec2c24579cfd..781a87718c659df5abc6025dccfbd2fa701721c0 100644 --- a/.gitignore +++ b/.gitignore @@ -135,4 +135,9 @@ fabric.properties app/release -# End of https://www.gitignore.io/api/androidstudio \ No newline at end of file +akamu.jks + +keystore.properties + +# End of https://www.gitignore.io/api/androidstudio +keystore.properties diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index e7ff73707155a2ace2880488b22363fdcd686827..0000000000000000000000000000000000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Akamu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/app/build.gradle b/app/build.gradle index 583476c517abd943d5c30a6f14dd15147f93cbd8..af6ae3962974e1d8455c7bc2eb9e51aa4df7e227 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,8 +21,8 @@ android { applicationId "de.akamu.tudarmstadt" minSdkVersion 21 targetSdkVersion 29 - versionCode 4 - versionName "0.4.0" + versionCode 5 + versionName "1.0.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } signingConfigs { @@ -34,7 +34,11 @@ android { } } buildTypes { + debug { + buildConfigField("String", "BASE_URL", '"https://dev.akamu.de/api/v2/"') + } release { + buildConfigField("String", "BASE_URL", '"https://akamu.de/api/v2/"') signingConfig signingConfigs.release minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' @@ -52,16 +56,19 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'com.google.android.material:material:1.3.0-alpha01' + implementation 'com.google.android.material:material:1.3.0-alpha03' implementation 'com.jaredrummler:animated-svg-view:1.0.5' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.squareup.okhttp3:okhttp:3.12.1' implementation 'com.github.bumptech.glide:glide:4.8.0' implementation 'org.greenrobot:eventbus:3.2.0' + // LANGUAGE + implementation "com.github.YarikSOffice:lingver:1.3.0" + // FIREBASE implementation 'com.google.firebase:firebase-analytics:17.4.4' // Recommended: Add the Firebase SDK for Google Analytics. diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 66503640b890b8250f51f36add9300c159c58b1e..d32e187c5e8747a4b740a4215f8ae8bbbb419d38 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,11 @@ android:supportsRtl="true" android:theme="@style/WhiteTheme" tools:ignore="GoogleAppIndexingWarning"> - + @@ -54,7 +58,7 @@ @@ -75,6 +80,8 @@ + = 200; } + public static String getBaseURL() { + return baseURL; + } } diff --git a/app/src/main/java/de/akamu/tudarmstadt/api/V2APIForgotPassword.java b/app/src/main/java/de/akamu/tudarmstadt/api/V2APIForgotPassword.java new file mode 100644 index 0000000000000000000000000000000000000000..6d6c7985fa6cbf2499dd43c80677f563ecee14b2 --- /dev/null +++ b/app/src/main/java/de/akamu/tudarmstadt/api/V2APIForgotPassword.java @@ -0,0 +1,24 @@ +package de.akamu.tudarmstadt.api; + +import android.util.ArrayMap; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.Map; + +import de.akamu.tudarmstadt.exceptions.AkamuAPIException; + +public final class V2APIForgotPassword { + public static void requestNewPassword(String usernameOrEmail) throws IOException, AkamuAPIException, JSONException { + Map parameters = new ArrayMap<>(0); + JSONObject json = new JSONObject(); + if (usernameOrEmail.contains("@")) { + json.put("email", usernameOrEmail); + } else { + json.put("username", usernameOrEmail); + } + V2API.post("forgotpassword", json.toString(), parameters); + } +} diff --git a/app/src/main/java/de/akamu/tudarmstadt/data/friends/FriendsDataSource.kt b/app/src/main/java/de/akamu/tudarmstadt/data/friends/FriendsDataSource.kt index 888b236bab619dbe129030da53c4b27561c6e1dc..62aea8d8bc2de7dc173074d033e62f909c92b0f5 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/data/friends/FriendsDataSource.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/data/friends/FriendsDataSource.kt @@ -19,6 +19,7 @@ interface FriendsDataSource { fun onChallengeRequestSuccess(friendName: String) fun onChallengeRequestFailed(reason : String) fun onChallengeRequestFailedNoPoolsSelected() + fun onChallengeRequestFailedNoPoolsInCommon() } interface GetAllUsersCallback { diff --git a/app/src/main/java/de/akamu/tudarmstadt/data/friends/FriendsDataSourceImpl.kt b/app/src/main/java/de/akamu/tudarmstadt/data/friends/FriendsDataSourceImpl.kt index 830af3234137b18f9523714bfdc1bc3461ba8c1a..76eb8f382941d6eb1d62e71f4ab3169758d58496 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/data/friends/FriendsDataSourceImpl.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/data/friends/FriendsDataSourceImpl.kt @@ -3,6 +3,7 @@ package de.akamu.tudarmstadt.data.friends import android.os.AsyncTask import de.akamu.tudarmstadt.api.V2APIDuel import de.akamu.tudarmstadt.api.V2APIFriend +import de.akamu.tudarmstadt.api.V2APIPool import de.akamu.tudarmstadt.api.V2APIUser import de.akamu.tudarmstadt.exceptions.AkamuAPIException import de.akamu.tudarmstadt.model.User @@ -51,16 +52,24 @@ class FriendsDataSourceImpl : FriendsDataSource { var errorMessage : String = "Oops! Something went wrong..." private var noPoolsSelected: Boolean = false + private var noPoolsInCommon: Boolean = false override fun doInBackground(vararg params: Void?): Boolean { return try { - V2APIDuel.startDuel(friend.id.toInt()) - true + val playablePools = V2APIPool.getPlayablePools() + val myPools = playablePools.filter { pool -> pool.isSelected } + if (myPools.isEmpty()) { + noPoolsSelected = true + false + } else { + V2APIDuel.startDuel(friend.id.toInt()) + true + } } catch (ae : AkamuAPIException) { ae.printStackTrace() errorMessage = ae.message!! if (ae.code == 409) { - noPoolsSelected = true + noPoolsInCommon = true } false } catch (e : Exception) { @@ -76,6 +85,8 @@ class FriendsDataSourceImpl : FriendsDataSource { } else { if (noPoolsSelected) { callback.onChallengeRequestFailedNoPoolsSelected() + } else if (noPoolsInCommon) { + callback.onChallengeRequestFailedNoPoolsInCommon() } else { callback.onChallengeRequestFailed(errorMessage) } diff --git a/app/src/main/java/de/akamu/tudarmstadt/data/password/PasswordDataSource.kt b/app/src/main/java/de/akamu/tudarmstadt/data/password/PasswordDataSource.kt index 056121e606b9d4bec7a34d2e4cf50671c254255d..77fc9ecf4653ccf7936f73a41e0ef86129d29c7d 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/data/password/PasswordDataSource.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/data/password/PasswordDataSource.kt @@ -4,7 +4,7 @@ import de.akamu.tudarmstadt.model.User interface PasswordDataSource { - interface VerifyPasswordDataSource { + interface VerifyPasswordCallback { /** * Called when the given password matches the user's password @@ -23,6 +23,21 @@ interface PasswordDataSource { /** * Checks if the given [password] matches the user's password */ - fun verifyPassword(user: User, password: String, firebaseToken: String, callback: PasswordDataSource.VerifyPasswordDataSource) + fun verifyPassword(user: User, password: String, firebaseToken: String, callback: VerifyPasswordCallback) + + + interface RequestNewPasswordCallback { + fun onRequestNewPasswordSuccess() + fun onRequestNewPasswordFailed(reason: String) + fun onNoSuchUserError() + } + + /** + * Sends a request for resetting the user's password + * + * @param usernameOrEmail the user or its email address + * @param callback RequestNewPasswordCallback + */ + fun requestNewPassword(usernameOrEmail: String, callback: RequestNewPasswordCallback) } \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/data/password/PasswordDataSourceImpl.kt b/app/src/main/java/de/akamu/tudarmstadt/data/password/PasswordDataSourceImpl.kt index af847c717870dd6dd791e121c765e6573e9ea2e8..875e8adbacde8c8b538a0dbaba7487c30cd8a84a 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/data/password/PasswordDataSourceImpl.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/data/password/PasswordDataSourceImpl.kt @@ -1,22 +1,32 @@ package de.akamu.tudarmstadt.data.password import android.os.AsyncTask +import de.akamu.tudarmstadt.api.V2APIForgotPassword import de.akamu.tudarmstadt.api.V2APILogin import de.akamu.tudarmstadt.exceptions.AkamuAPIException import de.akamu.tudarmstadt.model.Login import de.akamu.tudarmstadt.model.User +import java.lang.Exception class PasswordDataSourceImpl : PasswordDataSource { - override fun verifyPassword(user: User, password: String, firebaseToken: String, callback: PasswordDataSource.VerifyPasswordDataSource) { - + override fun verifyPassword( + user: User, + password: String, + firebaseToken: String, + callback: PasswordDataSource.VerifyPasswordCallback + ) { val task = VerifyPasswordTask(user, password, firebaseToken, callback) task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) } - class VerifyPasswordTask(private val user: User, private val password: String, private val firebaseToken: String, private val callback: PasswordDataSource.VerifyPasswordDataSource) - : AsyncTask() { + class VerifyPasswordTask( + private val user: User, + private val password: String, + private val firebaseToken: String, + private val callback: PasswordDataSource.VerifyPasswordCallback + ) : AsyncTask() { private var errorCode = 0 @@ -27,6 +37,8 @@ class PasswordDataSourceImpl : PasswordDataSource { } catch (e: AkamuAPIException) { errorCode = e.code return false + } catch (e: Exception) { + return false } return true @@ -47,4 +59,48 @@ class PasswordDataSourceImpl : PasswordDataSource { } + + override fun requestNewPassword( + usernameOrEmail: String, + callback: PasswordDataSource.RequestNewPasswordCallback + ) { + val task = RequestNewPasswordTask(usernameOrEmail, callback) + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) + } + + class RequestNewPasswordTask( + private val usernameOrEmail: String, + private val callback: PasswordDataSource.RequestNewPasswordCallback + ) : AsyncTask() { + + private var errorCode = 0 + private var errorMsg = "Oops. Something went wrong..." + + override fun doInBackground(vararg params: Void?): Boolean { + + try { + V2APIForgotPassword.requestNewPassword(usernameOrEmail) + } catch (e: AkamuAPIException) { + errorCode = e.code + errorMsg = e.message!! + return false + } catch (e: Exception) { + errorMsg = e.message!! + return false + } + + return true + } + + override fun onPostExecute(result: Boolean?) { + when { + result!! -> callback.onRequestNewPasswordSuccess() + errorCode == 404 -> callback.onNoSuchUserError() + else -> callback.onRequestNewPasswordFailed(errorMsg) + } + + } + + } + } \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/data/user/UserDataSource.kt b/app/src/main/java/de/akamu/tudarmstadt/data/user/UserDataSource.kt index 73499dfe1accf7e56aedf42cbb6899eddbf07859..76b93afb9d784b98491ea5fa3dc6772cfc2e8e87 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/data/user/UserDataSource.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/data/user/UserDataSource.kt @@ -3,6 +3,7 @@ package de.akamu.tudarmstadt.data.user import de.akamu.tudarmstadt.model.Avatar import de.akamu.tudarmstadt.model.User import java.util.* +import kotlin.collections.ArrayList /** * Defines general methods to change the user in the server @@ -46,14 +47,26 @@ interface UserDataSource { } /** - * Callback for loading the user's avatar + * Callback for loading all the avatars */ - interface LoadAvatarListCallback { + interface LoadAllAvatarListCallback { - /** Called when the user avatar was successfully loaded */ + /** Called when all the avatars were successfully loaded */ + fun onLoadAvatarListSuccess(avatarList: ArrayList) + + /** Called when loading all the avatars failed */ + fun onLoadAvatarListFail(reason: String) + } + + /** + * Callback for loading all the user's avatar + */ + interface LoadUnlockedAvatarListCallback { + + /** Called when the unlocked avatars was successfully loaded */ fun onLoadAvatarListSuccess(avatarSortedMap: SortedMap) - /** Called when loading the user avatar failed */ + /** Called when loading the unlocked avatars failed */ fun onLoadAvatarListFail(reason: String) } @@ -65,7 +78,7 @@ interface UserDataSource { fun loadUserAvatarFromServer(avatarUrl: String, callback: LoadAvatarCallback) - fun loadAllAvatarsFromServer(callback: LoadAvatarListCallback) + fun loadAllAvatarsFromServer(callback: LoadAllAvatarListCallback) - fun loadUnlockedAvatarsFromServer(callback: LoadAvatarListCallback) + fun loadUnlockedAvatarsFromServer(callback: LoadUnlockedAvatarListCallback) } \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/data/user/UserDataSourceImpl.kt b/app/src/main/java/de/akamu/tudarmstadt/data/user/UserDataSourceImpl.kt index fdc7acf224a90cca1ddda0e52d1a2f1f2402b433..29d4be91149f1640ed73815532725f05a9e55400 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/data/user/UserDataSourceImpl.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/data/user/UserDataSourceImpl.kt @@ -157,25 +157,18 @@ class UserDataSourceImpl : UserDataSource { } } - override fun loadAllAvatarsFromServer(callback: UserDataSource.LoadAvatarListCallback) { + override fun loadAllAvatarsFromServer(callback: UserDataSource.LoadAllAvatarListCallback) { val getAllAvatarsTask = GetAllAvatarsTask(callback) getAllAvatarsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) } - class GetAllAvatarsTask(var callback: UserDataSource.LoadAvatarListCallback) : AsyncTask() { + class GetAllAvatarsTask(var callback: UserDataSource.LoadAllAvatarListCallback) : AsyncTask() { lateinit var avatarList: ArrayList - lateinit var avatarSortedMap: SortedMap - private var avatarHashMap: HashMap = HashMap() private lateinit var errorMessage: String override fun doInBackground(vararg p0: Void?): Boolean { return try { avatarList = ArrayList(V2APIAvatar.loadAllAvatarsFromServer()) - for (avatar in avatarList) { - val res = V2APIAvatar.loadAvatarFromServer(avatar.image) - avatarHashMap[avatar] = res - } - avatarSortedMap = avatarHashMap.toSortedMap(compareBy { it.id }) true } catch (e: Exception) { errorMessage = e.message!! @@ -185,20 +178,20 @@ class UserDataSourceImpl : UserDataSource { override fun onPostExecute(success: Boolean?) { if (success!!) { - callback.onLoadAvatarListSuccess(avatarSortedMap) + callback.onLoadAvatarListSuccess(avatarList) } else { callback.onLoadAvatarListFail(errorMessage) } } } - override fun loadUnlockedAvatarsFromServer(callback: UserDataSource.LoadAvatarListCallback) { + override fun loadUnlockedAvatarsFromServer(callback: UserDataSource.LoadUnlockedAvatarListCallback) { val getUnlockedAvatarsTask = GetUnlockedAvatarsTask(callback) getUnlockedAvatarsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) } - class GetUnlockedAvatarsTask(var callback: UserDataSource.LoadAvatarListCallback) : AsyncTask() { + class GetUnlockedAvatarsTask(var callback: UserDataSource.LoadUnlockedAvatarListCallback) : AsyncTask() { lateinit var avatarList: ArrayList lateinit var avatarSortedMap: SortedMap private var avatarHashMap: HashMap = HashMap() diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/FriendsListFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/FriendsListFragment.kt index 86a6671a40974f1d13f2fbc55a89e39623b6da52..54a4f8401fd56a430d6bac7addf7c1cf08385cb9 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/FriendsListFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/FriendsListFragment.kt @@ -11,6 +11,7 @@ import android.view.ViewGroup import android.view.inputmethod.EditorInfo import android.widget.* import androidx.appcompat.widget.SearchView +import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -152,6 +153,7 @@ class FriendsListFragment : Fragment(), builder.setTitle(getString(R.string.confirm_unfriend)) val infoTextView = TextView(requireActivity()) infoTextView.text = getString(R.string.confirm_unfriend_info, friend.username) + infoTextView.setTextColor(ContextCompat.getColor(requireActivity(), R.color.textLight)) val container = FrameLayout(requireActivity()) val params = FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -182,6 +184,7 @@ class FriendsListFragment : Fragment(), builder.setTitle(getString(R.string.no_questionpool_selected)) val infoTextView = TextView(requireActivity()) infoTextView.text = getString(R.string.no_questionpool_selected_info) + infoTextView.setTextColor(ContextCompat.getColor(requireActivity(), R.color.textLight)) val container = FrameLayout(requireActivity()) val params = FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -202,6 +205,33 @@ class FriendsListFragment : Fragment(), infoDialog.show() } + override fun showSendChallengeRequestFailedNoPoolsInCommon() { + lateinit var infoDialog: AlertDialog + val builder = AlertDialog.Builder(context, R.style.DialogStyle) + builder.setTitle(getString(R.string.no_common_questionpools)) + val infoTextView = TextView(requireActivity()) + infoTextView.text = getString(R.string.no_common_questionpool_info) + infoTextView.setTextColor(ContextCompat.getColor(requireActivity(), R.color.textLight)) + val container = FrameLayout(requireActivity()) + val params = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + params.leftMargin = resources.getDimensionPixelSize(R.dimen.dialog_margin) + params.rightMargin = resources.getDimensionPixelSize(R.dimen.dialog_margin) + infoTextView.layoutParams = params + container.addView(infoTextView) + builder.setView(container) + builder.setPositiveButton(getString(R.string.select_your_questionpools)) { _: DialogInterface, _: Int -> + (requireActivity() as MainActivity).navigateToChangeQuestionPools() + } + builder.setNegativeButton(getString(R.string.cancel)) { dialog, _ -> + dialog.cancel() + } + infoDialog = builder.create() + infoDialog.show() + } + override fun showSendChallengeRequestSuccess(friendName: String) { Toast.makeText(requireActivity(), friendName + " " + getString(R.string.prompt_challenged_successful), Toast.LENGTH_SHORT).show() } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/MainActivity.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/MainActivity.kt index 851331ad16603fc7df2cba90e91be27af172c25c..1605e6fe14a067ca552e3fe6024f0ce598b0025e 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/MainActivity.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/MainActivity.kt @@ -27,6 +27,7 @@ import de.akamu.tudarmstadt.model.User import de.akamu.tudarmstadt.util.AkamuResource import de.akamu.tudarmstadt.util.AppUserUtil import de.akamu.tudarmstadt.util.Constants +import de.akamu.tudarmstadt.util.Extensions.Companion.toast import kotlinx.android.synthetic.main.activity_main.* import tyrantgit.explosionfield.ExplosionField @@ -68,7 +69,11 @@ class MainActivity : BaseActivity(), DashboardContract.View, NextLevelEventHandl } } window.setWindowAnimations(R.style.WindowAnimationFadeInOut) - recreate() + //recreate() + val refresh = Intent(this, MainActivity::class.java) + refresh.putExtra(Constants.KEY_MAINACTIVITY_PAGE, activeFragment) + finish() + startActivity(refresh) } constraintlayout_main_header.setOnClickListener { @@ -80,11 +85,15 @@ class MainActivity : BaseActivity(), DashboardContract.View, NextLevelEventHandl } mNextLevelExploder = ExplosionField.attach2Window(this) - progressbar_mainactivity_lvl.progress = AppUserUtil.getUserProgress(user!!).toInt() + progressbar_mainactivity_lvl.progress = AppUserUtil.getUserProgress(user!!) fillProfile() setupBottomNavigation() - navigateToDuelList() + when(intent.getIntExtra(Constants.KEY_MAINACTIVITY_PAGE, 0)) { + Constants.DUEL_LIST_FRAGMENT -> navigateToDuelList() + Constants.CHALLENGE_FRAGMENT -> navigateToChallenge() + else -> navigateToDuelList() + } } override fun navigateToProfile() { @@ -208,7 +217,7 @@ class MainActivity : BaseActivity(), DashboardContract.View, NextLevelEventHandl } override fun onLoadUserFail(reason: String) { - Toast.makeText(this, reason, Toast.LENGTH_SHORT).show() + toast(getString(R.string.load_user_failed, reason)) } override fun onNextLevelReached() { diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/ChallengeSection.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/ChallengeSection.kt index b51c0d555ad99e624fab310bc8c6129a2d5f7a56..4427beec19e35a7ccec21e2f5660e77290d18034 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/ChallengeSection.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/ChallengeSection.kt @@ -43,7 +43,7 @@ class ChallengeSection( } override fun onBindHeaderViewHolder(holder: RecyclerView.ViewHolder?) { - (holder as DuelSectionViewHolder).bind(context.getString(R.string.challenges)) + (holder as DuelSectionViewHolder).bind(context.getString(R.string.challenges), false) } override fun getHeaderViewHolder(view: View?): RecyclerView.ViewHolder { diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/FinishedDuelSection.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/FinishedDuelSection.kt index 9520cba892a4478a0d0ce3df5698b9803a6e4e7b..87cd5facfbaf402415df4540bd3b73daabed3db2 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/FinishedDuelSection.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/FinishedDuelSection.kt @@ -29,7 +29,7 @@ class FinishedDuelSection( } override fun onBindItemViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { - (holder as DuelViewHolder).bind(sectionDuels[position]) + (holder as DuelViewHolder).bind(sectionDuels[position], true) } override fun getItemViewHolder(view: View?): RecyclerView.ViewHolder { @@ -42,7 +42,7 @@ class FinishedDuelSection( } override fun onBindHeaderViewHolder(holder: RecyclerView.ViewHolder?) { - (holder as DuelSectionViewHolder).bind(context.getString(R.string.finished_duels)) + (holder as DuelSectionViewHolder).bind(context.getString(R.string.finished_duels), true) } override fun getHeaderViewHolder(view: View?): RecyclerView.ViewHolder { diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/RunningDuelSection.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/RunningDuelSection.kt index d016e4512a2258e7c9af1a9b682364810e60c42e..ae4f4d4fbf6180df2892e35e52885b45e3afc402 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/RunningDuelSection.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/sections/RunningDuelSection.kt @@ -29,7 +29,7 @@ class RunningDuelSection( } override fun onBindItemViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { - (holder as DuelViewHolder).bind(sectionDuels[position]) + (holder as DuelViewHolder).bind(sectionDuels[position], false) } override fun getItemViewHolder(view: View?): RecyclerView.ViewHolder { @@ -42,7 +42,7 @@ class RunningDuelSection( } override fun onBindHeaderViewHolder(holder: RecyclerView.ViewHolder?) { - (holder as DuelSectionViewHolder).bind(context.getString(R.string.running_duels)) + (holder as DuelSectionViewHolder).bind(context.getString(R.string.running_duels), false) } override fun getHeaderViewHolder(view: View?): RecyclerView.ViewHolder { diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/viewholders/DuelSectionViewHolder.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/viewholders/DuelSectionViewHolder.kt index e0b599540de4360c77a784182003c94e2e2f5ad9..9c79a9ed8d7a521f6f0fc0a9ba163359874a0783 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/viewholders/DuelSectionViewHolder.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/viewholders/DuelSectionViewHolder.kt @@ -9,7 +9,10 @@ class DuelSectionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) private var mSectionName: TextView = itemView.findViewById(R.id.textView_duel_section_name) - fun bind(sectionName: String) { + fun bind(sectionName: String, finished: Boolean) { mSectionName.text = sectionName + if (finished) { + mSectionName.alpha = 0.5f + } } } \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/viewholders/DuelViewHolder.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/viewholders/DuelViewHolder.kt index 63a02d1478baea286af41ccdca563d684db79974..c83a055162ad823a969e14749efe5282e345b8f9 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/viewholders/DuelViewHolder.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dashboard/duels/viewholders/DuelViewHolder.kt @@ -6,6 +6,9 @@ import android.view.View import android.widget.Button import android.widget.ImageView import android.widget.TextView +import androidx.cardview.widget.CardView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import de.akamu.tudarmstadt.R import de.akamu.tudarmstadt.features.dashboard.duels.listener.DuelClickListener @@ -13,10 +16,16 @@ import de.akamu.tudarmstadt.model.Duel import de.akamu.tudarmstadt.model.DuelPlayer import de.akamu.tudarmstadt.util.AkamuResource -class DuelViewHolder(itemView: View, var context: Context, private var duelClickListener: DuelClickListener, private var ID_ME: Int) : RecyclerView.ViewHolder(itemView), View.OnClickListener { +class DuelViewHolder( + itemView: View, + var context: Context, + private var duelClickListener: DuelClickListener, + private var ID_ME: Int +) : RecyclerView.ViewHolder(itemView), View.OnClickListener { private lateinit var mDuel: Duel + private var mCardParent: CardView = itemView.findViewById(R.id.CardParent) private var mOpponentName: TextView = itemView.findViewById(R.id.duel_item_opp_username) private var mOpponentTitle: TextView = itemView.findViewById(R.id.duel_item_opp_title) private var mOpponentAvatar: ImageView = itemView.findViewById(R.id.duel_item_opp_avatar) @@ -27,7 +36,7 @@ class DuelViewHolder(itemView: View, var context: Context, private var duelClick buttonDuelAction.setOnClickListener(this) } - fun bind(duel: Duel) { + fun bind(duel: Duel, finished: Boolean) { mDuel = duel val duelPlayers = duel.participants @@ -35,7 +44,7 @@ class DuelViewHolder(itemView: View, var context: Context, private var duelClick val me: DuelPlayer val opp: DuelPlayer - if(duelPlayers == null) { + if (duelPlayers == null) { return } @@ -58,6 +67,9 @@ class DuelViewHolder(itemView: View, var context: Context, private var duelClick buttonDuelAction.text = getDuelButtonText(duel, me, opp) buttonDuelAction.background = getDuelButtonBackground(buttonDuelAction.text) + if (finished) { + mCardParent.alpha = 0.5f + } } private fun getDuelButtonText(duel: Duel, me: DuelPlayer, opp: DuelPlayer): CharSequence? { @@ -78,12 +90,12 @@ class DuelViewHolder(itemView: View, var context: Context, private var duelClick private fun getDuelButtonBackground(duelStatus: CharSequence?): Drawable? { return when (duelStatus) { - context.getString(R.string.duel_status_won) -> context.getDrawable(R.color.colorPlayWon) - context.getString(R.string.duel_status_lost) -> context.getDrawable(R.color.colorLost) - context.getString(R.string.duel_status_tie) -> context.getDrawable(R.color.colorWaitTie) - context.getString(R.string.duel_status_play) -> context.getDrawable(R.color.colorPlayWon) + context.getString(R.string.duel_status_won) -> ContextCompat.getDrawable(context, R.color.colorPlayWon) + context.getString(R.string.duel_status_lost) -> ContextCompat.getDrawable(context, R.color.colorLost) + context.getString(R.string.duel_status_tie) -> ContextCompat.getDrawable(context, R.color.colorTie) + context.getString(R.string.duel_status_play) -> ContextCompat.getDrawable(context, R.color.colorPlayWon) else -> { - context.getDrawable(R.color.colorWaitTie) + ContextCompat.getDrawable(context, R.color.colorWait) } } } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dse/DSEStepperAdapter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dse/DSEStepperAdapter.kt index db736664c88e7c8a600021f71e34138735f3bc67..22ecf6e98dab729e55297d289e690fa54db3ef7c 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dse/DSEStepperAdapter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dse/DSEStepperAdapter.kt @@ -18,13 +18,14 @@ class DSEStepperAdapter(fm: FragmentManager, context: Context) : AbstractFragmen 3 -> Page4Fragment() 4 -> Page5Fragment() 5 -> Page6Fragment() - 6 -> Page7Fragment() + 6 -> Page8Fragment() + 7 -> Page7Fragment() else -> Page1Fragment() } } override fun getCount(): Int { - return 7 + return 8 } override fun getViewModel(position: Int): StepViewModel { @@ -49,6 +50,9 @@ class DSEStepperAdapter(fm: FragmentManager, context: Context) : AbstractFragmen .setEndButtonLabel(context.getString(R.string.dse_stepper_next)) .setBackButtonLabel(context.getString(R.string.dse_stepper_back)) 6 -> builder + .setEndButtonLabel(context.getString(R.string.dse_stepper_next)) + .setBackButtonLabel(context.getString(R.string.dse_stepper_back)) + 7 -> builder .setBackButtonLabel(context.getString(R.string.dse_stepper_back)) .setEndButtonVisible(false) else -> throw IllegalArgumentException("Unsupported position: $position") diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page1Fragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page1Fragment.kt index 3e25a53d79e47e6589682b38fa17b04d23e3a30c..4f3a8a3c6d792f337fcfee1a34373b149c1e21c4 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page1Fragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page1Fragment.kt @@ -40,14 +40,14 @@ class Page1Fragment : Fragment(), Step { } private fun showDeclineDialog(){ - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setTitle(getString(R.string.dse_page1_decline_popup_title)) dialog.setMessage(getString(R.string.dse_page1_decline_popup_text)) dialog.show() } private fun showConsentDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setTitle(getString(R.string.dse_page1_consent_popup_title)) dialog.setMessage(getString(R.string.dse_page1_consent_popup_text)) dialog.show() diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page4Fragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page4Fragment.kt index 78a24b60d8eb5f92050b473b60ef9f796cd7339e..e38768c17d73f7ae3d5ee560779abf60fc2d9223 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page4Fragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page4Fragment.kt @@ -25,7 +25,7 @@ class Page4Fragment : Fragment(), Step { } private fun showMethodDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setTitle(getString(R.string.dse_page4_method_popup_title)) dialog.setMessage(getText(R.string.dse_page4_method_popup_text)) dialog.show() diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page5Fragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page5Fragment.kt index 71348c25150c169352bf436df428fc2b62c1d117..c2d45b4dd63800bad64fff63d9cbecea4ab5ab3a 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page5Fragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page5Fragment.kt @@ -63,43 +63,43 @@ class Page5Fragment : Fragment(), Step { } private fun showRevokeDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setMessage(getString(R.string.dse_page5_revoke_popup_text)) dialog.show() } private fun showRequestDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setMessage(getString(R.string.dse_page5_information_popup_text)) dialog.show() } private fun showTransferDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setMessage(getString(R.string.dse_page5_transfer_popup_text)) dialog.show() } private fun showRestrictDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setMessage(getString(R.string.dse_page5_restriction_popup_text)) dialog.show() } private fun showDeleteDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setMessage(getString(R.string.dse_page5_delete_popup_text)) dialog.show() } private fun showComplainDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setMessage(getString(R.string.dse_page5_complain_popup_text)) dialog.show() } private fun showCorrectDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setMessage(getText(R.string.dse_page5_correct_popup)) dialog.show() } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page7Fragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page7Fragment.kt index 8da22dc19045c85b02afb0ab63a4d58b91cd3683..72cbfc46589902213ef36eaea304bed2d7bf7aad 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page7Fragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page7Fragment.kt @@ -45,14 +45,14 @@ class Page7Fragment : Fragment(), Step { } private fun showDeclineDialog(){ - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setTitle(getString(R.string.dse_page7_decline_popup_title)) dialog.setMessage(getString(R.string.dse_page7_decline_popup_text)) dialog.show() } private fun showConsentDialog() { - val dialog = AlertDialog.Builder(context, R.style.DialogStyle).create() + val dialog = AlertDialog.Builder(context, R.style.DialogStylePrivacyPolicy).create() dialog.setMessage(getText(R.string.dse_page7_popup_text)) dialog.show() } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page8Fragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page8Fragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..1c9e79bb39232a769d785ad27b5f42fd58a9eea0 --- /dev/null +++ b/app/src/main/java/de/akamu/tudarmstadt/features/dse/Page8Fragment.kt @@ -0,0 +1,57 @@ +package de.akamu.tudarmstadt.features.dse + +import android.os.Bundle +import android.text.method.LinkMovementMethod +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Switch +import androidx.fragment.app.Fragment +import com.stepstone.stepper.Step +import com.stepstone.stepper.VerificationError +import de.akamu.tudarmstadt.R +import android.widget.TextView +import androidx.appcompat.widget.SwitchCompat +import androidx.preference.PreferenceManager +import com.google.firebase.crashlytics.FirebaseCrashlytics +import de.akamu.tudarmstadt.util.Constants +import java.lang.RuntimeException + + +class Page8Fragment : Fragment(), Step { + lateinit var thisView: View + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + thisView = inflater.inflate(R.layout.fragment_page8, container, false) + + val textViewPrivacyPolicy: TextView = thisView.findViewById(R.id.dse_page8_pp) + textViewPrivacyPolicy.movementMethod = LinkMovementMethod.getInstance() + + return thisView + } + + fun setCrashlytics(isEnabled: Boolean) { + FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(isEnabled) + PreferenceManager.getDefaultSharedPreferences(activity).edit() + .putBoolean(Constants.BUG_REPORTS_ENABLED_KEY, isEnabled).apply() + } + + override fun onSelected() { + } + + override fun verifyStep(): VerificationError? { + // Set crashlytic setting + val switch = thisView.findViewById(R.id.switch_crashlytics) + setCrashlytics(switch.isChecked) + return null + } + + override fun onError(error: VerificationError) { + } + + +} \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListAdapter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListAdapter.kt index fca9126b3df8c26e8c2e869053e35df1929978ac..d93619422b67b9b6100b564d4b908a6850491a19 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListAdapter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListAdapter.kt @@ -8,6 +8,7 @@ import android.widget.ImageButton import android.widget.ImageView import android.widget.ProgressBar import android.widget.TextView +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import de.akamu.tudarmstadt.R import de.akamu.tudarmstadt.model.Duel @@ -137,7 +138,7 @@ class FriendsListAdapter( sendChallengeButton.visibility = View.VISIBLE sendChallengeButton.isEnabled = false sendChallengeButton.animate()?.rotation(360F)?.start() - sendChallengeButton.background = context.getDrawable(R.drawable.md_transparent) + sendChallengeButton.background = ContextCompat.getDrawable(context, R.drawable.md_transparent) sendChallengeButton.setImageResource(R.drawable.ic_checked_akamu_blue) } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListContract.kt b/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListContract.kt index 657f214fed83c66af47f5430147842fff5c64896..8f495e17ad08d9b20196da2336b633d072d7f06d 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListContract.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListContract.kt @@ -18,6 +18,8 @@ interface FriendsListContract { fun showSendChallengeRequestFailed(reason: String) /** Let the user know that sending a challenge request has failed because no pool has been selected **/ fun showSendChallengeRequestFailedNoPoolsSelected() + /** Let the user know that sending a challenge request has failed because both players have no common pools **/ + fun showSendChallengeRequestFailedNoPoolsInCommon() /** Let the user know that sending a challenge request was successful **/ fun showSendChallengeRequestSuccess(friendName: String) /** Bind the SearchListAdapter to the recycler view by passing a list of users **/ diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListInteractor.kt b/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListInteractor.kt index 34dcce7fe5919871aa67d9dbea6b7fecbc3cc9c3..bbebe2571305a27127e42a037d00ffad39f8d0f1 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListInteractor.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListInteractor.kt @@ -33,6 +33,10 @@ class FriendsListInteractor(private val dataSource: FriendsDataSourceImpl) : Fri callback.onChallengeRequestFailedNoPoolsSelected() } + override fun onChallengeRequestFailedNoPoolsInCommon() { + callback.onChallengeRequestFailedNoPoolsInCommon() + } + }) } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListPresenter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListPresenter.kt index f0ddbf28ce30c06b8e71334bd3080c6b37f6f257..f744673252c7ca60feb08b3389bd80e4e864721a 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListPresenter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/friends/FriendsListPresenter.kt @@ -76,6 +76,11 @@ class FriendsListPresenter( callback.indicateChallengeSentFailed() } + override fun onChallengeRequestFailedNoPoolsInCommon() { + view?.showSendChallengeRequestFailedNoPoolsInCommon() + callback.indicateChallengeSentFailed() + } + }) } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginActivity.kt b/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginActivity.kt index 6afb88ba476961ac23c69c076961a121ef398905..ff42f60060a6fbbd4acfccbe741e401378b98df2 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginActivity.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginActivity.kt @@ -5,11 +5,13 @@ import android.os.Bundle import android.view.KeyEvent import android.view.View import android.view.inputmethod.EditorInfo +import androidx.preference.PreferenceManager import de.akamu.tudarmstadt.BaseActivity import de.akamu.tudarmstadt.R import de.akamu.tudarmstadt.data.login.LoginDataSourceImpl import de.akamu.tudarmstadt.features.dashboard.MainActivity import de.akamu.tudarmstadt.features.dse.DSEActivity +import de.akamu.tudarmstadt.features.password.ForgotPasswordActivity import de.akamu.tudarmstadt.model.User import de.akamu.tudarmstadt.util.AppUserUtil import de.akamu.tudarmstadt.util.Constants @@ -21,13 +23,6 @@ class LoginActivity : BaseActivity(), LoginContract.View { override lateinit var presenter: LoginContract.Presenter - override fun onStart() { - super.onStart() - if (!presenter.unauthorized) { - presenter.autoLogin() - } - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setTheme(R.style.OffWhiteTheme) @@ -38,10 +33,15 @@ class LoginActivity : BaseActivity(), LoginContract.View { this ) - presenter.unauthorized = intent.getBooleanExtra(Constants.KEY_UNAUTHORIZED, false) + val isUnauthorized = intent.getBooleanExtra(Constants.KEY_UNAUTHORIZED, false) + PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(Constants.PREF_UNAUTHORIZED, isUnauthorized).apply() logo_login.start() + forgot_password_button.setOnClickListener { + startActivity(Intent(this, ForgotPasswordActivity::class.java)) + } + login_button.setOnClickListener { val username: String = login_username_input.text.toString() val password: String = login_password_input.text.toString() @@ -64,6 +64,13 @@ class LoginActivity : BaseActivity(), LoginContract.View { } } + override fun onStart() { + super.onStart() + if (!PreferenceManager.getDefaultSharedPreferences(this).getBoolean(Constants.PREF_UNAUTHORIZED, true)) { + presenter.autoLogin() + } + } + override fun showLoginFailed() { toast(getString(R.string.invalid_username_or_password)) } @@ -84,6 +91,7 @@ class LoginActivity : BaseActivity(), LoginContract.View { override fun isLoggedIn(loggedIn: Boolean, appUser: User) { if (loggedIn) { AppUserUtil.updateLocalAppUser(appUser, this) + PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean(Constants.PREF_UNAUTHORIZED, false).apply() startActivity(Intent(this, MainActivity::class.java)) finish() } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginContract.kt b/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginContract.kt index b2f5819e45f59a89b014675a4777050cdf5791b9..a63536c52700035eac92a274b53b4661bb301c6a 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginContract.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginContract.kt @@ -41,8 +41,6 @@ interface LoginContract { interface Presenter : BasePresenter { - var unauthorized : Boolean - /** Checks if the user is already logged in and if so, navigates to MainActivity */ fun autoLogin() diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginPresenter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginPresenter.kt index e6929f1d73e6ea003ce045f1686a8d19e1a77e21..9a1575c5a78072312ebc6a02d9f8d5d85a14a1c3 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginPresenter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/login/LoginPresenter.kt @@ -1,14 +1,14 @@ package de.akamu.tudarmstadt.features.login +import androidx.preference.PreferenceManager import de.akamu.tudarmstadt.api.AkamuFirebase import de.akamu.tudarmstadt.api.V2API import de.akamu.tudarmstadt.data.login.LoginDataSource import de.akamu.tudarmstadt.model.User +import de.akamu.tudarmstadt.util.Constants class LoginPresenter(private val interactor: LoginInteractor, var view: LoginContract.View?) : LoginContract.Presenter { - override var unauthorized: Boolean = false - init { view?.presenter = this } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordActivity.kt b/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordActivity.kt index c37d070e42a01fd6cb8bbb66f3bb6cc5b746199a..8e85c0998616e562b5f8b055abf64ca207c5e596 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordActivity.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordActivity.kt @@ -29,7 +29,7 @@ class ChangePasswordActivity : supportActionBar?.setDisplayHomeAsUpEnabled(true) - presenter = ChangePasswordPresenter(ChangePasswordInteractor(PasswordDataSourceImpl()), + presenter = ChangePasswordPresenter(PasswordInteractor(PasswordDataSourceImpl()), UserInteractor(UserDataSourceImpl()), this) user = AppUserUtil.getLocalAppUser(this) @@ -68,6 +68,7 @@ class ChangePasswordActivity : override fun showPasswordIncorrect() { Snackbar.make(findViewById(R.id.coordinator_change_password), getString(R.string.failed_to_change_password) + getString(R.string.error_invalid_password), Snackbar.LENGTH_LONG).show() + changepw_current.error = getString(R.string.error_invalid_password) } override fun showPasswordsMismatch() { @@ -80,8 +81,16 @@ class ChangePasswordActivity : getString(R.string.failed_to_change_password) + getString(R.string.error_invalid_password_short), Snackbar.LENGTH_LONG).show() } + override fun showOldPasswordEmpty() { + changepw_current.error = getString(R.string.please_enter_your_current_password) + } + override fun showUpdatingPassword() { changepw_progress_text.text = getString(R.string.updating_password) changepw_progress_container.visibility = View.VISIBLE } + + override fun handleUnauthorizedEvent() { + //Don't handle unauthorized event + } } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordContract.kt b/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordContract.kt index 3431882ab5fd94e3eee539baf30010b14319073a..721f6b8b65dbf0e54dc0d008cea0586683c1f322 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordContract.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordContract.kt @@ -17,6 +17,7 @@ interface ChangePasswordContract { fun showPasswordsMismatch() fun showPasswordTooShort() fun showUpdatingPassword() + fun showOldPasswordEmpty() /** Hide the indeterminate progress bar, that is shown to the user while processing the changed password **/ fun hideProgress() } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordInteractor.kt b/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordInteractor.kt deleted file mode 100644 index 9c1175e604cfa534fd73c247ecca78e8cdf9da44..0000000000000000000000000000000000000000 --- a/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordInteractor.kt +++ /dev/null @@ -1,25 +0,0 @@ -package de.akamu.tudarmstadt.features.password - -import de.akamu.tudarmstadt.data.password.PasswordDataSource -import de.akamu.tudarmstadt.model.User - -class ChangePasswordInteractor(private val dataSource: PasswordDataSource) : PasswordDataSource { - - override fun verifyPassword(user: User, password: String, firebaseToken: String, callback: PasswordDataSource.VerifyPasswordDataSource) { - dataSource.verifyPassword(user, password, firebaseToken, object : PasswordDataSource.VerifyPasswordDataSource { - override fun passwordCorrect() { - callback.passwordCorrect() - } - - override fun passwordInCorrect() { - callback.passwordInCorrect() - } - - override fun passwordError(msg: String) { - callback.passwordError(msg) - } - - }) - } - -} \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordPresenter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordPresenter.kt index 4ee42f3c602678b2264d88aa1428c602ff39a37b..69f25f6f7eab9244e4a7e7c0549345334d784580 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordPresenter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/password/ChangePasswordPresenter.kt @@ -5,8 +5,9 @@ import de.akamu.tudarmstadt.data.password.PasswordDataSource import de.akamu.tudarmstadt.data.user.UserDataSource import de.akamu.tudarmstadt.interactors.UserInteractor import de.akamu.tudarmstadt.model.User +import de.akamu.tudarmstadt.util.Constants -class ChangePasswordPresenter(private val interactor: ChangePasswordInteractor, +class ChangePasswordPresenter(private val interactor: PasswordInteractor, private val userInteractor: UserInteractor, private var view: ChangePasswordContract.View?) : ChangePasswordContract.Presenter { @@ -17,8 +18,13 @@ class ChangePasswordPresenter(private val interactor: ChangePasswordInteractor, override fun changePassword(user: User, currentPw: String, newPw: String, newPw2: String) { + if (currentPw.isEmpty()) { + view?.showOldPasswordEmpty() + return + } + // Check if new passwords are valid - if(!isPasswordValid(newPw, newPw2) || currentPw.isEmpty()) { + if(!isPasswordValid(newPw, newPw2)) { return } @@ -27,7 +33,7 @@ class ChangePasswordPresenter(private val interactor: ChangePasswordInteractor, AkamuFirebase.loadFirebaseToken(object : AkamuFirebase.GetFirebaseTokenCallback { override fun onGetFirebaseTokenSuccess(firebaseToken: String) { - interactor.verifyPassword(user, currentPw, firebaseToken, object: PasswordDataSource.VerifyPasswordDataSource { + interactor.verifyPassword(user, currentPw, firebaseToken, object: PasswordDataSource.VerifyPasswordCallback { override fun passwordCorrect() { user.password = newPw updateUserWithNewPW(newPw) @@ -58,7 +64,8 @@ class ChangePasswordPresenter(private val interactor: ChangePasswordInteractor, private fun isPasswordValid(newPw: String, newPw2: String) : Boolean { - if(newPw.isEmpty() || newPw2.isEmpty()) { + if(newPw.isEmpty() || newPw2.isEmpty() || newPw.length < Constants.MIN_PASSWORD_LENGTH) { + view?.showPasswordTooShort() return false } @@ -67,11 +74,6 @@ class ChangePasswordPresenter(private val interactor: ChangePasswordInteractor, return false } - if(newPw.length < 6) { - view?.showPasswordTooShort() - return false - } - return true } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordActivity.kt b/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..b1853e33f7ac909f41987a5e6be6f74f1788335c --- /dev/null +++ b/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordActivity.kt @@ -0,0 +1,70 @@ +package de.akamu.tudarmstadt.features.password + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import com.google.android.material.snackbar.Snackbar +import de.akamu.tudarmstadt.R +import de.akamu.tudarmstadt.data.password.PasswordDataSourceImpl +import de.akamu.tudarmstadt.data.user.UserDataSourceImpl +import de.akamu.tudarmstadt.interactors.UserInteractor +import de.akamu.tudarmstadt.model.User +import de.akamu.tudarmstadt.util.AppUserUtil +import kotlinx.android.synthetic.main.activity_change_password.* +import kotlinx.android.synthetic.main.activity_forgot_password.* + +class ForgotPasswordActivity : AppCompatActivity(), ForgotPasswordContract.View, + View.OnClickListener { + + override lateinit var presenter: ForgotPasswordContract.Presenter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setTheme(R.style.BlueTheme) + setContentView(R.layout.activity_forgot_password) + setSupportActionBar(toolbar_forgot_password) + + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + forgot_password_confirm_btn.setOnClickListener(this) + presenter = ForgotPasswordPresenter(PasswordInteractor(PasswordDataSourceImpl()), this) + } + + override fun onClick(v: View?) { + if (v!!.id == forgot_password_confirm_btn.id) { + val usernameOrEmail = forgot_password_input_text.text.toString() + presenter.requestNewPassword(usernameOrEmail) + } + } + + override fun showRequestNewPasswordSuccess() { + Snackbar.make(findViewById(R.id.coordinator_forgot_password), + R.string.email_sent, Snackbar.LENGTH_LONG).show() + } + + override fun showRequestNewPasswordFailed(reason: String) { + Snackbar.make(findViewById(R.id.coordinator_forgot_password), + getString(R.string.failed_to_send_email, reason), Snackbar.LENGTH_LONG).show() + } + + override fun showNoSuchUserError() { + Snackbar.make(findViewById(R.id.coordinator_forgot_password), + R.string.no_such_user, Snackbar.LENGTH_LONG).show() + } + + override fun disableConfirmButton() { + forgot_password_confirm_btn.visibility = View.GONE + } + + override fun enableConfirmButton() { + forgot_password_confirm_btn.visibility = View.VISIBLE + } + + override fun showProgress() { + forgot_password_progress_container.visibility = View.VISIBLE + } + + override fun hideProgress() { + forgot_password_progress_container.visibility = View.GONE + } +} \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordContract.kt b/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordContract.kt new file mode 100644 index 0000000000000000000000000000000000000000..f92c435689ae28114c0822aa5536a8467b2bcfe6 --- /dev/null +++ b/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordContract.kt @@ -0,0 +1,20 @@ +package de.akamu.tudarmstadt.features.password + +import de.akamu.tudarmstadt.BasePresenter +import de.akamu.tudarmstadt.BaseView + +class ForgotPasswordContract { + interface View : BaseView { + fun showRequestNewPasswordSuccess() + fun showRequestNewPasswordFailed(reason: String) + fun showNoSuchUserError() + fun disableConfirmButton() + fun enableConfirmButton() + fun showProgress() + fun hideProgress() + } + + interface Presenter : BasePresenter { + fun requestNewPassword(usernameOrEmail: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordPresenter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordPresenter.kt new file mode 100644 index 0000000000000000000000000000000000000000..e286d6f2a6fa72361481fb449102d48306c62b93 --- /dev/null +++ b/app/src/main/java/de/akamu/tudarmstadt/features/password/ForgotPasswordPresenter.kt @@ -0,0 +1,40 @@ +package de.akamu.tudarmstadt.features.password + +import de.akamu.tudarmstadt.data.password.PasswordDataSource + +class ForgotPasswordPresenter(private val interactor: PasswordInteractor, + private var view: ForgotPasswordContract.View?) + : ForgotPasswordContract.Presenter { + + init { + view?.presenter = this + } + + override fun requestNewPassword(usernameOrEmail: String) { + view?.disableConfirmButton() + view?.showProgress() + interactor.requestNewPassword(usernameOrEmail, object : PasswordDataSource.RequestNewPasswordCallback { + override fun onRequestNewPasswordSuccess() { + view?.hideProgress() + view?.enableConfirmButton() + view?.showRequestNewPasswordSuccess() + } + + override fun onRequestNewPasswordFailed(reason: String) { + view?.hideProgress() + view?.enableConfirmButton() + view?.showRequestNewPasswordFailed(reason) + } + + override fun onNoSuchUserError() { + view?.hideProgress() + view?.enableConfirmButton() + view?.showNoSuchUserError() + } + }) + } + + override fun stop() { + view = null + } +} \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/password/PasswordInteractor.kt b/app/src/main/java/de/akamu/tudarmstadt/features/password/PasswordInteractor.kt new file mode 100644 index 0000000000000000000000000000000000000000..d1b275179ed482ff54855c179f262acd2e0d8323 --- /dev/null +++ b/app/src/main/java/de/akamu/tudarmstadt/features/password/PasswordInteractor.kt @@ -0,0 +1,54 @@ +package de.akamu.tudarmstadt.features.password + +import de.akamu.tudarmstadt.data.password.PasswordDataSource +import de.akamu.tudarmstadt.model.User + +class PasswordInteractor(private val dataSource: PasswordDataSource) : PasswordDataSource { + + override fun verifyPassword( + user: User, + password: String, + firebaseToken: String, + callback: PasswordDataSource.VerifyPasswordCallback + ) { + dataSource.verifyPassword( + user, + password, + firebaseToken, + object : PasswordDataSource.VerifyPasswordCallback { + override fun passwordCorrect() { + callback.passwordCorrect() + } + + override fun passwordInCorrect() { + callback.passwordInCorrect() + } + + override fun passwordError(msg: String) { + callback.passwordError(msg) + } + + }) + } + + override fun requestNewPassword( + usernameOrEmail: String, + callback: PasswordDataSource.RequestNewPasswordCallback + ) { + dataSource.requestNewPassword(usernameOrEmail, object : PasswordDataSource.RequestNewPasswordCallback { + override fun onRequestNewPasswordSuccess() { + callback.onRequestNewPasswordSuccess() + } + + override fun onRequestNewPasswordFailed(reason: String) { + callback.onRequestNewPasswordFailed(reason) + } + + override fun onNoSuchUserError() { + callback.onNoSuchUserError() + } + + }) + } + +} \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/profile/AvatarGridAdapter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/profile/AvatarGridAdapter.kt index 02ca23f5d0c39a512c2531f315c6e81a462f5058..6f2aeb8b5ad570127997b4529031f9345c2d9632 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/profile/AvatarGridAdapter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/profile/AvatarGridAdapter.kt @@ -7,6 +7,7 @@ import android.view.ViewGroup import android.widget.AdapterView import android.widget.ImageView import android.widget.TextView +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import de.akamu.tudarmstadt.R @@ -93,7 +94,7 @@ class AvatarGridAdapter( .into(avatarImg) } else { Glide.with(context) - .load(context.getDrawable(R.drawable.lockavatar)) + .load(ContextCompat.getDrawable(context, R.drawable.lockavatar)) .into(avatarImg) } avatarUnlockLevel.text = String.format("LVL %d", mAvatar.level) diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/profile/ProfileActivity.kt b/app/src/main/java/de/akamu/tudarmstadt/features/profile/ProfileActivity.kt index e86b9fc9285ed9098862844deb816a9174ca51fc..da33628bb15b2f433f23483c8473ee88187b880d 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/profile/ProfileActivity.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/profile/ProfileActivity.kt @@ -1,17 +1,24 @@ package de.akamu.tudarmstadt.features.profile import android.app.Activity +import android.app.AlertDialog +import android.content.DialogInterface import android.content.Intent import android.os.Bundle import android.view.MenuItem import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.TextView import android.widget.Toast import androidx.appcompat.widget.Toolbar +import androidx.core.content.ContextCompat import com.afollestad.materialdialogs.MaterialDialog import com.google.android.material.snackbar.Snackbar import de.akamu.tudarmstadt.BaseActivity import de.akamu.tudarmstadt.R import de.akamu.tudarmstadt.data.user.UserDataSourceImpl +import de.akamu.tudarmstadt.features.dashboard.MainActivity import de.akamu.tudarmstadt.features.settings.SettingsActivity import de.akamu.tudarmstadt.features.login.LoginActivity import de.akamu.tudarmstadt.features.password.ChangePasswordActivity @@ -128,16 +135,30 @@ class ProfileActivity : BaseActivity(), ProfileContract.View, } fun onLogoutClick(@Suppress("UNUSED_PARAMETER") v: View) { - MaterialDialog(this).show { - title(text = getString(R.string.sign_out)) - message(text = getString(R.string.confirm_sign_out)) - positiveButton(text = getString(R.string.sign_out)) { - presenter.logout() - } - negativeButton(R.string.cancel) { - it.dismiss() - } + lateinit var infoDialog: AlertDialog + val builder = AlertDialog.Builder(this, R.style.DialogStyle) + builder.setTitle(getString(R.string.sign_out)) + val infoTextView = TextView(this) + infoTextView.text = getString(R.string.confirm_sign_out) + infoTextView.setTextColor(ContextCompat.getColor(this, R.color.textLight)) + val container = FrameLayout(this) + val params = FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + params.leftMargin = resources.getDimensionPixelSize(R.dimen.dialog_margin) + params.rightMargin = resources.getDimensionPixelSize(R.dimen.dialog_margin) + infoTextView.layoutParams = params + container.addView(infoTextView) + builder.setView(container) + builder.setPositiveButton(getString(R.string.sign_out)) { _: DialogInterface, _: Int -> + presenter.logout() + } + builder.setNegativeButton(getString(R.string.cancel)) { dialog, _ -> + dialog.cancel() } + infoDialog = builder.create() + infoDialog.show() } override fun destroyLoginToken() { diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/profile/ProfilePresenter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/profile/ProfilePresenter.kt index 59ec8690e487c329c44dde0bb084d3824e511dda..c4065d77eec62f5dab9b820983cb9300a0413673 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/profile/ProfilePresenter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/profile/ProfilePresenter.kt @@ -6,6 +6,7 @@ import de.akamu.tudarmstadt.interactors.UserInteractor import de.akamu.tudarmstadt.model.Avatar import de.akamu.tudarmstadt.model.User import java.util.* +import kotlin.collections.ArrayList import kotlin.collections.HashMap class ProfilePresenter(private var view: ProfileContract.View?, private val interactor: UserInteractor) : ProfileContract.Presenter { @@ -14,7 +15,7 @@ class ProfilePresenter(private var view: ProfileContract.View?, private val inte var allAvatarsFetched = false lateinit var unlockedAvatars : SortedMap - lateinit var allAvatars : SortedMap + lateinit var allAvatars : ArrayList var avatars: HashMap = HashMap() init { @@ -50,10 +51,10 @@ class ProfilePresenter(private var view: ProfileContract.View?, private val inte } override fun loadAllAvatarsFromServer() { - interactor.loadAllAvatarsFromServer(object : UserDataSource.LoadAvatarListCallback { - override fun onLoadAvatarListSuccess(avatarSortedMap: SortedMap) { + interactor.loadAllAvatarsFromServer(object : UserDataSource.LoadAllAvatarListCallback { + override fun onLoadAvatarListSuccess(avatarList: ArrayList) { allAvatarsFetched = true - allAvatars = avatarSortedMap + allAvatars = avatarList handleCallbacksReady() } @@ -65,7 +66,7 @@ class ProfilePresenter(private var view: ProfileContract.View?, private val inte } override fun loadUnlockedAvatarsFromServer() { - interactor.loadUnlockedAvatarsFromServer(object : UserDataSource.LoadAvatarListCallback { + interactor.loadUnlockedAvatarsFromServer(object : UserDataSource.LoadUnlockedAvatarListCallback { override fun onLoadAvatarListSuccess(avatarSortedMap: SortedMap) { unlockedAvatarsFetched = true unlockedAvatars = avatarSortedMap @@ -99,12 +100,14 @@ class ProfilePresenter(private var view: ProfileContract.View?, private val inte } } - fun prepareAvatars() { - for (av in allAvatars.keys) { + private fun prepareAvatars() { + for (av in allAvatars) { if (unlockedAvatars.contains(av)) { av.isUnlocked = true + avatars[av] = unlockedAvatars[av]!! + } else { + avatars[av] = byteArrayOf() // leave empty will be set later } - avatars[av] = allAvatars[av]!! } } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/questions/ContinueDuelFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/questions/ContinueDuelFragment.kt index 99d3dc0169ad96aff93e7b14cf1019e74e32c863..77b65d9ce554168ede009047c85480707690f1df 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/questions/ContinueDuelFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/questions/ContinueDuelFragment.kt @@ -12,6 +12,7 @@ import kotlinx.android.synthetic.main.fragment_continue_duel.* class ContinueDuelFragment : Fragment() { lateinit var onContinueDuelHandler: OnContinueDuelHandler + lateinit var presenter: QuestionContract.Presenter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -23,8 +24,16 @@ class ContinueDuelFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - button_continue_without_explanation.setOnClickListener {onContinueDuelHandler.onContinueWithoutExplanationClicked() } - button_continue_with_explanation.setOnClickListener { onContinueDuelHandler.onContinueWithExplanationClicked() } + + presenter = (activity as QuestionContract.View).presenter + + // Explanation button + if (presenter.isExplanationThere()) { + button_continue_with_explanation.setOnClickListener { onContinueDuelHandler.onContinueWithExplanationClicked() } + } else { + button_continue_with_explanation.visibility = View.GONE + } + button_continue_without_explanation.setOnClickListener { onContinueDuelHandler.onContinueWithoutExplanationClicked() } } override fun onAttach(context: Context) { diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionActivity.kt b/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionActivity.kt index 827d025d453f7116914757bc5cfb5dd660cbef9b..b6df77651dfdb06e2676d9ab4ecb6fc870f2e46f 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionActivity.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionActivity.kt @@ -13,6 +13,7 @@ import android.widget.EditText import android.widget.FrameLayout import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import de.akamu.tudarmstadt.R import de.akamu.tudarmstadt.data.duel.DuelDataSourceImpl import de.akamu.tudarmstadt.features.dashboard.MainActivity @@ -268,6 +269,7 @@ class QuestionActivity : params.leftMargin = resources.getDimensionPixelSize(R.dimen.dialog_margin) params.rightMargin = resources.getDimensionPixelSize(R.dimen.dialog_margin) input.layoutParams = params + input.setTextColor(ContextCompat.getColor(this, R.color.textLight)) container.addView(input) builder.setView(container) builder.setPositiveButton(getString(R.string.send_feedback)) { _: DialogInterface, _: Int -> diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionContract.kt b/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionContract.kt index 142afb7d80f9c86e257998270954906d90deabd3..85087a74e9474f4398b2b8e4231a1bd68da7963f 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionContract.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionContract.kt @@ -64,6 +64,8 @@ interface QuestionContract { fun submitUserOptionAnswer(selectedAnswerItemIds: IntArray) /** Finds the correct answerItem **/ fun getCorrectAnswerItem(answer: MultipleChoiceAnswer) : MultipleChoiceAnswerItem + /** Return true if an explanation is given **/ + fun isExplanationThere(): Boolean } } \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionPresenter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionPresenter.kt index 1764a588a7b097a9b4c4541f7cc555d0c9781324..cfb14b8a41097b94e81a14fe4c26d516c724fdd4 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionPresenter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/questions/QuestionPresenter.kt @@ -7,7 +7,10 @@ import de.akamu.tudarmstadt.model.* import de.akamu.tudarmstadt.util.Constants -class QuestionPresenter(private val interactor: DuelInteractor, private var view: QuestionContract.View?) : +class QuestionPresenter( + private val interactor: DuelInteractor, + private var view: QuestionContract.View? +) : QuestionContract.Presenter { /** @@ -73,16 +76,19 @@ class QuestionPresenter(private val interactor: DuelInteractor, private var view } override fun sendQuestionReport(feedbackText: String) { - interactor.reportQuestion(currentQuestion.id, feedbackText, object : DuelDataSource.ReportQuestionCallback { - override fun onReportQuestionSuccess() { - view?.showReportQuestionSuccess() - } + interactor.reportQuestion( + currentQuestion.id, + feedbackText, + object : DuelDataSource.ReportQuestionCallback { + override fun onReportQuestionSuccess() { + view?.showReportQuestionSuccess() + } - override fun onReportQuestionFailed(reason: String) { - view?.showReportQuestionFailed(reason) - } + override fun onReportQuestionFailed(reason: String) { + view?.showReportQuestionFailed(reason) + } - }) + }) } override fun next() { @@ -165,6 +171,10 @@ class QuestionPresenter(private val interactor: DuelInteractor, private var view throw AkamuAPIException(1002, "Logical internal error: Question has no correct answer.") } + override fun isExplanationThere(): Boolean { + return currentQuestion.explanation.text != null && currentQuestion.explanation.text != "" + } + override fun stop() { view = null } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/LongOptionsAnswerFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/LongOptionsAnswerFragment.kt index beed339d4370644fb2287a5b13376aab15ee923f..8bfd21d9850ebe6422d2be40e7bbc3b64968e12c 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/LongOptionsAnswerFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/LongOptionsAnswerFragment.kt @@ -103,6 +103,7 @@ class LongOptionsAnswerFragment : AnswerFragment(), View.OnClickListener { e.printStackTrace() } } + deactivateButtons() } private fun findViewForCorrectAnswerItem(correctAnswerItem: MultipleChoiceAnswerItem): View? { @@ -161,4 +162,11 @@ class LongOptionsAnswerFragment : AnswerFragment(), View.OnClickListener { return f } } + + fun deactivateButtons() { + button_questionlongansfragment_answer1.isClickable = false + button_questionlongansfragment_answer2.isClickable = false + button_questionlongansfragment_answer3.isClickable = false + button_questionlongansfragment_answer4.isClickable = false + } } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/ShortOptionsAnswerFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/ShortOptionsAnswerFragment.kt index 32048abe3fa9f24f1172b2c0f89ac2ca1077fba8..4ec56e708ac3a2f59366a4a0f9bc2ac3c6e5ab8c 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/ShortOptionsAnswerFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/ShortOptionsAnswerFragment.kt @@ -68,26 +68,33 @@ class ShortOptionsAnswerFragment : AnswerFragment(), View.OnClickListener { listener?.onShortOptionsAnswerClicked(answer.items[i]) } } - if(answer.items[i].isCorrect) { + if (answer.items[i].isCorrect) { presenter.userAnswers.add(true) v?.setBackgroundResource(R.drawable.button_answer_correct_ripple) } else { presenter.userAnswers.add(false) v?.setBackgroundResource(R.drawable.button_answer_wrong_ripple) try { - val correctAnswerItem = (activity as QuestionActivity).presenter.getCorrectAnswerItem(answer) + val correctAnswerItem = + (activity as QuestionActivity).presenter.getCorrectAnswerItem(answer) val cv = findViewForCorrectAnswerItem(correctAnswerItem) val anim = AnimationUtils.loadAnimation(activity, R.anim.wobble) cv?.setBackgroundResource(R.drawable.button_answer_correct_ripple) cv?.startAnimation(anim) } catch (e: AkamuAPIException) { - Toast.makeText(activity, "Logical internal error: " + e.code, Toast.LENGTH_SHORT).show() + Toast.makeText(activity, "Logical internal error: " + e.code, Toast.LENGTH_SHORT) + .show() e.printStackTrace() } catch (e: Exception) { - Toast.makeText(activity, "Unknown error in ShortOptionsAnswerFragment", Toast.LENGTH_SHORT).show() + Toast.makeText( + activity, + "Unknown error in ShortOptionsAnswerFragment", + Toast.LENGTH_SHORT + ).show() e.printStackTrace() } } + deactivateButtons() } private fun findViewForCorrectAnswerItem(correctAnswerItem: MultipleChoiceAnswerItem): View? { @@ -117,6 +124,13 @@ class ShortOptionsAnswerFragment : AnswerFragment(), View.OnClickListener { }*/ + fun deactivateButtons() { + button_questionshortansfragment_answer1.isClickable = false + button_questionshortansfragment_answer2.isClickable = false + button_questionshortansfragment_answer3.isClickable = false + button_questionshortansfragment_answer4.isClickable = false + } + override fun onAttach(context: Context) { super.onAttach(context) if (context is OnShortOptionsAnswerClickHandler) { diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/SwipeAnswerFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/SwipeAnswerFragment.kt index 72707bad6c0f8d057291af4aa5e65e59e0169350..e5f6c481583f906d51248b546e1c9fba4396bd63 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/SwipeAnswerFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/SwipeAnswerFragment.kt @@ -110,7 +110,7 @@ class SwipeAnswerFragment : } private fun showShortSummary() { - recyclerView_swipe_shortSummary.visibility = View.VISIBLE + constraintlayout_swipe_shortSummary.visibility = View.VISIBLE swipeFlingAdapterView?.visibility = View.GONE recyclerView_swipe_shortSummary.bringToFront() mShortSummaryAdapter = SwipeAnswerShortSummaryAdapter(requireActivity(), answer.items, presenter.userAnswers) diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/SwipeAnswerShortSummaryAdapter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/SwipeAnswerShortSummaryAdapter.kt index 260b39493e685e624f5559edb533c088ac1da476..cc5eec76d2aabadc723d617814032ca971af469c 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/SwipeAnswerShortSummaryAdapter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/questions/answers/SwipeAnswerShortSummaryAdapter.kt @@ -1,10 +1,12 @@ package de.akamu.tudarmstadt.features.questions.answers import android.content.Context +import android.graphics.Paint import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import de.akamu.tudarmstadt.R import de.akamu.tudarmstadt.model.MultipleChoiceAnswerItem @@ -24,7 +26,7 @@ class SwipeAnswerShortSummaryAdapter( } override fun onBindViewHolder(holder: SwipeAnswerShortSummaryAdapter.SwipeShortSummaryViewHolder, position: Int) { - holder.bind(userAnswers[position], answerItems[position].text) + holder.bind(userAnswers[position], answerItems[position]) } /** @@ -38,16 +40,24 @@ class SwipeAnswerShortSummaryAdapter( private var answerTextView : TextView = itemView.findViewById(R.id.textView_swipe_answer_short_summary_answerText) private var indicator : TextView = itemView.findViewById(R.id.textView_swipe_answer_short_summary_indicator) + private var leftIndicator : View = itemView.findViewById(R.id.view_swipe_answer_shortSummary_left_indicator) - fun bind(correct: Boolean, answerText: String?) { - answerTextView.text = answerText - if (correct) { + fun bind(answeredCorrectly: Boolean, answerItem: MultipleChoiceAnswerItem) { + answerTextView.text = answerItem.text + if (answeredCorrectly) { indicator.text = mContext.getString(R.string.correct) indicator.background = mContext.getDrawable(R.drawable.background_indicator_correct) } else { indicator.text = mContext.getString(R.string.wrong) indicator.background = mContext.getDrawable(R.drawable.background_indicator_wrong) } + if (answerItem.isCorrect) { + leftIndicator.setBackgroundResource(R.color.akamu_green) + //answerTextView.setTextColor(ContextCompat.getColor(mContext, R.color.akamu_green)) + } else { + leftIndicator.setBackgroundResource(R.color.colorLost) + //answerTextView.setTextColor(ContextCompat.getColor(mContext, R.color.colorLost)) + } } } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/settings/SettingsActivity.kt b/app/src/main/java/de/akamu/tudarmstadt/features/settings/SettingsActivity.kt index 69a83cc84ad38b799178f962dcc243d6bc3402b5..c342edec1d07b3cedb2eb4b2c5d04ebfeabf08b3 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/settings/SettingsActivity.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/settings/SettingsActivity.kt @@ -11,6 +11,7 @@ import kotlinx.android.synthetic.main.activity_settings.* class SettingsActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setTheme(R.style.BlueTheme) setContentView(R.layout.activity_settings) supportActionBar?.setDisplayHomeAsUpEnabled(true) diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/settings/SettingsFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/settings/SettingsFragment.kt index 8df2749870ce41ca2f0aaabb4150b85d3d840dec..81e50667ead020ae5f6bc393ea014c94db5f47bb 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/settings/SettingsFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/settings/SettingsFragment.kt @@ -1,15 +1,16 @@ package de.akamu.tudarmstadt.features.settings import android.content.Intent -import android.content.SharedPreferences +import android.os.Build import android.os.Bundle import androidx.preference.* import com.google.android.gms.oss.licenses.OssLicensesMenuActivity import com.google.firebase.crashlytics.FirebaseCrashlytics +import com.yariksoffice.lingver.Lingver import de.akamu.tudarmstadt.R +import de.akamu.tudarmstadt.features.dashboard.MainActivity import de.akamu.tudarmstadt.features.dse.DSEActivity import de.akamu.tudarmstadt.util.Constants -import de.akamu.tudarmstadt.util.LocaleManager class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener, @@ -19,10 +20,10 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - // val langPref = findPreference(getString(R.string.pref_language_key)) + val langPref = findPreference(getString(R.string.pref_language_key)) val closedDuelPref = findPreference(getString(R.string.pref_closed_duels_key)) - // langPref!!.onPreferenceChangeListener = this + langPref!!.onPreferenceChangeListener = this closedDuelPref!!.onPreferenceChangeListener = this val dseInfoPref = findPreference(getString(R.string.pref_privacy_policy_key)) dseInfoPref?.onPreferenceClickListener = this @@ -43,7 +44,7 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan if (preference != null) { when (preference.key) { getString(R.string.pref_language_key) -> { - changeLanguage() + changeLanguage((newValue as String)) return true } getString(R.string.pref_closed_duels_key) -> { @@ -80,11 +81,26 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan startActivity(dse) } - private fun changeLanguage() { - LocaleManager.setLocale(context) - val refresh = Intent(context, activity!!::class.java) - startActivity(refresh) + private fun changeLanguage(lang: String) { + if (lang == requireActivity().resources.getString(R.string.pref_language_sys_value)) { + Lingver.getInstance().setFollowSystemLocale(requireActivity()) + val intent = Intent(requireActivity(), MainActivity::class.java) + requireActivity().finish() + startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) + return + } + val currentLang = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + resources.configuration.locales.get(0).language + } else { + resources.configuration.locale.language + } + if (currentLang == lang) return + PreferenceManager.getDefaultSharedPreferences(requireActivity()).edit() + .putString(Constants.USER_LANG, lang).apply() + Lingver.getInstance().setLocale(requireActivity(), lang) + val intent = Intent(requireActivity(), MainActivity::class.java) requireActivity().finish() + startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) } private fun changeClosedDuels(newValue: String) { diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/signup/SignupActivity.kt b/app/src/main/java/de/akamu/tudarmstadt/features/signup/SignupActivity.kt index ef03bd4864d1ea9437e284c11b69c15fdd9ea0b4..e935beb1313f4713a5e626b4dd99fbacddc2bfb9 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/signup/SignupActivity.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/signup/SignupActivity.kt @@ -1,10 +1,11 @@ package de.akamu.tudarmstadt.features.signup +import android.content.Context import android.content.Intent import android.os.Bundle -import android.os.Message +import android.view.MotionEvent import android.view.View -import androidx.lifecycle.ViewModelStore +import android.view.inputmethod.InputMethodManager import com.stepstone.stepper.StepperLayout import com.stepstone.stepper.VerificationError import de.akamu.tudarmstadt.BaseActivity diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/signup/email/EmailFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/signup/email/EmailFragment.kt index b426a59e8ddec5c232d10ec0f09fad032d9af7ba..076a3601e2dd2def3ac7571428d56d27a6d3ecdf 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/signup/email/EmailFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/signup/email/EmailFragment.kt @@ -20,7 +20,7 @@ import kotlinx.android.synthetic.main.fragment_email.* class EmailFragment : Fragment(), EmailContract.View, Step { - private var errorStringInvalidEmail: String = "error" + private lateinit var errorStringInvalidEmail: String override lateinit var presenter: EmailContract.Presenter override lateinit var signupPresenter: SignupContract.Presenter diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/signup/email/EmailPresenter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/signup/email/EmailPresenter.kt index 28ef69232f44b3bd47ea09c61df5aad5c812084b..307c8533b059c14c3b7f7b5314147e609744d4bc 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/signup/email/EmailPresenter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/signup/email/EmailPresenter.kt @@ -9,8 +9,7 @@ class EmailPresenter(var view: EmailContract.View?) : EmailContract.Presenter { } override fun checkEmail(email: String) { - // if (email.endsWith("@stud.tu-darmstadt.de")) { - if (true) { + if (email.endsWith("@stud.tu-darmstadt.de")) { view?.showEmailValid() } else { view?.showEmailNotValid() diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/signup/password/PasswordFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/signup/password/PasswordFragment.kt index 75c0a22635b82881c8554730aae7694a9eda9c30..8965e579f1875ededa9169741bbedf9986e391c2 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/signup/password/PasswordFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/signup/password/PasswordFragment.kt @@ -15,6 +15,7 @@ import com.stepstone.stepper.VerificationError import de.akamu.tudarmstadt.R import de.akamu.tudarmstadt.features.signup.SignupActivity import de.akamu.tudarmstadt.features.signup.SignupContract +import de.akamu.tudarmstadt.util.Constants import de.akamu.tudarmstadt.util.Extensions.Companion.toast import kotlinx.android.synthetic.main.fragment_password.* @@ -25,8 +26,8 @@ class PasswordFragment : Fragment(), PasswordContract.View, Step { private var errorStringNotEqual: String = "error" private var errorStringNotUpperLower: String = "error" - var ve1 : VerificationError? = null - var ve2 : VerificationError? = null + var ve1: VerificationError? = null + var ve2: VerificationError? = null override lateinit var presenter: PasswordContract.Presenter override var signupPresenter: SignupContract.Presenter? = null @@ -50,10 +51,21 @@ class PasswordFragment : Fragment(), PasswordContract.View, Step { super.onActivityCreated(savedInstanceState) signupPresenter = (activity as SignupActivity).presenter + textView_password_info.text = getString( + R.string.password_rules, + Constants.MIN_PASSWORD_LENGTH, + Constants.MAX_PASSWORD_LENGTH + ) + val signUpFirstPasswordOnEditorActionListener = SignUpFirstPasswordOnEditorActionListener() - val signUpSecondPasswordOnEditorActionListener = SignUpSecondPasswordOnEditorActionListener() - textinputedittext_signup_password1.setOnEditorActionListener(signUpFirstPasswordOnEditorActionListener) - textinputedittext_signup_password2.setOnEditorActionListener(signUpSecondPasswordOnEditorActionListener) + val signUpSecondPasswordOnEditorActionListener = + SignUpSecondPasswordOnEditorActionListener() + textinputedittext_signup_password1.setOnEditorActionListener( + signUpFirstPasswordOnEditorActionListener + ) + textinputedittext_signup_password2.setOnEditorActionListener( + signUpSecondPasswordOnEditorActionListener + ) } override fun showFirstPasswordValid() { @@ -128,12 +140,14 @@ class PasswordFragment : Fragment(), PasswordContract.View, Step { // activity?.toast(error.errorMessage) } - private inner class SignUpFirstPasswordOnEditorActionListener : TextView.OnEditorActionListener { + private inner class SignUpFirstPasswordOnEditorActionListener : + TextView.OnEditorActionListener { override fun onEditorAction(textView: TextView, id: Int, keyEvent: KeyEvent?): Boolean { if (id == EditorInfo.IME_ACTION_NEXT || id == EditorInfo.IME_NULL) { presenter.checkFirstPassword(textinputedittext_signup_password1.text.toString()) - if(ve1 == null){ - val imm = activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? + if (ve1 == null) { + val imm = + activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? imm!!.hideSoftInputFromWindow( textinputlayout_signup_password1.windowToken, InputMethodManager.RESULT_UNCHANGED_SHOWN @@ -145,15 +159,17 @@ class PasswordFragment : Fragment(), PasswordContract.View, Step { } } - private inner class SignUpSecondPasswordOnEditorActionListener : TextView.OnEditorActionListener { + private inner class SignUpSecondPasswordOnEditorActionListener : + TextView.OnEditorActionListener { override fun onEditorAction(textView: TextView, id: Int, keyEvent: KeyEvent?): Boolean { if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) { presenter.checkSecondPassword( textinputedittext_signup_password1.text.toString(), textinputedittext_signup_password2.text.toString() ) - if(ve2 == null){ - val imm = activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? + if (ve2 == null) { + val imm = + activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? imm!!.hideSoftInputFromWindow( textinputlayout_signup_password2.windowToken, InputMethodManager.RESULT_UNCHANGED_SHOWN diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/signup/password/PasswordPresenter.kt b/app/src/main/java/de/akamu/tudarmstadt/features/signup/password/PasswordPresenter.kt index 2b96941574a2a8d605f8827c4b6e6cd55c78c71f..f50ea202300f23ed4088dff0c7b0324bb217dbdf 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/signup/password/PasswordPresenter.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/signup/password/PasswordPresenter.kt @@ -62,7 +62,7 @@ class PasswordPresenter(var view: PasswordContract.View?) checkSecondPassword(password1, password2) } - fun containsUpperAndLowerChar(password: String) : Boolean { + private fun containsUpperAndLowerChar(password: String) : Boolean { return password != password.toLowerCase(Locale.ROOT) && password != password.toUpperCase(Locale.ROOT) } diff --git a/app/src/main/java/de/akamu/tudarmstadt/features/signup/username/UsernameFragment.kt b/app/src/main/java/de/akamu/tudarmstadt/features/signup/username/UsernameFragment.kt index f2e7e9604751bf3e4757b2b0c8181837cdeda56b..365b8676b5dae566cac00094fb4e5f51e282a297 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/features/signup/username/UsernameFragment.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/features/signup/username/UsernameFragment.kt @@ -1,10 +1,8 @@ package de.akamu.tudarmstadt.features.signup.username +import android.app.Activity import android.content.Context -import android.os.AsyncTask import android.os.Bundle -import android.os.Handler -import android.os.Looper import android.view.KeyEvent import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/de/akamu/tudarmstadt/interactors/UserInteractor.kt b/app/src/main/java/de/akamu/tudarmstadt/interactors/UserInteractor.kt index 7714a55472bf4458543763b7102a012a604972a1..f4008d3a7ed3fbcaea4b1c9d563881cc42b81054 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/interactors/UserInteractor.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/interactors/UserInteractor.kt @@ -4,6 +4,7 @@ import de.akamu.tudarmstadt.data.user.UserDataSource import de.akamu.tudarmstadt.model.Avatar import de.akamu.tudarmstadt.model.User import java.util.* +import kotlin.collections.ArrayList class UserInteractor(private val dataSource: UserDataSource) : UserDataSource { override fun updateUserInServer(user: User, callback: UserDataSource.UpdateUserCallback) { @@ -59,10 +60,10 @@ class UserInteractor(private val dataSource: UserDataSource) : UserDataSource { }) } - override fun loadAllAvatarsFromServer(callback: UserDataSource.LoadAvatarListCallback) { - dataSource.loadAllAvatarsFromServer(object: UserDataSource.LoadAvatarListCallback{ - override fun onLoadAvatarListSuccess(avatarSortedMap: SortedMap) { - callback.onLoadAvatarListSuccess(avatarSortedMap) + override fun loadAllAvatarsFromServer(callback: UserDataSource.LoadAllAvatarListCallback) { + dataSource.loadAllAvatarsFromServer(object: UserDataSource.LoadAllAvatarListCallback{ + override fun onLoadAvatarListSuccess(avatarList: ArrayList) { + callback.onLoadAvatarListSuccess(avatarList) } override fun onLoadAvatarListFail(reason: String) { @@ -72,8 +73,8 @@ class UserInteractor(private val dataSource: UserDataSource) : UserDataSource { }) } - override fun loadUnlockedAvatarsFromServer(callback: UserDataSource.LoadAvatarListCallback) { - dataSource.loadUnlockedAvatarsFromServer(object: UserDataSource.LoadAvatarListCallback{ + override fun loadUnlockedAvatarsFromServer(callback: UserDataSource.LoadUnlockedAvatarListCallback) { + dataSource.loadUnlockedAvatarsFromServer(object: UserDataSource.LoadUnlockedAvatarListCallback { override fun onLoadAvatarListSuccess(avatarSortedMap: SortedMap) { callback.onLoadAvatarListSuccess(avatarSortedMap) } diff --git a/app/src/main/java/de/akamu/tudarmstadt/util/AkamuResource.kt b/app/src/main/java/de/akamu/tudarmstadt/util/AkamuResource.kt index 5e6c3a24e4952a57319fb9bf92be39e4513f8142..ec09cd038d101e1dfb5538dbb373add45533ee2e 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/util/AkamuResource.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/util/AkamuResource.kt @@ -17,7 +17,7 @@ class AkamuResource { return } } - val glideUrl = GlideUrl("https://dev.akamu.de/api/v2/resource/$resId") { + val glideUrl = GlideUrl(V2API.getBaseURL() + "resource/$resId") { mapOf(Pair("Authorization", "Bearer ${V2API.getToken()}")) } diff --git a/app/src/main/java/de/akamu/tudarmstadt/util/Constants.kt b/app/src/main/java/de/akamu/tudarmstadt/util/Constants.kt index 687ce34786d85dc8bc9f295a85f6e015b14afe73..cdc1705748108c890058df39eec52bba8fefdd56 100644 --- a/app/src/main/java/de/akamu/tudarmstadt/util/Constants.kt +++ b/app/src/main/java/de/akamu/tudarmstadt/util/Constants.kt @@ -24,7 +24,7 @@ class Constants { const val ITEM_TYPE_DUEL_FINISHED = 2 // LOGIN AND SIGNUP - const val MIN_PASSWORD_LENGTH = 6 + const val MIN_PASSWORD_LENGTH = 8 const val MAX_PASSWORD_LENGTH = 50 const val MIN_USERNAME_LENGTH = 4 const val MAX_USERNAME_LENGTH = 12 @@ -34,6 +34,7 @@ class Constants { const val KEY_POOL = "KEY_POOL" const val KEY_UNAUTHORIZED = "KEY_UNAUTHORIZED" const val KEY_DSE_INFO = "DSE_INFO" + const val KEY_MAINACTIVITY_PAGE = "KEY_MAINACTIVITY_PAGE" // ARG KEYS const val KEY_OPTION_ANSWER = "OPTION_ANSWER" @@ -52,5 +53,7 @@ class Constants { const val CLOSED_DUELS_KEY = "CLOSED_DUELS_KEY" const val BUG_REPORTS_ENABLED_KEY = "BUG_REPORTS_ENABLED_KEY" const val IS_NIGHT_MODE = "IS_NIGHT_MODE" + const val USER_LANG = "USER_LANG" + const val PREF_UNAUTHORIZED = "PREF_UNAUTHORIZED" } } \ No newline at end of file diff --git a/app/src/main/java/de/akamu/tudarmstadt/util/LocaleManager.java b/app/src/main/java/de/akamu/tudarmstadt/util/LocaleManager.java deleted file mode 100644 index 786d976f2d54dc245a906a70dcbe136d82701861..0000000000000000000000000000000000000000 --- a/app/src/main/java/de/akamu/tudarmstadt/util/LocaleManager.java +++ /dev/null @@ -1,67 +0,0 @@ -package de.akamu.tudarmstadt.util; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.preference.PreferenceManager; -import de.akamu.tudarmstadt.R; - -import java.util.Locale; - -/** - * This helper class is used for updating the app's locale. - * - * @author Patrick Christ - * @version 1.0.1 - * @since 1.0.1 - */ -public class LocaleManager { - - /** - * Sets the given Context with an Locale including the currently supported language. - * - * @param c the current context - * @return the context set with the appropriate Locale - * @author Patrick Christ - * @version 1.0.1 - * @since 1.0.1 - */ - public static Context setLocale(Context c) { - return updateResources(c, getLanguage(c)); - } - - /** - * Returns the language currently stored in SharedPreferences. - * - * @param c the current context - * @return the language saved in SharedPreferences - * @author Patrick Christ - * @version 1.0.1 - * @since 1.0.1 - */ - private static String getLanguage(Context c) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c); - return prefs.getString(c.getResources().getString(R.string.pref_language_key), c.getResources().getString(R.string.pref_language_eng_value)); - } - - /** - * Updates the App's resources with the given language. - * - * @param context the current context - * @param language the language to include in App's resources - * @return the context set with the appropriate Locale - * @author Patrick Christ - * @version 1.0.1 - * @since 1.0.1 - */ - private static Context updateResources(Context context, String language) { - Locale locale = new Locale(language); - Locale.setDefault(locale); - Resources res = context.getResources(); - Configuration config = new Configuration(res.getConfiguration()); - config.setLocale(locale); - context = context.createConfigurationContext(config); - return context; - } -} \ No newline at end of file diff --git a/app/src/main/res/drawable-anydpi/ic_bug_report.xml b/app/src/main/res/drawable-anydpi/ic_bug_report.xml index e6eec40f566b9a2b6c17f7cdc04ea1aa1bdce0c0..7d8ea532d70838bf2ee1c036b5b9518625ff65d2 100644 --- a/app/src/main/res/drawable-anydpi/ic_bug_report.xml +++ b/app/src/main/res/drawable-anydpi/ic_bug_report.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="#000000" + android:tint="@color/iconBlack" android:alpha="0.8"> + + diff --git a/app/src/main/res/drawable-anydpi/ic_closed_duels.xml b/app/src/main/res/drawable-anydpi/ic_closed_duels.xml index 47b27d56276f6496d2d4262b3758f21c73b3ca70..2f22f8908b9c655e773b20356ef868db3b5b6494 100644 --- a/app/src/main/res/drawable-anydpi/ic_closed_duels.xml +++ b/app/src/main/res/drawable-anydpi/ic_closed_duels.xml @@ -3,8 +3,9 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="#333333"> - + android:tint="@color/iconBlack" + android:alpha="0.8"> + diff --git a/app/src/main/res/drawable-anydpi/ic_code.xml b/app/src/main/res/drawable-anydpi/ic_code.xml index 787e3c9227856274fa92d4056adaefd38fd6311f..afcdd29c329a552e8eaa6d6652fa99344c134b0a 100644 --- a/app/src/main/res/drawable-anydpi/ic_code.xml +++ b/app/src/main/res/drawable-anydpi/ic_code.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="#000000" + android:tint="@color/iconBlack" android:alpha="0.8"> + android:tint="@color/iconAccent"> diff --git a/app/src/main/res/drawable-anydpi/ic_language.xml b/app/src/main/res/drawable-anydpi/ic_language.xml index 3e7b1430b62a15b9ff816a4dd707742d1796863e..82fc3e3889def97ce884d6a6a966e8b67fae0914 100644 --- a/app/src/main/res/drawable-anydpi/ic_language.xml +++ b/app/src/main/res/drawable-anydpi/ic_language.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="#000000" + android:tint="@color/iconBlack" android:alpha="0.8"> + + diff --git a/app/src/main/res/drawable-hdpi/ic_akamu_notification_white.png b/app/src/main/res/drawable-hdpi/ic_akamu_notification_white.png new file mode 100644 index 0000000000000000000000000000000000000000..cdf2c80615dbfd0b6c157289824dfe1a58bc87bf Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_akamu_notification_white.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_close_dark.png b/app/src/main/res/drawable-hdpi/ic_close_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..7ac5ef405ca0f72b8489f551e2cd48b46f79adb0 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_close_dark.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_closed_duels.png b/app/src/main/res/drawable-hdpi/ic_closed_duels.png index 9b553e9f0d702cf3428c26b9f06f2bde6c1a76d0..a51dfb0e44da5a330ff8c4f0960a570b9861de94 100644 Binary files a/app/src/main/res/drawable-hdpi/ic_closed_duels.png and b/app/src/main/res/drawable-hdpi/ic_closed_duels.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_search.png b/app/src/main/res/drawable-hdpi/ic_search.png new file mode 100644 index 0000000000000000000000000000000000000000..017e93caa04e581b257e79db1d809db93beab3f7 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_search.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_akamu_notification_white.png b/app/src/main/res/drawable-mdpi/ic_akamu_notification_white.png new file mode 100644 index 0000000000000000000000000000000000000000..0f18dabdb5e17376ebc5232ab3dc01ea04e376eb Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_akamu_notification_white.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_close_dark.png b/app/src/main/res/drawable-mdpi/ic_close_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..31c164ceb29e6885f1e6c85d79518d4f0e4f68f0 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_close_dark.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_closed_duels.png b/app/src/main/res/drawable-mdpi/ic_closed_duels.png index 7dfe9c4d7f87f01c7b26fa28b3937078f50d673a..57e5dad78363498e0c14ee0b35959c3ea27667f3 100644 Binary files a/app/src/main/res/drawable-mdpi/ic_closed_duels.png and b/app/src/main/res/drawable-mdpi/ic_closed_duels.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_search.png b/app/src/main/res/drawable-mdpi/ic_search.png new file mode 100644 index 0000000000000000000000000000000000000000..d86216377bd4d31cd0868f4cc340ebafe4d11027 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_search.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_akamu_notification_white.png b/app/src/main/res/drawable-xhdpi/ic_akamu_notification_white.png new file mode 100644 index 0000000000000000000000000000000000000000..e68b264893309f8f702def35c7c22305c9e87709 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_akamu_notification_white.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_close_dark.png b/app/src/main/res/drawable-xhdpi/ic_close_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..ca66c38898154dbf08c1fb8681ff16126b6137f2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_close_dark.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_closed_duels.png b/app/src/main/res/drawable-xhdpi/ic_closed_duels.png index adc04d7e449a78841d62587d51d19dbcfa7c549d..be06585bce5dda4dc8e565ff92e33580ed459743 100644 Binary files a/app/src/main/res/drawable-xhdpi/ic_closed_duels.png and b/app/src/main/res/drawable-xhdpi/ic_closed_duels.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_search.png b/app/src/main/res/drawable-xhdpi/ic_search.png new file mode 100644 index 0000000000000000000000000000000000000000..65b0915bf72e714067106483722130606b946814 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_search.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_akamu_notification_white.png b/app/src/main/res/drawable-xxhdpi/ic_akamu_notification_white.png new file mode 100644 index 0000000000000000000000000000000000000000..22e5f4a5c2074b82b2a6e725734f80b998b1983b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_akamu_notification_white.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_close_dark.png b/app/src/main/res/drawable-xxhdpi/ic_close_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..b499ceaf3ae4494a11ea4aaba2691b53ea2230fe Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_close_dark.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_closed_duels.png b/app/src/main/res/drawable-xxhdpi/ic_closed_duels.png index 2dcb86ca493f6ce36b589874a84396f71a9ce1f5..4dcf1c3db11cf936cf6822cdb17c0cae308916b7 100644 Binary files a/app/src/main/res/drawable-xxhdpi/ic_closed_duels.png and b/app/src/main/res/drawable-xxhdpi/ic_closed_duels.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_search.png b/app/src/main/res/drawable-xxhdpi/ic_search.png new file mode 100644 index 0000000000000000000000000000000000000000..594bcc40263de44380c743737dbe7e2162934b49 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_search.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_akamu_notification_white.png b/app/src/main/res/drawable-xxxhdpi/ic_akamu_notification_white.png new file mode 100644 index 0000000000000000000000000000000000000000..62e69b71e6deed8d84100691c9a19d91dab0f903 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_akamu_notification_white.png differ diff --git a/app/src/main/res/layout/activity_change_password.xml b/app/src/main/res/layout/activity_change_password.xml index 15d895c4ef3aa08278787e467b69c5678e73d0b5..a227c8c981f6796b207f186cd75b0174e4de19b7 100644 --- a/app/src/main/res/layout/activity_change_password.xml +++ b/app/src/main/res/layout/activity_change_password.xml @@ -58,11 +58,13 @@ android:layout_marginTop="50dp" android:layout_marginEnd="@dimen/activity_margin_side" android:hint="@string/current_password" + android:textColor="@color/darkText" + android:textColorHint="@color/textLight" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView_changepassword_descr" app:passwordToggleEnabled="true" - app:passwordToggleTint="@color/colorPrimary"> + app:passwordToggleTint="@color/akamu_blue"> + app:passwordToggleTint="@color/akamu_blue" + android:backgroundTint="@color/textLight"/> @@ -82,11 +85,13 @@ android:layout_marginTop="@dimen/activity_margin_top" android:layout_marginEnd="@dimen/activity_margin_side" android:hint="@string/enter_new_password" + android:textColor="@color/darkText" + android:textColorHint="@color/textLight" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textinputlayout_changepasswordscreen_currentpw" app:passwordToggleEnabled="true" - app:passwordToggleTint="@color/colorPrimary"> + app:passwordToggleTint="@color/akamu_blue"> + app:passwordToggleTint="@color/akamu_blue" + android:backgroundTint="@color/textLight" /> @@ -106,11 +112,13 @@ android:layout_marginTop="@dimen/activity_margin_top" android:layout_marginEnd="@dimen/activity_margin_side" android:hint="@string/confirm_new_password" + android:textColor="@color/darkText" + android:textColorHint="@color/textLight" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textinputlayout_changepasswordscreen_enterpassword" app:passwordToggleEnabled="true" - app:passwordToggleTint="@color/colorPrimary"> + app:passwordToggleTint="@color/akamu_blue"> + app:passwordToggleTint="@color/akamu_blue" + android:backgroundTint="@color/textLight" /> diff --git a/app/src/main/res/layout/activity_forgot_password.xml b/app/src/main/res/layout/activity_forgot_password.xml new file mode 100644 index 0000000000000000000000000000000000000000..3ee7bfcb0b4ba2b4183dbb21197ae52b6c1bbcf0 --- /dev/null +++ b/app/src/main/res/layout/activity_forgot_password.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + +