mirror of
https://github.com/Michatec/michas-droid.git
synced 2026-05-31 02:12:42 +02:00
Initial commit
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
package nya.kitsunyan.foxydroid.screen
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Parcel
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.FrameLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.Fragment
|
||||
import nya.kitsunyan.foxydroid.R
|
||||
import nya.kitsunyan.foxydroid.content.Cache
|
||||
import nya.kitsunyan.foxydroid.content.Preferences
|
||||
import nya.kitsunyan.foxydroid.database.CursorOwner
|
||||
import nya.kitsunyan.foxydroid.utility.KParcelable
|
||||
import nya.kitsunyan.foxydroid.utility.Utils
|
||||
import nya.kitsunyan.foxydroid.utility.extension.android.*
|
||||
import nya.kitsunyan.foxydroid.utility.extension.resources.*
|
||||
import nya.kitsunyan.foxydroid.utility.extension.text.*
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
abstract class ScreenActivity: AppCompatActivity() {
|
||||
companion object {
|
||||
private const val STATE_FRAGMENT_STACK = "fragmentStack"
|
||||
}
|
||||
|
||||
sealed class SpecialIntent {
|
||||
object Updates: SpecialIntent()
|
||||
class Install(val packageName: String?, val cacheFileName: String?): SpecialIntent()
|
||||
}
|
||||
|
||||
private class FragmentStackItem(val className: String, val arguments: Bundle?,
|
||||
val savedState: Fragment.SavedState?): KParcelable {
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
dest.writeString(className)
|
||||
dest.writeByte(if (arguments != null) 1 else 0)
|
||||
arguments?.writeToParcel(dest, flags)
|
||||
dest.writeByte(if (savedState != null) 1 else 0)
|
||||
savedState?.writeToParcel(dest, flags)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Suppress("unused") @JvmField val CREATOR = KParcelable.creator {
|
||||
val className = it.readString()!!
|
||||
val arguments = if (it.readByte().toInt() == 0) null else Bundle.CREATOR.createFromParcel(it)
|
||||
arguments?.classLoader = ScreenActivity::class.java.classLoader
|
||||
val savedState = if (it.readByte().toInt() == 0) null else Fragment.SavedState.CREATOR.createFromParcel(it)
|
||||
FragmentStackItem(className, arguments, savedState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var cursorOwner: CursorOwner
|
||||
private set
|
||||
|
||||
private val fragmentStack = mutableListOf<FragmentStackItem>()
|
||||
private var toolbar: WeakReference<Toolbar>? = null
|
||||
|
||||
private val currentFragment: Fragment?
|
||||
get() {
|
||||
supportFragmentManager.executePendingTransactions()
|
||||
return supportFragmentManager.findFragmentById(R.id.main_content)
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(Utils.configureLocale(base))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTheme(Preferences[Preferences.Key.Theme].resId)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
addContentView(FrameLayout(this).apply { id = R.id.main_content },
|
||||
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
cursorOwner = CursorOwner()
|
||||
supportFragmentManager.beginTransaction()
|
||||
.add(cursorOwner, CursorOwner::class.java.name)
|
||||
.commit()
|
||||
} else {
|
||||
cursorOwner = supportFragmentManager
|
||||
.findFragmentByTag(CursorOwner::class.java.name) as CursorOwner
|
||||
}
|
||||
|
||||
savedInstanceState?.getParcelableArrayList<FragmentStackItem>(STATE_FRAGMENT_STACK)
|
||||
?.let { fragmentStack += it }
|
||||
if (savedInstanceState == null) {
|
||||
replaceFragment(TabsFragment(), null)
|
||||
if ((intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
|
||||
handleIntent(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putParcelableArrayList(STATE_FRAGMENT_STACK, ArrayList(fragmentStack))
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
val menuItem = toolbar?.get()?.menu?.findItem(R.id.toolbar_search)
|
||||
if (menuItem != null && menuItem.isActionViewExpanded) {
|
||||
menuItem.collapseActionView()
|
||||
} else {
|
||||
hideKeyboard()
|
||||
if (!popFragment()) {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun replaceFragment(fragment: Fragment, open: Boolean?) {
|
||||
if (open != null) {
|
||||
currentFragment?.view?.translationZ = (if (open) Int.MIN_VALUE else Int.MAX_VALUE).toFloat()
|
||||
}
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.apply {
|
||||
if (open != null) {
|
||||
setCustomAnimations(if (open) R.animator.slide_in else 0,
|
||||
if (open) R.animator.slide_in_keep else R.animator.slide_out)
|
||||
}
|
||||
}
|
||||
.replace(R.id.main_content, fragment)
|
||||
.commit()
|
||||
}
|
||||
|
||||
private fun pushFragment(fragment: Fragment) {
|
||||
currentFragment?.let { fragmentStack.add(FragmentStackItem(it::class.java.name, it.arguments,
|
||||
supportFragmentManager.saveFragmentInstanceState(it))) }
|
||||
replaceFragment(fragment, true)
|
||||
}
|
||||
|
||||
private fun popFragment(): Boolean {
|
||||
return fragmentStack.isNotEmpty() && run {
|
||||
val stackItem = fragmentStack.removeAt(fragmentStack.size - 1)
|
||||
val fragment = Class.forName(stackItem.className).newInstance() as Fragment
|
||||
stackItem.arguments?.let(fragment::setArguments)
|
||||
stackItem.savedState?.let(fragment::setInitialSavedState)
|
||||
replaceFragment(fragment, false)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideKeyboard() {
|
||||
(getSystemService(INPUT_METHOD_SERVICE) as? InputMethodManager)
|
||||
?.hideSoftInputFromWindow((currentFocus ?: window.decorView).windowToken, 0)
|
||||
}
|
||||
|
||||
override fun onAttachFragment(fragment: Fragment) {
|
||||
super.onAttachFragment(fragment)
|
||||
hideKeyboard()
|
||||
}
|
||||
|
||||
internal fun onFragmentViewCreated(toolbar: Toolbar?) {
|
||||
this.toolbar = toolbar?.let(::WeakReference)
|
||||
if (fragmentStack.isNotEmpty() && toolbar != null) {
|
||||
toolbar.navigationIcon = toolbar.context.getDrawableFromAttr(R.attr.homeAsUpIndicator)
|
||||
toolbar.setNavigationOnClickListener { onBackPressed() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
handleIntent(intent)
|
||||
}
|
||||
|
||||
protected val Intent.packageName: String?
|
||||
get() {
|
||||
val uri = data
|
||||
return when {
|
||||
uri?.scheme == "package" || uri?.scheme == "fdroid.app" -> uri.schemeSpecificPart?.nullIfEmpty()
|
||||
uri?.scheme == "market" && uri.host == "details" -> uri.getQueryParameter("id")?.nullIfEmpty()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
protected fun handleSpecialIntent(specialIntent: SpecialIntent) {
|
||||
when (specialIntent) {
|
||||
is SpecialIntent.Updates -> {
|
||||
if (currentFragment !is TabsFragment) {
|
||||
fragmentStack.clear()
|
||||
replaceFragment(TabsFragment(), true)
|
||||
}
|
||||
val tabsFragment = currentFragment as TabsFragment
|
||||
tabsFragment.selectUpdates()
|
||||
}
|
||||
is SpecialIntent.Install -> {
|
||||
val packageName = specialIntent.packageName
|
||||
if (!packageName.isNullOrEmpty()) {
|
||||
val fragment = currentFragment
|
||||
if (fragment !is ProductFragment || fragment.packageName != packageName) {
|
||||
pushFragment(ProductFragment(packageName))
|
||||
}
|
||||
specialIntent.cacheFileName?.let(::startPackageInstaller)
|
||||
}
|
||||
Unit
|
||||
}
|
||||
}::class
|
||||
}
|
||||
|
||||
open fun handleIntent(intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
Intent.ACTION_VIEW -> {
|
||||
val packageName = intent.packageName
|
||||
if (!packageName.isNullOrEmpty()) {
|
||||
val fragment = currentFragment
|
||||
if (fragment !is ProductFragment || fragment.packageName != packageName) {
|
||||
pushFragment(ProductFragment(packageName))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun startPackageInstaller(cacheFileName: String) {
|
||||
val (uri, flags) = if (Android.sdk(24)) {
|
||||
Pair(Cache.getReleaseUri(this, cacheFileName), Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
} else {
|
||||
Pair(Uri.fromFile(Cache.getReleaseFile(this, cacheFileName)), 0)
|
||||
}
|
||||
// TODO Handle deprecation
|
||||
@Suppress("DEPRECATION")
|
||||
startActivity(Intent(Intent.ACTION_INSTALL_PACKAGE)
|
||||
.setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags))
|
||||
}
|
||||
|
||||
internal fun navigateProduct(packageName: String) = pushFragment(ProductFragment(packageName))
|
||||
internal fun navigateRepositories() = pushFragment(RepositoriesFragment())
|
||||
internal fun navigatePreferences() = pushFragment(PreferencesFragment())
|
||||
internal fun navigateAddRepository() = pushFragment(EditRepositoryFragment(null))
|
||||
internal fun navigateRepository(repositoryId: Long) = pushFragment(RepositoryFragment(repositoryId))
|
||||
internal fun navigateEditRepository(repositoryId: Long) = pushFragment(EditRepositoryFragment(repositoryId))
|
||||
}
|
||||
Reference in New Issue
Block a user