Reformatted Code and Updated VersionName/VersionCode

This commit is contained in:
Mohit 2021-06-08 21:28:45 +05:30
parent 93442f74d1
commit efc02add3d
6 changed files with 980 additions and 845 deletions

View File

@ -25,8 +25,8 @@ android {
applicationId 'com.looker.droidify'
minSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName '0.1'
versionCode 2
versionName '0.2'
def languages = [ 'en' ]
buildConfigField 'String[]', 'LANGUAGES', '{ "' + languages.join('", "') + '" }'

View File

@ -20,11 +20,6 @@ import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toolbar
import androidx.fragment.app.DialogFragment
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import com.looker.droidify.R
import com.looker.droidify.database.Database
import com.looker.droidify.entity.Repository
@ -33,24 +28,31 @@ import com.looker.droidify.service.Connection
import com.looker.droidify.service.SyncService
import com.looker.droidify.utility.RxUtils
import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.resources.*
import com.looker.droidify.utility.extension.text.*
import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.looker.droidify.utility.extension.resources.inflate
import com.looker.droidify.utility.extension.text.nullIfEmpty
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import java.net.URI
import java.net.URL
import java.nio.charset.Charset
import java.util.Locale
import kotlin.math.*
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.min
class EditRepositoryFragment(): ScreenFragment() {
class EditRepositoryFragment() : ScreenFragment() {
companion object {
private const val EXTRA_REPOSITORY_ID = "repositoryId"
private val checkPaths = listOf("", "fdroid/repo", "repo")
}
constructor(repositoryId: Long?): this() {
constructor(repositoryId: Long?) : this() {
arguments = Bundle().apply {
repositoryId?.let { putLong(EXTRA_REPOSITORY_ID, it) }
}
@ -71,8 +73,10 @@ class EditRepositoryFragment(): ScreenFragment() {
}
private val repositoryId: Long?
get() = requireArguments().let { if (it.containsKey(EXTRA_REPOSITORY_ID))
it.getLong(EXTRA_REPOSITORY_ID) else null }
get() = requireArguments().let {
if (it.containsKey(EXTRA_REPOSITORY_ID))
it.getLong(EXTRA_REPOSITORY_ID) else null
}
private lateinit var errorColorFilter: PorterDuffColorFilter
@ -85,7 +89,11 @@ class EditRepositoryFragment(): ScreenFragment() {
private var takenAddresses = emptySet<String>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment, container, false)
}
@ -114,22 +122,28 @@ class EditRepositoryFragment(): ScreenFragment() {
}
val content = view.findViewById<FrameLayout>(R.id.fragment_content)!!
errorColorFilter = PorterDuffColorFilter(content.context
.getColorFromAttr(R.attr.colorError).defaultColor, PorterDuff.Mode.SRC_IN)
errorColorFilter = PorterDuffColorFilter(
content.context
.getColorFromAttr(R.attr.colorError).defaultColor, PorterDuff.Mode.SRC_IN
)
content.addView(content.inflate(R.layout.edit_repository))
val layout = Layout(content)
this.layout = layout
layout.fingerprint.hint = generateSequence { "FF" }.take(32).joinToString(separator = " ")
layout.fingerprint.addTextChangedListener(object: TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
layout.fingerprint.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) =
Unit
override fun onTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
private val validChar: (Char) -> Boolean = { it in '0' .. '9' || it in 'a' .. 'f' || it in 'A' .. 'F' }
private val validChar: (Char) -> Boolean =
{ it in '0'..'9' || it in 'a'..'f' || it in 'A'..'F' }
private fun logicalPosition(s: String, position: Int): Int {
return if (position > 0) s.asSequence().take(position).count(validChar) else position
return if (position > 0) s.asSequence().take(position)
.count(validChar) else position
}
private fun realPosition(s: String, position: Int): Int {
@ -149,13 +163,17 @@ class EditRepositoryFragment(): ScreenFragment() {
override fun afterTextChanged(s: Editable) {
val inputString = s.toString()
val outputString = inputString.toUpperCase(Locale.US)
val outputString = inputString.uppercase(Locale.US)
.filter(validChar).windowed(2, 2, true).take(32).joinToString(separator = " ")
if (inputString != outputString) {
val inputStart = logicalPosition(inputString, Selection.getSelectionStart(s))
val inputEnd = logicalPosition(inputString, Selection.getSelectionEnd(s))
s.replace(0, s.length, outputString)
Selection.setSelection(s, realPosition(outputString, inputStart), realPosition(outputString, inputEnd))
Selection.setSelection(
s,
realPosition(outputString, inputStart),
realPosition(outputString, inputEnd)
)
}
}
})
@ -163,7 +181,8 @@ class EditRepositoryFragment(): ScreenFragment() {
if (savedInstanceState == null) {
val repository = repositoryId?.let(Database.RepositoryAdapter::get)
if (repository == null) {
val clipboardManager = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipboardManager =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val text = clipboardManager.primaryClip
?.let { if (it.itemCount > 0) it else null }
?.getItemAt(0)?.text?.toString().orEmpty()
@ -171,8 +190,10 @@ class EditRepositoryFragment(): ScreenFragment() {
val uri = Uri.parse(URL(text).toString())
val fingerprintText = uri.getQueryParameter("fingerprint")?.nullIfEmpty()
?: uri.getQueryParameter("FINGERPRINT")?.nullIfEmpty()
Pair(uri.buildUpon().path(uri.path?.pathCropped)
.query(null).fragment(null).build().toString(), fingerprintText)
Pair(
uri.buildUpon().path(uri.path?.pathCropped)
.query(null).fragment(null).build().toString(), fingerprintText
)
} catch (e: Exception) {
Pair(null, null)
}
@ -183,10 +204,16 @@ class EditRepositoryFragment(): ScreenFragment() {
val mirrors = repository.mirrors.map { it.withoutKnownPath }
if (mirrors.isNotEmpty()) {
layout.addressMirror.visibility = View.VISIBLE
layout.address.apply { setPaddingRelative(paddingStart, paddingTop,
paddingEnd + layout.addressMirror.layoutParams.width, paddingBottom) }
layout.addressMirror.setOnClickListener { SelectMirrorDialog(mirrors)
.show(childFragmentManager, SelectMirrorDialog::class.java.name) }
layout.address.apply {
setPaddingRelative(
paddingStart, paddingTop,
paddingEnd + layout.addressMirror.layoutParams.width, paddingBottom
)
}
layout.addressMirror.setOnClickListener {
SelectMirrorDialog(mirrors)
.show(childFragmentManager, SelectMirrorDialog::class.java.name)
}
}
layout.fingerprint.setText(repository.fingerprint)
val (usernameText, passwordText) = repository.authentication.nullIfEmpty()
@ -201,7 +228,10 @@ class EditRepositoryFragment(): ScreenFragment() {
}
?.let {
val index = it.indexOf(':')
if (index >= 0) Pair(it.substring(0, index), it.substring(index + 1)) else null
if (index >= 0) Pair(
it.substring(0, index),
it.substring(index + 1)
) else null
}
?: Pair(null, null)
layout.username.setText(usernameText)
@ -232,7 +262,7 @@ class EditRepositoryFragment(): ScreenFragment() {
.observeOn(Schedulers.io())
.flatMapSingle { RxUtils.querySingle { Database.RepositoryAdapter.getAll(it) } }
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
.subscribe { it ->
takenAddresses = it.asSequence().filter { it.id != repositoryId }
.flatMap { (it.mirrors + it.address).asSequence() }
.map { it.withoutKnownPath }.toSet()
@ -310,7 +340,8 @@ class EditRepositoryFragment(): ScreenFragment() {
val usernameInvalid = username.contains(':')
val usernameEmpty = username.isEmpty() && password.isNotEmpty()
val passwordEmpty = username.isNotEmpty() && password.isEmpty()
layout.usernameError.visibility = if (usernameInvalid || usernameEmpty) View.VISIBLE else View.GONE
layout.usernameError.visibility =
if (usernameInvalid || usernameEmpty) View.VISIBLE else View.GONE
layout.passwordError.visibility = if (passwordEmpty) View.VISIBLE else View.GONE
if (usernameInvalid) {
layout.usernameError.setText(R.string.invalid_username_format)
@ -330,8 +361,10 @@ class EditRepositoryFragment(): ScreenFragment() {
val layout = layout!!
saveMenuItem!!.isEnabled = !addressError && !fingerprintError &&
!usernamePasswordError && checkDisposable == null
layout.apply { sequenceOf(address, addressMirror, fingerprint, username, password)
.forEach { it.isEnabled = checkDisposable == null } }
layout.apply {
sequenceOf(address, addressMirror, fingerprint, username, password)
.forEach { it.isEnabled = checkDisposable == null }
}
layout.overlay.visibility = if (checkDisposable != null) View.VISIBLE else View.GONE
}
@ -346,7 +379,10 @@ class EditRepositoryFragment(): ScreenFragment() {
val cropped = pathCropped
val endsWith = checkPaths.asSequence().filter { it.isNotEmpty() }
.sortedByDescending { it.length }.find { cropped.endsWith("/$it") }
return if (endsWith != null) cropped.substring(0, cropped.length - endsWith.length - 1) else cropped
return if (endsWith != null) cropped.substring(
0,
cropped.length - endsWith.length - 1
) else cropped
}
private fun normalizeAddress(address: String): String? {
@ -359,7 +395,15 @@ class EditRepositoryFragment(): ScreenFragment() {
val path = uri?.path?.pathCropped
return if (uri != null && path != null) {
try {
URI(uri.scheme, uri.userInfo, uri.host, uri.port, path, uri.query, uri.fragment).toString()
URI(
uri.scheme,
uri.userInfo,
uri.host,
uri.port,
path,
uri.query,
uri.fragment
).toString()
} catch (e: Exception) {
null
}
@ -385,23 +429,41 @@ class EditRepositoryFragment(): ScreenFragment() {
val username = layout.username.text.toString().nullIfEmpty()
val password = layout.password.text.toString().nullIfEmpty()
val paths = sequenceOf("", "fdroid/repo", "repo")
val authentication = username?.let { u -> password
?.let { p -> Base64.encodeToString("$u:$p".toByteArray(Charset.defaultCharset()), Base64.NO_WRAP) } }
val authentication = username?.let { u ->
password
?.let { p ->
Base64.encodeToString(
"$u:$p".toByteArray(Charset.defaultCharset()),
Base64.NO_WRAP
)
}
}
?.let { "Basic $it" }.orEmpty()
if (check) {
checkDisposable = paths
.fold(Single.just("")) { oldAddressSingle, checkPath -> oldAddressSingle
.fold(Single.just("")) { oldAddressSingle, checkPath ->
oldAddressSingle
.flatMap { oldAddress ->
if (oldAddress.isEmpty()) {
val builder = Uri.parse(address).buildUpon()
.let { if (checkPath.isEmpty()) it else it.appendEncodedPath(checkPath) }
.let {
if (checkPath.isEmpty()) it else it.appendEncodedPath(
checkPath
)
}
val newAddress = builder.build()
val indexAddress = builder.appendPath("index.jar").build()
RxUtils
.callSingle { Downloader
.createCall(Request.Builder().method("HEAD", null)
.url(indexAddress.toString().toHttpUrl()), authentication, null) }
.callSingle {
Downloader
.createCall(
Request.Builder().method("HEAD", null)
.url(indexAddress.toString().toHttpUrl()),
authentication,
null
)
}
.subscribeOn(Schedulers.io())
.map { if (it.code == 200) newAddress.toString() else "" }
} else {
@ -413,14 +475,19 @@ class EditRepositoryFragment(): ScreenFragment() {
.subscribe { result, throwable ->
checkDisposable = null
throwable?.printStackTrace()
val resultAddress = result?.let { if (it.isEmpty()) null else it } ?: address
val resultAddress =
result?.let { if (it.isEmpty()) null else it } ?: address
val allow = resultAddress == address || run {
layout.address.setText(resultAddress)
invalidateAddress(resultAddress)
!addressError
}
if (allow) {
onSaveRepositoryProceedInvalidate(resultAddress, fingerprint, authentication)
onSaveRepositoryProceedInvalidate(
resultAddress,
fingerprint,
authentication
)
} else {
invalidateState()
}
@ -432,7 +499,11 @@ class EditRepositoryFragment(): ScreenFragment() {
}
}
private fun onSaveRepositoryProceedInvalidate(address: String, fingerprint: String, authentication: String) {
private fun onSaveRepositoryProceedInvalidate(
address: String,
fingerprint: String,
authentication: String
) {
val binder = syncConnection.binder
if (binder != null) {
val repositoryId = repositoryId
@ -454,18 +525,18 @@ class EditRepositoryFragment(): ScreenFragment() {
}
}
private class SimpleTextWatcher(private val callback: (Editable) -> Unit): TextWatcher {
private class SimpleTextWatcher(private val callback: (Editable) -> Unit) : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
override fun afterTextChanged(s: Editable) = callback(s)
}
class SelectMirrorDialog(): DialogFragment() {
class SelectMirrorDialog() : DialogFragment() {
companion object {
private const val EXTRA_MIRRORS = "mirrors"
}
constructor(mirrors: List<String>): this() {
constructor(mirrors: List<String>) : this() {
arguments = Bundle().apply {
putStringArrayList(EXTRA_MIRRORS, ArrayList(mirrors))
}
@ -475,8 +546,10 @@ class EditRepositoryFragment(): ScreenFragment() {
val mirrors = requireArguments().getStringArrayList(EXTRA_MIRRORS)!!
return AlertDialog.Builder(requireContext())
.setTitle(R.string.select_mirror)
.setItems(mirrors.toTypedArray()) { _, position -> (parentFragment as EditRepositoryFragment)
.setMirror(mirrors[position]) }
.setItems(mirrors.toTypedArray()) { _, position ->
(parentFragment as EditRepositoryFragment)
.setMirror(mirrors[position])
}
.setNegativeButton(R.string.cancel, null)
.create()
}

View File

@ -8,15 +8,17 @@ import androidx.recyclerview.widget.RecyclerView
import com.looker.droidify.R
import com.looker.droidify.database.Database
import com.looker.droidify.entity.Repository
import com.looker.droidify.utility.extension.resources.*
import com.looker.droidify.utility.extension.resources.inflate
import com.looker.droidify.widget.CursorRecyclerAdapter
class RepositoriesAdapter(private val onClick: (Repository) -> Unit,
private val onSwitch: (repository: Repository, isEnabled: Boolean) -> Boolean):
class RepositoriesAdapter(
private val onClick: (Repository) -> Unit,
private val onSwitch: (repository: Repository, isEnabled: Boolean) -> Boolean
) :
CursorRecyclerAdapter<RepositoriesAdapter.ViewType, RecyclerView.ViewHolder>() {
enum class ViewType { REPOSITORY }
private class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
private class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val name = itemView.findViewById<TextView>(R.id.name)!!
val enabled = itemView.findViewById<Switch>(R.id.enabled)!!
@ -34,7 +36,10 @@ class RepositoriesAdapter(private val onClick: (Repository) -> Unit,
return Database.RepositoryAdapter.transform(moveTo(position))
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: ViewType): RecyclerView.ViewHolder {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: ViewType
): RecyclerView.ViewHolder {
return ViewHolder(parent.inflate(R.layout.repository_item)).apply {
itemView.setOnClickListener { onClick(getRepository(adapterPosition)) }
enabled.setOnCheckedChangeListener { _, isChecked ->

View File

@ -16,12 +16,16 @@ import com.looker.droidify.service.Connection
import com.looker.droidify.service.SyncService
import com.looker.droidify.utility.Utils
class RepositoriesFragment: ScreenFragment(), CursorOwner.Callback {
class RepositoriesFragment : ScreenFragment(), CursorOwner.Callback {
private var recyclerView: RecyclerView? = null
private val syncConnection = Connection(SyncService::class.java)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment, container, false).apply {
val content = findViewById<FrameLayout>(R.id.fragment_content)!!
content.addView(RecyclerView(content.context).apply {
@ -30,8 +34,10 @@ class RepositoriesFragment: ScreenFragment(), CursorOwner.Callback {
isMotionEventSplittingEnabled = false
setHasFixedSize(true)
adapter = RepositoriesAdapter({ screenActivity.navigateRepository(it.id) },
{ repository, isEnabled -> repository.enabled != isEnabled &&
syncConnection.binder?.setEnabled(repository, isEnabled) == true })
{ repository, isEnabled ->
repository.enabled != isEnabled &&
syncConnection.binder?.setEnabled(repository, isEnabled) == true
})
recyclerView = this
}, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
}

View File

@ -9,29 +9,26 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.ScrollView
import android.widget.TextView
import android.widget.Toolbar
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import android.widget.*
import com.looker.droidify.R
import com.looker.droidify.database.Database
import com.looker.droidify.service.Connection
import com.looker.droidify.service.SyncService
import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.resources.*
import java.util.Date
import java.util.Locale
import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.looker.droidify.utility.extension.resources.inflate
import com.looker.droidify.utility.extension.resources.sizeScaled
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import java.util.*
class RepositoryFragment(): ScreenFragment() {
class RepositoryFragment() : ScreenFragment() {
companion object {
private const val EXTRA_REPOSITORY_ID = "repositoryId"
}
constructor(repositoryId: Long): this() {
constructor(repositoryId: Long) : this() {
arguments = Bundle().apply {
putLong(EXTRA_REPOSITORY_ID, repositoryId)
}
@ -45,7 +42,11 @@ class RepositoryFragment(): ScreenFragment() {
private val syncConnection = Connection(SyncService::class.java)
private var repositoryDisposable: Disposable? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment, container, false)
}
@ -75,7 +76,9 @@ class RepositoryFragment(): ScreenFragment() {
.setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_delete))
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS)
.setOnMenuItemClickListener {
MessageDialog(MessageDialog.Message.DeleteRepositoryConfirm).show(childFragmentManager)
MessageDialog(MessageDialog.Message.DeleteRepositoryConfirm).show(
childFragmentManager
)
true
}
}
@ -84,12 +87,20 @@ class RepositoryFragment(): ScreenFragment() {
val scroll = ScrollView(content.context)
scroll.id = android.R.id.list
scroll.isFillViewport = true
content.addView(scroll, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
content.addView(
scroll,
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
val layout = LinearLayout(scroll.context)
layout.orientation = LinearLayout.VERTICAL
resources.sizeScaled(8).let { layout.setPadding(0, it, 0, it) }
this.layout = layout
scroll.addView(layout, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
scroll.addView(
layout,
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
override fun onDestroyView() {
@ -116,7 +127,8 @@ class RepositoryFragment(): ScreenFragment() {
val lastUpdated = repository.updated
if (lastUpdated > 0L) {
val date = Date(repository.updated)
val format = if (DateUtils.isToday(date.time)) DateUtils.FORMAT_SHOW_TIME else
val format =
if (DateUtils.isToday(date.time)) DateUtils.FORMAT_SHOW_TIME else
DateUtils.FORMAT_SHOW_TIME or DateUtils.FORMAT_SHOW_DATE
DateUtils.formatDateTime(layout.context, date.time, format)
} else {
@ -124,24 +136,35 @@ class RepositoryFragment(): ScreenFragment() {
}
})
if (repository.enabled && (repository.lastModified.isNotEmpty() || repository.entityTag.isNotEmpty())) {
layout.addTitleText(R.string.number_of_applications,
Database.ProductAdapter.getCount(repository.id).toString())
layout.addTitleText(
R.string.number_of_applications,
Database.ProductAdapter.getCount(repository.id).toString()
)
}
} else {
layout.addTitleText(R.string.description, getString(R.string.repository_not_used_DESC))
layout.addTitleText(
R.string.description,
getString(R.string.repository_not_used_DESC)
)
}
if (repository.fingerprint.isEmpty()) {
if (repository.updated > 0L) {
val builder = SpannableStringBuilder(getString(R.string.repository_unsigned_DESC))
builder.setSpan(ForegroundColorSpan(layout.context.getColorFromAttr(R.attr.colorError).defaultColor),
0, builder.length, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE)
val builder =
SpannableStringBuilder(getString(R.string.repository_unsigned_DESC))
builder.setSpan(
ForegroundColorSpan(layout.context.getColorFromAttr(R.attr.colorError).defaultColor),
0, builder.length, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE
)
layout.addTitleText(R.string.fingerprint, builder)
}
} else {
val fingerprint = SpannableStringBuilder(repository.fingerprint.windowed(2, 2, false)
.take(32).joinToString(separator = " ") { it.toUpperCase(Locale.US) })
fingerprint.setSpan(TypefaceSpan("monospace"), 0, fingerprint.length,
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE)
val fingerprint =
SpannableStringBuilder(repository.fingerprint.windowed(2, 2, false)
.take(32).joinToString(separator = " ") { it.uppercase(Locale.US) })
fingerprint.setSpan(
TypefaceSpan("monospace"), 0, fingerprint.length,
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE
)
layout.addTitleText(R.string.fingerprint, fingerprint)
}
}

View File

@ -18,22 +18,24 @@ import com.looker.droidify.content.Preferences
import com.looker.droidify.database.CursorOwner
import com.looker.droidify.utility.KParcelable
import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.extension.android.*
import com.looker.droidify.utility.extension.resources.*
import com.looker.droidify.utility.extension.text.*
import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.extension.resources.getDrawableFromAttr
import com.looker.droidify.utility.extension.text.nullIfEmpty
abstract class ScreenActivity: FragmentActivity() {
abstract class ScreenActivity : FragmentActivity() {
companion object {
private const val STATE_FRAGMENT_STACK = "fragmentStack"
}
sealed class SpecialIntent {
object Updates: SpecialIntent()
class Install(val packageName: String?, val cacheFileName: String?): 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 {
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)
@ -43,11 +45,16 @@ abstract class ScreenActivity: FragmentActivity() {
}
companion object {
@Suppress("unused") @JvmField val CREATOR = KParcelable.creator {
@Suppress("unused")
@JvmField
val CREATOR = KParcelable.creator {
val className = it.readString()!!
val arguments = if (it.readByte().toInt() == 0) null else Bundle.CREATOR.createFromParcel(it)
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)
val savedState = if (it.readByte()
.toInt() == 0
) null else Fragment.SavedState.CREATOR.createFromParcel(it)
FragmentStackItem(className, arguments, savedState)
}
}
@ -72,10 +79,16 @@ abstract class ScreenActivity: FragmentActivity() {
setTheme(Preferences[Preferences.Key.Theme].getResId(resources.configuration))
super.onCreate(savedInstanceState)
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
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))
addContentView(
FrameLayout(this).apply { id = R.id.main_content },
ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
)
if (savedInstanceState == null) {
cursorOwner = CursorOwner()
@ -114,14 +127,17 @@ abstract class ScreenActivity: FragmentActivity() {
private fun replaceFragment(fragment: Fragment, open: Boolean?) {
if (open != null) {
currentFragment?.view?.translationZ = (if (open) Int.MIN_VALUE else Int.MAX_VALUE).toFloat()
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)
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)
@ -129,8 +145,14 @@ abstract class ScreenActivity: FragmentActivity() {
}
private fun pushFragment(fragment: Fragment) {
currentFragment?.let { fragmentStack.add(FragmentStackItem(it::class.java.name, it.arguments,
supportFragmentManager.saveFragmentInstanceState(it))) }
currentFragment?.let {
fragmentStack.add(
FragmentStackItem(
it::class.java.name, it.arguments,
supportFragmentManager.saveFragmentInstanceState(it)
)
)
}
replaceFragment(fragment, true)
}
@ -157,7 +179,8 @@ abstract class ScreenActivity: FragmentActivity() {
internal fun onToolbarCreated(toolbar: Toolbar) {
if (fragmentStack.isNotEmpty()) {
toolbar.navigationIcon = toolbar.context.getDrawableFromAttr(android.R.attr.homeAsUpIndicator)
toolbar.navigationIcon =
toolbar.context.getDrawableFromAttr(android.R.attr.homeAsUpIndicator)
toolbar.setNavigationOnClickListener { onBackPressed() }
}
}
@ -237,14 +260,19 @@ abstract class ScreenActivity: FragmentActivity() {
}
// TODO Handle deprecation
@Suppress("DEPRECATION")
startActivity(Intent(Intent.ACTION_INSTALL_PACKAGE)
.setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags))
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 navigatePreferences() = pushFragment(SettingsFragment())
internal fun navigateAddRepository() = pushFragment(EditRepositoryFragment(null))
internal fun navigateRepository(repositoryId: Long) = pushFragment(RepositoryFragment(repositoryId))
internal fun navigateEditRepository(repositoryId: Long) = pushFragment(EditRepositoryFragment(repositoryId))
internal fun navigateRepository(repositoryId: Long) =
pushFragment(RepositoryFragment(repositoryId))
internal fun navigateEditRepository(repositoryId: Long) =
pushFragment(EditRepositoryFragment(repositoryId))
}