add onboarding (login), change default theme to dark

closes #14
This commit is contained in:
2021-01-16 00:16:47 +01:00
parent 3f45d769d2
commit 8a22554846
34 changed files with 514 additions and 67 deletions

View File

@ -1,8 +1,9 @@
package org.mosad.teapod
package org.mosad.teapod.activity
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.mosad.teapod.activity.main.MainActivity
class SplashActivity : AppCompatActivity() {

View File

@ -20,7 +20,7 @@
*
*/
package org.mosad.teapod
package org.mosad.teapod.activity.main
import android.content.Intent
import android.os.Bundle
@ -34,16 +34,18 @@ import com.afollestad.materialdialogs.callbacks.onDismiss
import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.runBlocking
import org.mosad.teapod.R
import org.mosad.teapod.databinding.ActivityMainBinding
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.player.PlayerActivity
import org.mosad.teapod.activity.player.PlayerActivity
import org.mosad.teapod.preferences.EncryptedPreferences
import org.mosad.teapod.preferences.Preferences
import org.mosad.teapod.ui.components.LoginDialog
import org.mosad.teapod.ui.fragments.AccountFragment
import org.mosad.teapod.ui.fragments.HomeFragment
import org.mosad.teapod.ui.fragments.LibraryFragment
import org.mosad.teapod.ui.fragments.SearchFragment
import org.mosad.teapod.activity.main.fragments.AccountFragment
import org.mosad.teapod.activity.main.fragments.HomeFragment
import org.mosad.teapod.activity.main.fragments.LibraryFragment
import org.mosad.teapod.activity.main.fragments.SearchFragment
import org.mosad.teapod.activity.onboarding.OnboardingActivity
import org.mosad.teapod.util.DataTypes
import org.mosad.teapod.util.StorageController
import java.net.SocketTimeoutException
@ -120,8 +122,8 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
private fun getThemeResource(): Int {
return when (Preferences.theme) {
DataTypes.Theme.DARK -> R.style.AppTheme_Dark
else -> R.style.AppTheme_Light
DataTypes.Theme.LIGHT -> R.style.AppTheme_Light
else -> R.style.AppTheme_Dark
}
}
@ -138,22 +140,23 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
EncryptedPreferences.readCredentials(this)
StorageController.load(this)
try {
// make sure credentials are set, run's async
if (EncryptedPreferences.password.isEmpty()) {
showLoginDialog(true)
} else {
// try to login in, as most sites can only bee loaded once loged in
if (!AoDParser.login()) showLoginDialog(false)
}
} catch (ex: SocketTimeoutException) {
Log.w(javaClass.name, "Timeout during login!")
// show onbaording
if (EncryptedPreferences.password.isEmpty()) {
showOnboarding()
} else {
try {
if (!AoDParser.login()) {
showLoginDialog()
}
} catch (ex: SocketTimeoutException) {
Log.w(javaClass.name, "Timeout during login!")
// show waring dialog before finishing
MaterialDialog(this).show {
title(R.string.dialog_timeout_head)
message(R.string.dialog_timeout_desc)
onDismiss { exitAndRemoveTask() }
// show waring dialog before finishing
MaterialDialog(this).show {
title(R.string.dialog_timeout_head)
message(R.string.dialog_timeout_desc)
onDismiss { exitAndRemoveTask() }
}
}
}
@ -164,12 +167,12 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
wasInitialized = true
}
private fun showLoginDialog(firstTry: Boolean) {
LoginDialog(this, firstTry).positiveButton {
private fun showLoginDialog() {
LoginDialog(this, false).positiveButton {
EncryptedPreferences.saveCredentials(login, password, context)
if (!AoDParser.login()) {
showLoginDialog(false)
showLoginDialog()
Log.w(javaClass.name, "Login failed, please try again.")
}
}.negativeButton {
@ -178,6 +181,14 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
}.show()
}
/**
* start the onboarding activity and finish the main activity
*/
private fun showOnboarding() {
startActivity(Intent(this, OnboardingActivity::class.java))
finish()
}
/**
* Show a fragment on top of the current fragment.
* The current fragment is replaced and the new one is added

View File

@ -1,4 +1,4 @@
package org.mosad.teapod.ui.fragments
package org.mosad.teapod.activity.main.fragments
import android.os.Bundle
import android.view.LayoutInflater

View File

@ -1,4 +1,4 @@
package org.mosad.teapod.ui.fragments
package org.mosad.teapod.activity.main.fragments
import android.os.Bundle
import android.util.Log
@ -9,7 +9,7 @@ import androidx.fragment.app.Fragment
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItemsSingleChoice
import org.mosad.teapod.BuildConfig
import org.mosad.teapod.MainActivity
import org.mosad.teapod.activity.main.MainActivity
import org.mosad.teapod.R
import org.mosad.teapod.databinding.FragmentAccountBinding
import org.mosad.teapod.parser.AoDParser

View File

@ -1,4 +1,4 @@
package org.mosad.teapod.ui.fragments
package org.mosad.teapod.activity.main.fragments
import android.graphics.drawable.Drawable
import android.os.Bundle
@ -14,7 +14,7 @@ import com.bumptech.glide.request.transition.Transition
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.mosad.teapod.MainActivity
import org.mosad.teapod.activity.main.MainActivity
import org.mosad.teapod.R
import org.mosad.teapod.databinding.FragmentHomeBinding
import org.mosad.teapod.parser.AoDParser

View File

@ -1,4 +1,4 @@
package org.mosad.teapod.ui.fragments
package org.mosad.teapod.activity.main.fragments
import android.os.Bundle
import android.view.LayoutInflater
@ -9,7 +9,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.mosad.teapod.MainActivity
import org.mosad.teapod.activity.main.MainActivity
import org.mosad.teapod.databinding.FragmentLibraryBinding
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.util.adapter.MediaItemAdapter

View File

@ -1,4 +1,4 @@
package org.mosad.teapod.ui.fragments
package org.mosad.teapod.activity.main.fragments
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
@ -12,8 +12,8 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import jp.wasabeef.glide.transformations.BlurTransformation
import kotlinx.coroutines.*
import org.mosad.teapod.MainActivity
import org.mosad.teapod.R
import org.mosad.teapod.activity.main.MainActivity
import org.mosad.teapod.databinding.FragmentMediaBinding
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.util.*

View File

@ -1,4 +1,4 @@
package org.mosad.teapod.ui.fragments
package org.mosad.teapod.activity.main.fragments
import android.os.Bundle
import android.view.LayoutInflater
@ -7,7 +7,7 @@ import android.view.ViewGroup
import android.widget.SearchView
import androidx.fragment.app.Fragment
import kotlinx.coroutines.*
import org.mosad.teapod.MainActivity
import org.mosad.teapod.activity.main.MainActivity
import org.mosad.teapod.databinding.FragmentSearchBinding
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.util.decoration.MediaItemDecoration

View File

@ -0,0 +1,54 @@
package org.mosad.teapod.activity.onboarding
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.coroutines.*
import org.mosad.teapod.R
import org.mosad.teapod.databinding.FragmentOnLoginBinding
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.preferences.EncryptedPreferences
class OnLoginFragment: Fragment() {
private lateinit var binding: FragmentOnLoginBinding
private var loginJob: Job? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = FragmentOnLoginBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initActions()
}
private fun initActions() {
binding.buttonLogin.setOnClickListener {
// get login credentials from gui
val email = binding.editTextLogin.text.toString()
val password = binding.editTextPassword.text.toString()
EncryptedPreferences.saveCredentials(email, password, requireContext()) // save the credentials
binding.buttonLogin.isClickable = false
loginJob = GlobalScope.launch {
if (AoDParser.login()) {
// if login was successful, switch to main
if (activity is OnboardingActivity) {
(activity as OnboardingActivity).launchMainActivity()
}
} else {
withContext(Dispatchers.Main) {
binding.textLoginDesc.text = getString(R.string.on_login_failed)
binding.buttonLogin.isClickable = true
}
}
}
}
}
}

View File

@ -0,0 +1,31 @@
package org.mosad.teapod.activity.onboarding
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import org.mosad.teapod.databinding.FragmentOnWelcomeBinding
class OnWelcomeFragment: Fragment() {
private lateinit var binding: FragmentOnWelcomeBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = FragmentOnWelcomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initActions()
}
private fun initActions() {
binding.buttonGetStarted.setOnClickListener {
if (activity is OnboardingActivity) {
(activity as OnboardingActivity).nextFragment()
}
}
}
}

View File

@ -0,0 +1,78 @@
package org.mosad.teapod.activity.onboarding
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayoutMediator
import org.mosad.teapod.activity.main.MainActivity
import org.mosad.teapod.databinding.ActivityOnboardingBinding
class OnboardingActivity : AppCompatActivity() {
private lateinit var binding: ActivityOnboardingBinding
private lateinit var pagerAdapter: FragmentStateAdapter
private val fragments = arrayOf(OnLoginFragment())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityOnboardingBinding.inflate(layoutInflater)
setContentView(binding.root)
pagerAdapter = ScreenSlidePagerAdapter(this)
binding.viewPager.adapter = pagerAdapter
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
}.attach()
// we don't use the skip button, instead we use the start button to skip the last fragment
binding.buttonSkip.visibility = View.GONE
// hide tab layout if only one tab is displayed
if (fragments.size <= 1) {
binding.tabLayout.visibility = View.GONE
}
}
override fun onBackPressed() {
if (binding.viewPager.currentItem == 0) {
super.onBackPressed()
} else {
binding.viewPager.currentItem = binding.viewPager.currentItem - 1
}
}
fun nextFragment() {
if (binding.viewPager.currentItem < fragments.size - 1) {
binding.viewPager.currentItem++
} else {
launchMainActivity()
}
}
fun btnSkipClick(@Suppress("UNUSED_PARAMETER")v: View) {
//launchMainActivity() // currently not used in Teapod
}
fun launchMainActivity() {
startActivity(Intent(this, MainActivity::class.java))
finish()
}
/**
* A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in
* sequence.
*/
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
override fun getItemCount(): Int = fragments.size
override fun createFragment(position: Int): Fragment = fragments[position]
}
}

View File

@ -1,4 +1,4 @@
package org.mosad.teapod.player
package org.mosad.teapod.activity.player
import android.animation.Animator
import android.animation.AnimatorListenerAdapter

View File

@ -1,4 +1,4 @@
package org.mosad.teapod.player
package org.mosad.teapod.activity.player
import android.app.Application
import android.net.Uri
@ -15,7 +15,6 @@ import kotlinx.coroutines.runBlocking
import org.mosad.teapod.R
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.preferences.Preferences
import org.mosad.teapod.ui.fragments.MediaFragment
import org.mosad.teapod.util.DataTypes
import org.mosad.teapod.util.Episode
import org.mosad.teapod.util.Media

View File

@ -56,7 +56,7 @@ object AoDParser {
fun login(): Boolean = runBlocking {
withContext(Dispatchers.Default) {
withContext(Dispatchers.IO) {
// get the authenticity token
val resAuth = Jsoup.connect(baseUrl + loginPath)
.header("User-Agent", userAgent)

View File

@ -11,7 +11,7 @@ object Preferences {
internal set
var autoplay = true
internal set
var theme = DataTypes.Theme.LIGHT
var theme = DataTypes.Theme.DARK
internal set
private fun getSharedPref(context: Context): SharedPreferences {
@ -62,8 +62,8 @@ object Preferences {
)
theme = DataTypes.Theme.valueOf(
sharedPref.getString(
context.getString(R.string.save_key_theme), DataTypes.Theme.LIGHT.toString()
) ?: DataTypes.Theme.LIGHT.toString()
context.getString(R.string.save_key_theme), DataTypes.Theme.DARK.toString()
) ?: DataTypes.Theme.DARK.toString()
)
}

View File

@ -6,7 +6,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.LinearLayout
import org.mosad.teapod.databinding.PlayerEpisodesListBinding
import org.mosad.teapod.player.PlayerViewModel
import org.mosad.teapod.activity.player.PlayerViewModel
import org.mosad.teapod.util.adapter.PlayerEpisodeItemAdapter
class EpisodesListPlayer @JvmOverloads constructor(

View File

@ -13,7 +13,7 @@ import android.widget.TextView
import androidx.core.view.children
import org.mosad.teapod.R
import org.mosad.teapod.databinding.PlayerLanguageSettingsBinding
import org.mosad.teapod.player.PlayerViewModel
import org.mosad.teapod.activity.player.PlayerViewModel
import java.util.*
class LanguageSettingsPlayer @JvmOverloads constructor(