From baf9944dc94c46076d667899ea9f66c2241d0d48 Mon Sep 17 00:00:00 2001 From: Mohit Date: Tue, 8 Jun 2021 21:35:46 +0530 Subject: [PATCH] - Screenshots are Expanded by Default - Reformatted Code - Added background to Show More Button - Shortened Tab Indicator... --- .../looker/droidify/screen/ProductAdapter.kt | 2634 +++++++++-------- .../looker/droidify/screen/ProductFragment.kt | 960 +++--- .../looker/droidify/screen/ProductsAdapter.kt | 311 +- .../droidify/screen/ProductsFragment.kt | 2 - .../looker/droidify/screen/TabsFragment.kt | 1130 +++---- 5 files changed, 2719 insertions(+), 2318 deletions(-) diff --git a/src/main/kotlin/com/looker/droidify/screen/ProductAdapter.kt b/src/main/kotlin/com/looker/droidify/screen/ProductAdapter.kt index 11010d7d..af211e64 100644 --- a/src/main/kotlin/com/looker/droidify/screen/ProductAdapter.kt +++ b/src/main/kotlin/com/looker/droidify/screen/ProductAdapter.kt @@ -16,25 +16,13 @@ import android.net.Uri import android.os.Parcel import android.text.SpannableStringBuilder import android.text.format.DateFormat -import android.text.style.BulletSpan -import android.text.style.ClickableSpan -import android.text.style.RelativeSizeSpan -import android.text.style.ReplacementSpan -import android.text.style.TypefaceSpan -import android.text.style.URLSpan +import android.text.style.* import android.text.util.Linkify import android.view.Gravity import android.view.MotionEvent import android.view.View import android.view.ViewGroup -import android.widget.Button -import android.widget.FrameLayout -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.ProgressBar -import android.widget.Switch -import android.widget.TextView -import android.widget.Toast +import android.widget.* import androidx.core.graphics.ColorUtils import androidx.core.text.HtmlCompat import androidx.core.text.util.LinkifyCompat @@ -42,11 +30,7 @@ import androidx.recyclerview.widget.RecyclerView import com.looker.droidify.R import com.looker.droidify.content.Preferences import com.looker.droidify.content.ProductPreferences -import com.looker.droidify.entity.InstalledItem -import com.looker.droidify.entity.Product -import com.looker.droidify.entity.ProductPreference -import com.looker.droidify.entity.Release -import com.looker.droidify.entity.Repository +import com.looker.droidify.entity.* import com.looker.droidify.graphics.PaddingDrawable import com.looker.droidify.network.PicassoDownloader import com.looker.droidify.utility.KParcelable @@ -56,1250 +40,1508 @@ 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.widget.ClickableMovementMethod -import com.looker.droidify.widget.DividerItemDecoration import com.looker.droidify.widget.StableRecyclerAdapter import java.lang.ref.WeakReference -import java.util.Locale +import java.util.* import kotlin.math.* -class ProductAdapter(private val callbacks: Callbacks, private val columns: Int): - StableRecyclerAdapter() { - companion object { - private const val GRID_SPACING_OUTER_DP = 16 - private const val GRID_SPACING_INNER_DP = 4 - } - - interface Callbacks { - fun onActionClick(action: Action) - fun onPreferenceChanged(preference: ProductPreference) - fun onPermissionsClick(group: String?, permissions: List) - fun onScreenshotClick(screenshot: Product.Screenshot) - fun onReleaseClick(release: Release) - fun onUriClick(uri: Uri, shouldConfirm: Boolean): Boolean - } - - enum class Action(val titleResId: Int) { - INSTALL(R.string.install), - UPDATE(R.string.update), - LAUNCH(R.string.launch), - DETAILS(R.string.details), - UNINSTALL(R.string.uninstall), - CANCEL(R.string.cancel) - } - - sealed class Status { - object Pending: Status() - object Connecting: Status() - data class Downloading(val read: Long, val total: Long?): Status() - } - - enum class ViewType { HEADER, SWITCH, SECTION, EXPAND, TEXT, LINK, PERMISSIONS, SCREENSHOT, RELEASE, EMPTY } - - private enum class SwitchType(val titleResId: Int) { - IGNORE_ALL_UPDATES(R.string.ignore_all_updates), - IGNORE_THIS_UPDATE(R.string.ignore_this_update) - } - - private enum class SectionType(val titleResId: Int, val colorAttrResId: Int) { - ANTI_FEATURES(R.string.anti_features, R.attr.colorError), - CHANGES(R.string.changes, android.R.attr.colorAccent), - LINKS(R.string.links, android.R.attr.colorAccent), - DONATE(R.string.donate, android.R.attr.colorAccent), - PERMISSIONS(R.string.permissions, android.R.attr.colorAccent), - SCREENSHOTS(R.string.screenshots, android.R.attr.colorAccent), - VERSIONS(R.string.versions, android.R.attr.colorAccent) - } - - internal enum class ExpandType { NOTHING, DESCRIPTION, CHANGES, - LINKS, DONATES, PERMISSIONS, SCREENSHOTS, VERSIONS } - private enum class TextType { DESCRIPTION, ANTI_FEATURES, CHANGES } - - private enum class LinkType(val iconResId: Int, val titleResId: Int, - val format: ((Context, String) -> String)? = null) { - AUTHOR(R.drawable.ic_person, R.string.author_website), - EMAIL(R.drawable.ic_email, R.string.author_email), - LICENSE(R.drawable.ic_copyright, R.string.license, - format = { context, text -> context.getString(R.string.license_FORMAT, text) }), - SOURCE(R.drawable.ic_code, R.string.source_code), - TRACKER(R.drawable.ic_bug_report, R.string.bug_tracker), - CHANGELOG(R.drawable.ic_history, R.string.changelog), - WEB(R.drawable.ic_public, R.string.project_website) - } - - private sealed class Item { - abstract val descriptor: String - abstract val viewType: ViewType - - class HeaderItem(val repository: Repository, val product: Product): Item() { - override val descriptor: String - get() = "header" - - override val viewType: ViewType - get() = ViewType.HEADER - } - - class SwitchItem(val switchType: SwitchType, val packageName: String, val versionCode: Long): Item() { - override val descriptor: String - get() = "switch.${switchType.name}" - - override val viewType: ViewType - get() = ViewType.SWITCH - } - - class SectionItem(val sectionType: SectionType, val expandType: ExpandType, - val items: List, val collapseCount: Int): Item() { - constructor(sectionType: SectionType): this(sectionType, ExpandType.NOTHING, emptyList(), 0) - - override val descriptor: String - get() = "section.${sectionType.name}" - - override val viewType: ViewType - get() = ViewType.SECTION - } - - class ExpandItem(val expandType: ExpandType, val replace: Boolean, val items: List): Item() { - override val descriptor: String - get() = "expand.${expandType.name}" - - override val viewType: ViewType - get() = ViewType.EXPAND - } - - class TextItem(val textType: TextType, val text: CharSequence): Item() { - override val descriptor: String - get() = "text.${textType.name}" - - override val viewType: ViewType - get() = ViewType.TEXT - } - - sealed class LinkItem: Item() { - override val viewType: ViewType - get() = ViewType.LINK - - abstract val iconResId: Int - abstract fun getTitle(context: Context): String - abstract val uri: Uri? - - val displayLink: String? - get() = uri?.schemeSpecificPart?.nullIfEmpty() - ?.let { if (it.startsWith("//")) null else it } ?: uri?.toString() - - class Typed(val linkType: LinkType, val text: String, override val uri: Uri?): LinkItem() { - override val descriptor: String - get() = "link.typed.${linkType.name}" - - override val iconResId: Int - get() = linkType.iconResId - - override fun getTitle(context: Context): String { - return text.nullIfEmpty()?.let { linkType.format?.invoke(context, it) ?: it } - ?: context.getString(linkType.titleResId) - } - } - - class Donate(val donate: Product.Donate): LinkItem() { - override val descriptor: String - get() = "link.donate.$donate" - - override val iconResId: Int - get() = when (donate) { - is Product.Donate.Regular -> R.drawable.ic_public - is Product.Donate.Bitcoin -> R.drawable.ic_donate_bitcoin - is Product.Donate.Litecoin -> R.drawable.ic_donate_litecoin - is Product.Donate.Flattr -> R.drawable.ic_donate_flattr - is Product.Donate.Liberapay -> R.drawable.ic_donate_liberapay - is Product.Donate.OpenCollective -> R.drawable.ic_donate_opencollective - } - - override fun getTitle(context: Context): String = when (donate) { - is Product.Donate.Regular -> context.getString(R.string.website) - is Product.Donate.Bitcoin -> "Bitcoin" - is Product.Donate.Litecoin -> "Litecoin" - is Product.Donate.Flattr -> "Flattr" - is Product.Donate.Liberapay -> "Liberapay" - is Product.Donate.OpenCollective -> "Open Collective" - } - - override val uri: Uri? = when (donate) { - is Product.Donate.Regular -> Uri.parse(donate.url) - is Product.Donate.Bitcoin -> Uri.parse("bitcoin:${donate.address}") - is Product.Donate.Litecoin -> Uri.parse("litecoin:${donate.address}") - is Product.Donate.Flattr -> Uri.parse("https://flattr.com/thing/${donate.id}") - is Product.Donate.Liberapay -> Uri.parse("https://liberapay.com/~${donate.id}") - is Product.Donate.OpenCollective -> Uri.parse("https://opencollective.com/${donate.id}") - } - } - } - - class PermissionsItem(val group: PermissionGroupInfo?, val permissions: List): Item() { - override val descriptor: String - get() = "permissions.${group?.name}.${permissions.joinToString(separator = ".") { it.name }}" - - override val viewType: ViewType - get() = ViewType.PERMISSIONS - } - - class ScreenshotItem(val repository: Repository, val packageName: String, - val screenshot: Product.Screenshot): Item() { - override val descriptor: String - get() = "screenshot.${repository.id}.${screenshot.identifier}" - - override val viewType: ViewType - get() = ViewType.SCREENSHOT - } - - class ReleaseItem(val repository: Repository, val release: Release, val selectedRepository: Boolean, - val showSignature: Boolean): Item() { - override val descriptor: String - get() = "release.${repository.id}.${release.identifier}" - - override val viewType: ViewType - get() = ViewType.RELEASE - } - - class EmptyItem(val packageName: String): Item() { - override val descriptor: String - get() = "empty" - - override val viewType: ViewType - get() = ViewType.EMPTY - } - } - - private class Measurement { - private var density = 0f - private var scaledDensity = 0f - private lateinit var metric: T - - fun measure(view: View) { - View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED).let { view.measure(it, it) } - } - - fun invalidate(resources: Resources, callback: () -> T): T { - val (density, scaledDensity) = resources.displayMetrics.let { Pair(it.density, it.scaledDensity) } - if (this.density != density || this.scaledDensity != scaledDensity) { - this.density = density - this.scaledDensity = scaledDensity - metric = callback() - } - return metric - } - } - - private enum class Payload { REFRESH, STATUS } - - private class HeaderViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) { - val icon = itemView.findViewById(R.id.icon)!! - val name = itemView.findViewById(R.id.name)!! - val version = itemView.findViewById(R.id.version)!! - val packageName = itemView.findViewById(R.id.package_name)!! - val action = itemView.findViewById