diff --git a/app/build.gradle b/app/build.gradle index c8d87ab..80e301f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.denizd.substitutionplan" minSdkVersion 21 targetSdkVersion 28 - versionCode 37 - versionName "2.2.14" + versionCode 38 + versionName "2.3.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 46b3b8c..0f37854 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,6 +18,13 @@ android:supportsRtl="true" tools:ignore="GoogleAppIndexingWarning"> + + (R.id.coordinatorLayout) + parentLayout.layoutTransition.enableTransitionType(LayoutTransition.CHANGING) + val barColour = when { Build.VERSION.SDK_INT < Build.VERSION_CODES.M -> ContextCompat.getColor(context, R.color.legacyBlack) Build.VERSION.SDK_INT <= Build.VERSION_CODES.P -> ContextCompat.getColor(context, R.color.colorBackground) @@ -111,12 +115,11 @@ internal class FirstTime : AppCompatActivity(R.layout.activity_first_time) { .putBoolean("colourTransferred", true) .apply() - val cLayout = findViewById(R.id.coordinatorLayout) val linearInflation = findViewById(R.id.linearInflation) val x: Int = fab.right - fab.width / 2 - val y: Int = fab.bottom- fab.height / 2 - val endRadius = hypot(cLayout.width.toDouble(), cLayout.height.toDouble()).toInt() + val y: Int = fab.bottom - fab.height / 2 + val endRadius = hypot(parentLayout.width.toDouble(), parentLayout.height.toDouble()).toInt() inflater.inflate(R.layout.welcome_screen, linearInflation, true) val anim = ViewAnimationUtils.createCircularReveal(linearInflation, x, y, 0F, endRadius.toFloat()) val handler = Handler() @@ -147,11 +150,11 @@ internal class FirstTime : AppCompatActivity(R.layout.activity_first_time) { val mImgCheck = findViewById(R.id.imageView).drawable as AnimatedVectorDrawableCompat mImgCheck.start() } - }, 1000) + }, 600) handler.postDelayed({ startActivity(mainActivity) finish() - }, 2000) + }, 3000) } } diff --git a/app/src/main/java/com/denizd/substitutionplan/activities/Login.kt b/app/src/main/java/com/denizd/substitutionplan/activities/Login.kt new file mode 100644 index 0000000..e5f725a --- /dev/null +++ b/app/src/main/java/com/denizd/substitutionplan/activities/Login.kt @@ -0,0 +1,132 @@ +package com.denizd.substitutionplan.activities + +import android.animation.LayoutTransition +import android.annotation.SuppressLint +import android.content.Intent +import android.content.SharedPreferences +import android.graphics.drawable.AnimatedVectorDrawable +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.preference.PreferenceManager +import android.view.View +import android.view.ViewAnimationUtils +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import android.webkit.WebView +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.app.AppCompatDelegate +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat +import com.denizd.substitutionplan.R +import com.denizd.substitutionplan.data.LoginWebViewClient +import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton +import kotlin.math.hypot + +internal class Login : AppCompatActivity(R.layout.activity_login_webview), LoginWebViewClient.OnLoginSuccessListener { + + private lateinit var prefs: SharedPreferences + private lateinit var parentLayout: ConstraintLayout + private lateinit var logInButton: ExtendedFloatingActionButton + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setTheme(R.style.AppTheme0) + parentLayout = findViewById(R.id.constraintLayout) + parentLayout.layoutTransition.enableTransitionType(LayoutTransition.CHANGING) + val title = findViewById(R.id.txtWelcome) + prefs = PreferenceManager.getDefaultSharedPreferences(this) + + val barColour = when { + Build.VERSION.SDK_INT < Build.VERSION_CODES.M -> ContextCompat.getColor(this, R.color.legacyBlack) + Build.VERSION.SDK_INT <= Build.VERSION_CODES.P -> ContextCompat.getColor(this, R.color.colorBackground) + else -> 0 + } + if (barColour != 0) { + window.navigationBarColor = barColour + window.statusBarColor = barColour + } + if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_NO) { + if (Build.VERSION.SDK_INT in 23..28) { + @SuppressLint("InlinedApi") + window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + } + } + + logInButton = findViewById(R.id.loginFab) + logInButton.setOnClickListener { + findViewById(R.id.linearLayout).apply { + logInButton.hide() + removeAllViews() + title.text = getString(R.string.logging_in) + val view = View.inflate(this@Login, R.layout.webview, null) + addView(view) + val webView = view.findViewById(R.id.webView) + webView.webViewClient = LoginWebViewClient(this@Login) + openLoginPage(webView) + handler.postDelayed({ + webView.scrollY = -4000 + }, 2000) + } + } + } + + override fun onLoginSucceeded(success: Boolean) { + if (success) { + success() + } + } + + private fun openLoginPage(webView: WebView) { + webView.loadUrl("https://307.joomla.schule.bremen.de/index.php/component/users/#top") + } + + private fun success() { + prefs.edit().putBoolean("successful_login", true).apply() + + val layoutAfterCircleReveal = findViewById(R.id.layoutAfterCircleReveal) + + val x: Int = logInButton.right - logInButton.width / 2 + val y: Int = logInButton.bottom - logInButton.height / 2 + val endRadius = hypot(parentLayout.width.toDouble(), parentLayout.height.toDouble()).toInt() + View.inflate(this, R.layout.unlock_screen, layoutAfterCircleReveal) + val anim = ViewAnimationUtils.createCircularReveal(layoutAfterCircleReveal, x, y, 0F, endRadius.toFloat()) + val handler = Handler() + val animOut = AnimationUtils.loadAnimation(this, R.anim.fade_out_short) + anim.duration = 600 + val colour = findViewById(R.id.colourLayout) + layoutAfterCircleReveal.visibility = View.VISIBLE + anim.start() + logInButton.hide() + + handler.postDelayed({ + colour.startAnimation(animOut) + }, 400) + animOut.setAnimationListener(object: Animation.AnimationListener { + override fun onAnimationStart(arg0: Animation) {} + override fun onAnimationRepeat(arg0: Animation) {} + override fun onAnimationEnd(arg0: Animation) { + colour.visibility = View.GONE + } + }) + handler.postDelayed({ + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { + val mImgCheck = findViewById(R.id.imageView).drawable as AnimatedVectorDrawable + mImgCheck.start() + } else { + val mImgCheck = findViewById(R.id.imageView).drawable as AnimatedVectorDrawableCompat + mImgCheck.start() + } + }, 600) + handler.postDelayed({ + val main = Intent(this, Main::class.java) + startActivity(main) + finish() + }, 3000) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/denizd/substitutionplan/activities/Main.kt b/app/src/main/java/com/denizd/substitutionplan/activities/Main.kt index 035674c..7dee1a2 100644 --- a/app/src/main/java/com/denizd/substitutionplan/activities/Main.kt +++ b/app/src/main/java/com/denizd/substitutionplan/activities/Main.kt @@ -43,13 +43,17 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) context = this - prefs = PreferenceManager.getDefaultSharedPreferences(context) as SharedPreferences + prefs = PreferenceManager.getDefaultSharedPreferences(context) val edit = prefs.edit() val firstTime = Intent(context, FirstTime::class.java) + val login = Intent(context, Login::class.java) Crashlytics.setUserIdentifier(prefs.getString("username", "") ?: "") - if (prefs.getBoolean("firstTime", true)) { -// if (true) { + if (!prefs.getBoolean("successful_login", false)) { + startActivity(login) + finish() + } else if (prefs.getBoolean("firstTime", true)) { +// } else if (true) { startActivity(firstTime) finish() } else { @@ -238,10 +242,10 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) { } private fun personalPlanTitle(): String { - return if (prefs.getBoolean("greeting", true)) { + val user = prefs.getString("username", "") ?: "" + return if (prefs.getBoolean("greeting", true) || user.isEmpty()) { getString(R.string.yourPlan) } else { - val user = prefs.getString("username", "") ?: "" if (user.endsWith("s", true) || user.endsWith("x", true) || user.endsWith("z", true)) { "$user${getString(R.string.noSPlan)}" } else { diff --git a/app/src/main/java/com/denizd/substitutionplan/adapters/ColourAdapter.kt b/app/src/main/java/com/denizd/substitutionplan/adapters/ColourAdapter.kt index 8e59358..1206311 100644 --- a/app/src/main/java/com/denizd/substitutionplan/adapters/ColourAdapter.kt +++ b/app/src/main/java/com/denizd/substitutionplan/adapters/ColourAdapter.kt @@ -29,10 +29,7 @@ internal class ColourAdapter(private var mColours: List, onClickListener override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ColourViewHolder { val v = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false) - return ColourViewHolder( - v, - mOnClickListener - ) + return ColourViewHolder(v, mOnClickListener) } override fun onBindViewHolder(holder: ColourViewHolder, position: Int) { diff --git a/app/src/main/java/com/denizd/substitutionplan/data/LoginWebViewClient.kt b/app/src/main/java/com/denizd/substitutionplan/data/LoginWebViewClient.kt new file mode 100644 index 0000000..5d58cac --- /dev/null +++ b/app/src/main/java/com/denizd/substitutionplan/data/LoginWebViewClient.kt @@ -0,0 +1,46 @@ +package com.denizd.substitutionplan.data + +import android.webkit.CookieManager +import android.webkit.WebView +import android.webkit.WebViewClient + +/** + * class that extends WebViewClient to provide a function that checks the webpage's cookies to + * verify a login + * + * @param successListener a reference to the OnLoginSuccessListener implemented in an activity + */ +internal class LoginWebViewClient(successListener: OnLoginSuccessListener) : WebViewClient() { + + private val mSuccessListener = successListener + + /** + * onPageFinished has been overridden to check if the cookie "joomla_user_state=logged_in" + * exists, and returns true to the OnLoginSuccessListener + * + * @param view a reference to the WebView + * @param url a reference to the url of the WebView + */ + override fun onPageFinished(view: WebView?, url: String?) { + super.onPageFinished(view, url) + val cookies = CookieManager.getInstance().getCookie(url) + + if (cookies.contains("joomla_user_state=logged_in")) { + mSuccessListener.onLoginSucceeded(true) + } + } + + /** + * the interface that provides onLoginSucceeded to the activity or fragment that implements it + */ + internal interface OnLoginSuccessListener { + + /** + * the function that can be overridden to check whether a successful login has occurred + * + * @param success boolean value that returns true if the cookie could be found, + * false otherwise + */ + fun onLoginSucceeded(success: Boolean) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/denizd/substitutionplan/fragments/SettingsFragment.kt b/app/src/main/java/com/denizd/substitutionplan/fragments/SettingsFragment.kt index 14bbb14..4f21148 100644 --- a/app/src/main/java/com/denizd/substitutionplan/fragments/SettingsFragment.kt +++ b/app/src/main/java/com/denizd/substitutionplan/fragments/SettingsFragment.kt @@ -47,7 +47,6 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl private lateinit var prefs: SharedPreferences private val builder = CustomTabsIntent.Builder() private val customTabsIntent = builder.build() as CustomTabsIntent - private var cs: Int = 7 private var window: Window? = null private lateinit var colourRecycler: RecyclerView private lateinit var ringtoneCustomiserDialog: AlertDialog @@ -253,19 +252,6 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl "\n---\n" + "\nThis privacy policy was modified upon the template provided by privacypolicytemplate.net and App Privacy Policy Generator. These services are in no way affiliated with AvH Plan or the developer.") } - R.id.btnVersion -> { - if (cs > 0) { - cs-- - } else { - try { - cs = 7 - customTabsIntent.launchUrl(mContext, Uri.parse("http://www.flussufer.de/gerd/person.htm")) - makeToast(getString(R.string.dontTellHim)) - } catch (e: ActivityNotFoundException) { - makeToast(getString(R.string.chromeCompatibleNotFound)) - } - } - } R.id.btnForceRefresh -> { DataFetcher( isPlan = true, diff --git a/app/src/main/java/com/denizd/substitutionplan/services/FBPingService.kt b/app/src/main/java/com/denizd/substitutionplan/services/FBPingService.kt index 656ed68..6b79681 100644 --- a/app/src/main/java/com/denizd/substitutionplan/services/FBPingService.kt +++ b/app/src/main/java/com/denizd/substitutionplan/services/FBPingService.kt @@ -25,28 +25,30 @@ internal class FBPingService : JobService() { private fun doBackgroundWork(params: JobParameters) { val prefs = PreferenceManager.getDefaultSharedPreferences(context) FirebaseApp.initializeApp(context) - FirebaseMessaging.getInstance().apply { - if (prefs.getBoolean("notif", true)) { - subscribeToTopic(Topic.ANDROID.tag) - } else { - unsubscribeFromTopic(Topic.ANDROID.tag) + if (!prefs.getBoolean("firstTime", true)) { + FirebaseMessaging.getInstance().apply { + if (prefs.getBoolean("notif", true)) { + subscribeToTopic(Topic.ANDROID.tag) + } else { + unsubscribeFromTopic(Topic.ANDROID.tag) + } + + if (prefs.getBoolean("subscribedToFBDebugChannel", false)) { + subscribeToTopic(Topic.DEVELOPMENT.tag) + } else { + unsubscribeFromTopic(Topic.DEVELOPMENT.tag) + } + + if (prefs.getBoolean("subscribedToiOSChannel", false)) { + subscribeToTopic(Topic.IOS.tag) + } else { + unsubscribeFromTopic(Topic.IOS.tag) + } + + subscribeToTopic(Topic.BROADCAST.tag) + + prefs.edit().putInt("pingFB", prefs.getInt("pingFB", 0) + 1).apply() } - - if (prefs.getBoolean("subscribedToFBDebugChannel", false)) { - subscribeToTopic(Topic.DEVELOPMENT.tag) - } else { - unsubscribeFromTopic(Topic.DEVELOPMENT.tag) - } - - if (prefs.getBoolean("subscribedToiOSChannel", false)) { - subscribeToTopic(Topic.IOS.tag) - } else { - unsubscribeFromTopic(Topic.IOS.tag) - } - - subscribeToTopic(Topic.BROADCAST.tag) - - prefs.edit().putInt("pingFB", prefs.getInt("pingFB", 0) + 1).apply() } jobFinished(params, false) } diff --git a/app/src/main/res/animator/unlock_animation.xml b/app/src/main/res/animator/unlock_animation.xml new file mode 100644 index 0000000..feda24f --- /dev/null +++ b/app/src/main/res/animator/unlock_animation.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/animated_lock.xml b/app/src/main/res/drawable/animated_lock.xml new file mode 100644 index 0000000..49e9937 --- /dev/null +++ b/app/src/main/res/drawable/animated_lock.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/check_mark.xml b/app/src/main/res/drawable/check_mark.xml index 95337e7..8ebbbf9 100644 --- a/app/src/main/res/drawable/check_mark.xml +++ b/app/src/main/res/drawable/check_mark.xml @@ -3,18 +3,18 @@ android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0"> - - - + + + + + + + android:strokeColor="@color/colorAccent" + android:strokeWidth="2" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_closed_lock.xml b/app/src/main/res/drawable/ic_closed_lock.xml new file mode 100644 index 0000000..6a19fca --- /dev/null +++ b/app/src/main/res/drawable/ic_closed_lock.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_open_lock.xml b/app/src/main/res/drawable/ic_open_lock.xml new file mode 100644 index 0000000..9fafe85 --- /dev/null +++ b/app/src/main/res/drawable/ic_open_lock.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_first_time.xml b/app/src/main/res/layout/activity_first_time.xml index 5ad70ef..d16eee0 100644 --- a/app/src/main/res/layout/activity_first_time.xml +++ b/app/src/main/res/layout/activity_first_time.xml @@ -1,5 +1,5 @@ - + tools:context=".activities.FirstTime" + android:animateLayoutChanges="true"> + android:translationZ="-1dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toTopOf="@+id/snackBarLayout"/> + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml new file mode 100644 index 0000000..33315b0 --- /dev/null +++ b/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + +