diff --git a/src/main/kotlin/com/looker/droidify/installer/InstallerService.kt b/src/main/kotlin/com/looker/droidify/installer/InstallerService.kt index 88f48cb5..8cd9d84e 100644 --- a/src/main/kotlin/com/looker/droidify/installer/InstallerService.kt +++ b/src/main/kotlin/com/looker/droidify/installer/InstallerService.kt @@ -74,7 +74,7 @@ class InstallerService : Service() { .setAutoCancel(true) .setColor( ContextThemeWrapper(this, R.style.Theme_Main_Light) - .getColorFromAttr(android.R.attr.colorAccent).defaultColor + .getColorFromAttr(R.attr.colorPrimary).defaultColor ) when (status) { diff --git a/src/main/kotlin/com/looker/droidify/screen/EditRepositoryFragment.kt b/src/main/kotlin/com/looker/droidify/screen/EditRepositoryFragment.kt index 951a11ba..478da0e8 100644 --- a/src/main/kotlin/com/looker/droidify/screen/EditRepositoryFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/EditRepositoryFragment.kt @@ -93,7 +93,8 @@ class EditRepositoryFragment() : ScreenFragment() { syncConnection.bind(requireContext()) screenActivity.onToolbarCreated(toolbar) - toolbar.setTitle(if (repositoryId != null) R.string.edit_repository else R.string.add_repository) + collapsingToolbar.title = + getString(if (repositoryId != null) R.string.edit_repository else R.string.add_repository) saveMenuItem = toolbar.menu.add(R.string.save) .setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_save)) @@ -179,7 +180,7 @@ class EditRepositoryFragment() : ScreenFragment() { } catch (e: Exception) { Pair(null, null) } - layout.address.setText(addressText?.nullIfEmpty() ?: layout.address.hint) + layout.address.setText(addressText) layout.fingerprint.setText(fingerprintText) } else { layout.address.setText(repository.address) diff --git a/src/main/kotlin/com/looker/droidify/screen/RepositoriesAdapter.kt b/src/main/kotlin/com/looker/droidify/screen/RepositoriesAdapter.kt index 7d662837..bb894558 100644 --- a/src/main/kotlin/com/looker/droidify/screen/RepositoriesAdapter.kt +++ b/src/main/kotlin/com/looker/droidify/screen/RepositoriesAdapter.kt @@ -3,10 +3,15 @@ package com.looker.droidify.screen import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.switchmaterial.SwitchMaterial +import coil.load +import com.google.android.material.card.MaterialCardView +import com.google.android.material.imageview.ShapeableImageView +import com.google.android.material.textview.MaterialTextView import com.looker.droidify.R import com.looker.droidify.database.Database import com.looker.droidify.entity.Repository +import com.looker.droidify.utility.extension.resources.clear +import com.looker.droidify.utility.extension.resources.getColorFromAttr import com.looker.droidify.utility.extension.resources.inflate import com.looker.droidify.widget.CursorRecyclerAdapter @@ -18,9 +23,12 @@ class RepositoriesAdapter( enum class ViewType { REPOSITORY } private class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val switch = itemView.findViewById(R.id.repository_switch)!! + val item = itemView.findViewById(R.id.repository_item)!! + val checkMark = itemView.findViewById(R.id.repository_state)!! + val repoName = itemView.findViewById(R.id.repository_name)!! + val repoDesc = itemView.findViewById(R.id.repository_description)!! - var listenSwitch = true + var isEnabled = true } override val viewTypeClass: Class @@ -39,15 +47,13 @@ class RepositoriesAdapter( viewType: ViewType, ): RecyclerView.ViewHolder { return ViewHolder(parent.inflate(R.layout.repository_item)).apply { - itemView.setOnClickListener { onClick(getRepository(adapterPosition)) } - switch.setOnCheckedChangeListener { _, isChecked -> - if (listenSwitch) { - if (!onSwitch(getRepository(adapterPosition), isChecked)) { - listenSwitch = false - switch.isChecked = !isChecked - listenSwitch = true - } - } + itemView.setOnLongClickListener { + onClick(getRepository(adapterPosition)) + true + } + itemView.setOnClickListener { + isEnabled = !isEnabled + onSwitch(getRepository(adapterPosition), isEnabled) } } } @@ -55,10 +61,26 @@ class RepositoriesAdapter( override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { holder as ViewHolder val repository = getRepository(position) - val lastListenSwitch = holder.listenSwitch - holder.listenSwitch = false - holder.switch.isChecked = repository.enabled - holder.listenSwitch = lastListenSwitch - holder.switch.text = repository.name + holder.repoName.text = repository.name + holder.repoDesc.text = repository.description.trim() + if (repository.enabled) { + holder.isEnabled = true + holder.item.setCardBackgroundColor( + holder.item.context.getColorFromAttr(R.attr.colorPrimaryContainer) + ) + holder.repoName.setTextColor(holder.repoName.context.getColorFromAttr(R.attr.colorOnPrimaryContainer)) + holder.repoDesc.setTextColor(holder.repoDesc.context.getColorFromAttr(R.attr.colorOnPrimaryContainer)) + holder.checkMark.load(R.drawable.ic_check) + holder.checkMark.imageTintList = + holder.checkMark.context.getColorFromAttr(R.attr.colorOnPrimaryContainer) + } else { + holder.isEnabled = false + holder.item.setCardBackgroundColor(holder.item.context.getColorFromAttr(android.R.attr.colorBackground)) + holder.repoName.setTextColor(holder.repoName.context.getColorFromAttr(R.attr.colorOnBackground)) + holder.repoDesc.setTextColor(holder.repoDesc.context.getColorFromAttr(R.attr.colorOnBackground)) + holder.checkMark.clear() + holder.checkMark.imageTintList = + holder.checkMark.context.getColorFromAttr(R.attr.colorOnBackground) + } } } diff --git a/src/main/kotlin/com/looker/droidify/screen/RepositoriesFragment.kt b/src/main/kotlin/com/looker/droidify/screen/RepositoriesFragment.kt index 2a5146d5..4a013d8f 100644 --- a/src/main/kotlin/com/looker/droidify/screen/RepositoriesFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/RepositoriesFragment.kt @@ -13,6 +13,7 @@ import com.looker.droidify.database.CursorOwner import com.looker.droidify.service.Connection import com.looker.droidify.service.SyncService import com.looker.droidify.utility.Utils +import com.looker.droidify.widget.RecyclerFastScroller class RepositoriesFragment : ScreenFragment(), CursorOwner.Callback { private var recyclerView: RecyclerView? = null @@ -37,9 +38,11 @@ class RepositoriesFragment : ScreenFragment(), CursorOwner.Callback { syncConnection.binder?.setEnabled(repository, isEnabled) == true }) recyclerView = this + RecyclerFastScroller(this) }) } this.toolbar = fragmentBinding.toolbar + this.collapsingToolbar = fragmentBinding.collapsingToolbar return view } @@ -49,18 +52,15 @@ class RepositoriesFragment : ScreenFragment(), CursorOwner.Callback { syncConnection.bind(requireContext()) screenActivity.cursorOwner.attach(this, CursorOwner.Request.Repositories) - toolbar.apply { - screenActivity.onToolbarCreated(this) - setTitle(R.string.repositories) - - menu.add(R.string.add_repository) - .setIcon(Utils.getToolbarIcon(this.context, R.drawable.ic_add)) - .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS) - .setOnMenuItemClickListener { - view.post { screenActivity.navigateAddRepository() } - true - } - } + screenActivity.onToolbarCreated(toolbar) + toolbar.menu.add(R.string.add_repository) + .setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_add)) + .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS) + .setOnMenuItemClickListener { + view.post { screenActivity.navigateAddRepository() } + true + } + collapsingToolbar.title = getString(R.string.repositories) } override fun onDestroyView() { diff --git a/src/main/kotlin/com/looker/droidify/screen/RepositoryFragment.kt b/src/main/kotlin/com/looker/droidify/screen/RepositoryFragment.kt index a95defe2..bd1904fa 100644 --- a/src/main/kotlin/com/looker/droidify/screen/RepositoryFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/RepositoryFragment.kt @@ -19,7 +19,6 @@ import com.looker.droidify.service.SyncService import com.looker.droidify.utility.Utils import com.looker.droidify.utility.extension.resources.getColorFromAttr import com.looker.droidify.utility.extension.resources.sizeScaled -import io.reactivex.rxjava3.disposables.Disposable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.util.* @@ -44,7 +43,6 @@ class RepositoryFragment() : ScreenFragment() { private var layout: LinearLayoutCompat? = null private val syncConnection = Connection(SyncService::class.java) - private var repositoryDisposable: Disposable? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -54,7 +52,7 @@ class RepositoryFragment() : ScreenFragment() { lifecycleScope.launch(Dispatchers.Main) { updateRepositoryView() } screenActivity.onToolbarCreated(toolbar) - toolbar.setTitle(R.string.repository) + collapsingToolbar.title = getString(R.string.repository) toolbar.menu.apply { add(R.string.edit_repository) @@ -98,8 +96,6 @@ class RepositoryFragment() : ScreenFragment() { layout = null titleBinding = null syncConnection.unbind(requireContext()) - repositoryDisposable?.dispose() - repositoryDisposable = null } private fun updateRepositoryView() { @@ -111,7 +107,7 @@ class RepositoryFragment() : ScreenFragment() { } else { layout.addTitleText(R.string.address, repository.address) if (repository.updated > 0L) { - toolbar.title = repository.name + collapsingToolbar.title = repository.name layout.addTitleText(R.string.name, repository.name) layout.addTitleText(R.string.description, repository.description.replace('\n', ' ')) layout.addTitleText(R.string.recently_updated, run { diff --git a/src/main/kotlin/com/looker/droidify/screen/ScreenActivity.kt b/src/main/kotlin/com/looker/droidify/screen/ScreenActivity.kt index 6d79e6c6..54f473d4 100644 --- a/src/main/kotlin/com/looker/droidify/screen/ScreenActivity.kt +++ b/src/main/kotlin/com/looker/droidify/screen/ScreenActivity.kt @@ -14,6 +14,7 @@ import com.looker.droidify.R import com.looker.droidify.content.Preferences import com.looker.droidify.database.CursorOwner import com.looker.droidify.installer.AppInstaller +import com.looker.droidify.ui.appDetail.AppDetailFragment import com.looker.droidify.utility.KParcelable import com.looker.droidify.utility.extension.resources.getDrawableFromAttr import com.looker.droidify.utility.extension.text.nullIfEmpty @@ -235,7 +236,7 @@ abstract class ScreenActivity : AppCompatActivity() { val packageName = intent.packageName if (!packageName.isNullOrEmpty()) { val fragment = currentFragment - if (fragment !is ProductFragment || fragment.packageName != packageName) { + if (fragment !is AppDetailFragment || fragment.packageName != packageName) { navigateProduct(packageName) } } @@ -243,7 +244,7 @@ abstract class ScreenActivity : AppCompatActivity() { } } - internal fun navigateProduct(packageName: String) = pushFragment(ProductFragment(packageName)) + internal fun navigateProduct(packageName: String) = pushFragment(AppDetailFragment(packageName)) internal fun navigateRepositories() = pushFragment(RepositoriesFragment()) internal fun navigatePreferences() = pushFragment(SettingsFragment()) internal fun navigateAddRepository() = pushFragment(EditRepositoryFragment(null)) diff --git a/src/main/kotlin/com/looker/droidify/screen/ScreenFragment.kt b/src/main/kotlin/com/looker/droidify/screen/ScreenFragment.kt index 0671ea3a..26570e5c 100644 --- a/src/main/kotlin/com/looker/droidify/screen/ScreenFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/ScreenFragment.kt @@ -4,18 +4,16 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.appcompat.widget.Toolbar -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.CollapsingToolbarLayout +import com.google.android.material.appbar.MaterialToolbar import com.looker.droidify.databinding.FragmentBinding open class ScreenFragment : BaseFragment() { private var _fragmentBinding: FragmentBinding? = null val fragmentBinding get() = _fragmentBinding!! - lateinit var toolbar: Toolbar + lateinit var toolbar: MaterialToolbar lateinit var collapsingToolbar: CollapsingToolbarLayout - lateinit var appBar: AppBarLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -29,7 +27,6 @@ open class ScreenFragment : BaseFragment() { ): View? { this.toolbar = fragmentBinding.toolbar this.collapsingToolbar = fragmentBinding.collapsingToolbar - this.appBar = fragmentBinding.appbarLayout return fragmentBinding.root } diff --git a/src/main/kotlin/com/looker/droidify/screen/ScreenshotsAdapter.kt b/src/main/kotlin/com/looker/droidify/screen/ScreenshotsAdapter.kt index c9e45905..cf351591 100644 --- a/src/main/kotlin/com/looker/droidify/screen/ScreenshotsAdapter.kt +++ b/src/main/kotlin/com/looker/droidify/screen/ScreenshotsAdapter.kt @@ -48,7 +48,6 @@ class ScreenshotsAdapter(private val onClick: (Product.Screenshot) -> Unit) : .setAllCornerSizes(radius) .build() image.shapeAppearanceModel = shapeAppearanceModel - image.setBackgroundColor(surfaceColor) itemView.addView(image) itemView.layoutParams = RecyclerView.LayoutParams( RecyclerView.LayoutParams.WRAP_CONTENT, diff --git a/src/main/kotlin/com/looker/droidify/screen/SettingsFragment.kt b/src/main/kotlin/com/looker/droidify/screen/SettingsFragment.kt index bdd13d09..d6fa1e5a 100644 --- a/src/main/kotlin/com/looker/droidify/screen/SettingsFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/SettingsFragment.kt @@ -45,7 +45,7 @@ class SettingsFragment : ScreenFragment() { super.onViewCreated(view, savedInstanceState) preferenceBinding = PreferenceItemBinding.inflate(layoutInflater) screenActivity.onToolbarCreated(toolbar) - toolbar.setTitle(R.string.settings) + collapsingToolbar.title = getString(R.string.settings) val content = fragmentBinding.fragmentContent val scroll = NestedScrollView(content.context) @@ -202,8 +202,10 @@ class SettingsFragment : ScreenFragment() { preferences[Preferences.Key.ProxyPort]?.setEnabled(enabled) } if (key == Preferences.Key.RootPermission) { - preferences[Preferences.Key.RootPermission]?.setEnabled(Shell.getCachedShell()?.isRoot - ?: Shell.getShell().isRoot) + preferences[Preferences.Key.RootPermission]?.setEnabled( + Shell.getCachedShell()?.isRoot + ?: Shell.getShell().isRoot + ) } if (key == Preferences.Key.Theme) { requireActivity().recreate() @@ -217,7 +219,7 @@ class SettingsFragment : ScreenFragment() { val text = MaterialTextView(context) text.typeface = TypefaceExtra.medium text.setTextSizeScaled(14) - text.setTextColor(text.context.getColorFromAttr(R.attr.colorAccent)) + text.setTextColor(text.context.getColorFromAttr(R.attr.colorPrimary)) text.text = title resources.sizeScaled(16).let { text.setPadding(it, it, it, 0) } addView( diff --git a/src/main/kotlin/com/looker/droidify/screen/TabsFragment.kt b/src/main/kotlin/com/looker/droidify/screen/TabsFragment.kt index c7626a56..6bf8014d 100644 --- a/src/main/kotlin/com/looker/droidify/screen/TabsFragment.kt +++ b/src/main/kotlin/com/looker/droidify/screen/TabsFragment.kt @@ -115,7 +115,7 @@ class TabsFragment : ScreenFragment() { syncConnection.bind(requireContext()) screenActivity.onToolbarCreated(toolbar) - toolbar.setTitle(R.string.application_name) + collapsingToolbar.title = getString(R.string.application_name) // Move focus from SearchView to Toolbar toolbar.isFocusableInTouchMode = true @@ -136,7 +136,7 @@ class TabsFragment : ScreenFragment() { return true } }) - setOnSearchClickListener { appBar.setExpanded(false, true) } + setOnSearchClickListener { fragmentBinding.appbarLayout.setExpanded(false, true) } } toolbar.menu.apply { @@ -340,16 +340,6 @@ class TabsFragment : ScreenFragment() { } } - override fun onAttachFragment(childFragment: Fragment) { - super.onAttachFragment(childFragment) - - if (view != null && childFragment is AppListFragment) { - childFragment.setSearchQuery(searchQuery) - childFragment.setSection(section) - childFragment.setOrder(Preferences[Preferences.Key.SortOrder].order) - } - } - override fun onBackPressed(): Boolean { return when { searchMenuItem?.isActionViewExpanded == true -> { diff --git a/src/main/kotlin/com/looker/droidify/service/DownloadService.kt b/src/main/kotlin/com/looker/droidify/service/DownloadService.kt index ff606b5f..0b456054 100644 --- a/src/main/kotlin/com/looker/droidify/service/DownloadService.kt +++ b/src/main/kotlin/com/looker/droidify/service/DownloadService.kt @@ -220,7 +220,7 @@ class DownloadService : ConnectionService() { .setSmallIcon(android.R.drawable.stat_sys_warning) .setColor( ContextThemeWrapper(this, R.style.Theme_Main_Light) - .getColorFromAttr(R.attr.colorAccent).defaultColor + .getColorFromAttr(R.attr.colorPrimary).defaultColor ) .setContentIntent( PendingIntent.getBroadcast( @@ -286,7 +286,7 @@ class DownloadService : ConnectionService() { .setSmallIcon(android.R.drawable.stat_sys_download_done) .setColor( ContextThemeWrapper(this, R.style.Theme_Main_Light) - .getColorFromAttr(android.R.attr.colorAccent).defaultColor + .getColorFromAttr(R.attr.colorPrimary).defaultColor ) .setContentIntent(installIntent(task)) .setContentTitle(getString(R.string.downloaded_FORMAT, task.name)) diff --git a/src/main/kotlin/com/looker/droidify/screen/ProductAdapter.kt b/src/main/kotlin/com/looker/droidify/ui/appDetail/AppDetailAdapter.kt similarity index 95% rename from src/main/kotlin/com/looker/droidify/screen/ProductAdapter.kt rename to src/main/kotlin/com/looker/droidify/ui/appDetail/AppDetailAdapter.kt index 12075fec..ae3ed1d6 100644 --- a/src/main/kotlin/com/looker/droidify/screen/ProductAdapter.kt +++ b/src/main/kotlin/com/looker/droidify/ui/appDetail/AppDetailAdapter.kt @@ -1,4 +1,4 @@ -package com.looker.droidify.screen +package com.looker.droidify.ui.appDetail import android.annotation.SuppressLint import android.content.ClipData @@ -21,7 +21,6 @@ import android.view.Gravity import android.view.MotionEvent import android.view.View import android.view.ViewGroup -import android.widget.TextView import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.appcompat.widget.LinearLayoutCompat @@ -47,6 +46,7 @@ import com.looker.droidify.content.Preferences import com.looker.droidify.content.ProductPreferences import com.looker.droidify.entity.* import com.looker.droidify.network.CoilDownloader +import com.looker.droidify.screen.ScreenshotsAdapter import com.looker.droidify.utility.KParcelable import com.looker.droidify.utility.PackageItemResolver import com.looker.droidify.utility.Utils @@ -59,8 +59,8 @@ import java.lang.ref.WeakReference import java.util.* import kotlin.math.* -class ProductAdapter(private val callbacks: Callbacks) : - StableRecyclerAdapter() { +class AppDetailAdapter(private val callbacks: Callbacks) : + StableRecyclerAdapter() { interface Callbacks { fun onActionClick(action: Action) @@ -96,11 +96,11 @@ class ProductAdapter(private val callbacks: Callbacks) : private enum class SectionType(val titleResId: Int, val colorAttrResId: Int) { ANTI_FEATURES(R.string.anti_features, R.attr.colorError), - CHANGES(R.string.changes, R.attr.colorAccent), - LINKS(R.string.links, R.attr.colorAccent), - DONATE(R.string.donate, R.attr.colorAccent), - PERMISSIONS(R.string.permissions, R.attr.colorAccent), - VERSIONS(R.string.versions, R.attr.colorAccent) + CHANGES(R.string.changes, R.attr.colorPrimary), + LINKS(R.string.links, R.attr.colorPrimary), + DONATE(R.string.donate, R.attr.colorPrimary), + PERMISSIONS(R.string.permissions, R.attr.colorPrimary), + VERSIONS(R.string.versions, R.attr.colorPrimary) } internal enum class ExpandType { @@ -129,8 +129,7 @@ class ProductAdapter(private val callbacks: Callbacks) : class AppInfoItem( val repository: Repository, - val product: Product, - val packageName: String, + val product: Product ) : Item() { override val descriptor: String get() = "app_info.${product.name}" @@ -329,9 +328,9 @@ class ProductAdapter(private val callbacks: Callbacks) : val progressIcon: Drawable val defaultIcon: Drawable - val actionTintNormal = action.context.getColorFromAttr(R.attr.colorSurface) + val actionTintNormal = action.context.getColorFromAttr(R.attr.colorPrimary) + val actionTintOnNormal = action.context.getColorFromAttr(R.attr.colorOnPrimary) val actionTintCancel = action.context.getColorFromAttr(R.attr.colorError) - val actionTintOnNormal = action.context.getColorFromAttr(R.attr.colorOnSurface) val actionTintOnCancel = action.context.getColorFromAttr(R.attr.colorOnError) init { @@ -362,7 +361,7 @@ class ProductAdapter(private val callbacks: Callbacks) : } private class SwitchViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val enabled = itemView.findViewById(R.id.enabled)!! + val enabled = itemView.findViewById(R.id.update_state_switch)!! val statefulViews: Sequence get() = sequenceOf(itemView, enabled) @@ -404,7 +403,7 @@ class ProductAdapter(private val callbacks: Callbacks) : private class TextViewHolder(context: Context) : RecyclerView.ViewHolder(MaterialTextView(context)) { - val text: TextView + val text: MaterialTextView get() = itemView as MaterialTextView init { @@ -481,7 +480,7 @@ class ProductAdapter(private val callbacks: Callbacks) : val dateFormat = DateFormat.getDateFormat(itemView.context)!! val version = itemView.findViewById(R.id.version)!! - val status = itemView.findViewById(R.id.status)!! + val status = itemView.findViewById(R.id.installation_status)!! val source = itemView.findViewById(R.id.source)!! val added = itemView.findViewById(R.id.added)!! val size = itemView.findViewById(R.id.size)!! @@ -499,21 +498,6 @@ class ProductAdapter(private val callbacks: Callbacks) : signature, compatibility ) - - init { - status.apply { - background = - ResourcesCompat.getDrawable( - itemView.resources, - R.drawable.background_border, - itemView.context.theme - ) - backgroundTintList = itemView.context.getColorFromAttr(R.attr.colorSurface) - typeface = TypefaceExtra.bold - setPadding(15, 5, 15, 5) - setTextColor(itemView.context.getColorFromAttr(R.attr.colorPrimary)) - } - } } private class EmptyViewHolder(context: Context) : @@ -568,8 +552,7 @@ class ProductAdapter(private val callbacks: Callbacks) : if (productRepository != null) { items += Item.AppInfoItem( productRepository.second, - productRepository.first, - packageName + productRepository.first ) items += Item.ScreenshotItem( productRepository.first.screenshots, @@ -709,8 +692,7 @@ class ProductAdapter(private val callbacks: Callbacks) : ) } author.email.nullIfEmpty()?.let { - linkItems += Item.LinkItem - .Typed(LinkType.EMAIL, "", Uri.parse("mailto:$it")) + linkItems += Item.LinkItem.Typed(LinkType.EMAIL, "", Uri.parse("mailto:$it")) } linkItems += licenses.asSequence().map { Item.LinkItem.Typed( @@ -887,7 +869,7 @@ class ProductAdapter(private val callbacks: Callbacks) : val from = items.indexOfFirst { it is Item.ReleaseItem } val to = items.indexOfLast { it is Item.ReleaseItem } if (from in 0..to) { - notifyItemRangeChanged(from, to - from + 1) + notifyItemRangeChanged(0, 1) } } else { notifyItemChanged(index, Payload.STATUS) @@ -909,7 +891,7 @@ class ProductAdapter(private val callbacks: Callbacks) : ): RecyclerView.ViewHolder { return when (viewType) { ViewType.APP_INFO -> AppInfoViewHolder(parent.inflate(R.layout.item_app_info_x)).apply { - action.setOnClickListener { this@ProductAdapter.action?.let(callbacks::onActionClick) } + action.setOnClickListener { this@AppDetailAdapter.action?.let(callbacks::onActionClick) } } ViewType.SCREENSHOT -> ScreenShotViewHolder(parent.inflate(R.layout.screenshot_scrollview)) ViewType.SWITCH -> SwitchViewHolder(parent.inflate(R.layout.switch_item)).apply { @@ -1118,14 +1100,12 @@ class ProductAdapter(private val callbacks: Callbacks) : if (status.total != null) { holder.progress.progress = (holder.progress.max.toFloat() * status.read / status.total).roundToInt() - } - Unit + } else Unit } }::class } } - val imageSource = product?.source?.trimAfter('/', 4).plus(".png").toUri() val sdk = product?.displayRelease?.targetSdkVersion holder.version.doOnPreDraw { @@ -1143,13 +1123,9 @@ class ProductAdapter(private val callbacks: Callbacks) : } val devName = product?.source?.trimAfter('/', 4).trimBefore('/', 3) holder.devName.text = if (author.isNullOrEmpty()) devName else author - when { - imageSource.toString() - .contains("kde.org") -> holder.devIcon.setImageResource(R.drawable.ic_kde) - imageSource.toString() - .contains("gitlab") -> holder.devIcon.setImageResource(R.drawable.ic_gitlab) - imageSource.toString().contains("github") -> holder.devIcon.load(imageSource) - } + + holder.devIcon.load(R.drawable.ic_code) + holder.dev.setOnClickListener { product?.source?.let { link -> if (link.isNotEmpty()) { @@ -1334,30 +1310,46 @@ class ProductAdapter(private val callbacks: Callbacks) : installedItem?.signature == item.release.signature val suggested = incompatibility == null && item.release.selected && item.selectedRepository - val olderOrSignature = installedItem?.let { - it.versionCode > item.release.versionCode || - it.signature != item.release.signature - } == true - val grayOut = incompatibility != null || olderOrSignature - val primarySecondaryColor = context.getColorFromAttr( - if (grayOut) - android.R.attr.textColorSecondary else android.R.attr.textColor - ) + + if (suggested) { + holder.itemView.apply { + background = ResourcesCompat.getDrawable( + holder.itemView.resources, + R.drawable.background_border, + holder.itemView.context.theme + ) + backgroundTintList = + holder.itemView.context.getColorFromAttr(R.attr.colorSurface) + } + } else { + holder.itemView.background = null + } holder.version.text = context.getString(R.string.version_FORMAT, item.release.version) - holder.version.setTextColor(primarySecondaryColor) - holder.status.visibility = if (installed || suggested) View.VISIBLE else View.GONE - holder.status.setText( - when { - installed -> R.string.installed - suggested -> R.string.suggested - else -> R.string.unknown - } - ) + + holder.status.apply { + visibility = if (installed || suggested) View.VISIBLE else View.GONE + setText( + when { + installed -> R.string.installed + suggested -> R.string.suggested + else -> R.string.unknown + } + ) + background = + ResourcesCompat.getDrawable( + holder.itemView.resources, + R.drawable.background_border, + context.theme + ) + setPadding(15, 15, 15, 15) + backgroundTintList = + context.getColorFromAttr(R.attr.colorSecondaryContainer) + setTextColor(context.getColorFromAttr(R.attr.colorOnSecondaryContainer)) + } holder.source.text = context.getString(R.string.provided_by_FORMAT, item.repository.name) holder.added.text = holder.dateFormat.format(item.release.added) - holder.added.setTextColor(primarySecondaryColor) holder.size.text = item.release.size.formatSize() holder.signature.visibility = if (item.showSignature && item.release.signature.isNotEmpty()) @@ -1466,7 +1458,7 @@ class ProductAdapter(private val callbacks: Callbacks) : Snackbar.make(view, R.string.link_copied_to_clipboard, Snackbar.LENGTH_SHORT).show() } - private class LinkSpan(private val url: String, productAdapter: ProductAdapter) : + private class LinkSpan(private val url: String, productAdapter: AppDetailAdapter) : ClickableSpan() { private val productAdapterReference = WeakReference(productAdapter) diff --git a/src/main/kotlin/com/looker/droidify/screen/ProductFragment.kt b/src/main/kotlin/com/looker/droidify/ui/appDetail/AppDetailFragment.kt similarity index 91% rename from src/main/kotlin/com/looker/droidify/screen/ProductFragment.kt rename to src/main/kotlin/com/looker/droidify/ui/appDetail/AppDetailFragment.kt index 6211298e..1fd8006a 100644 --- a/src/main/kotlin/com/looker/droidify/screen/ProductFragment.kt +++ b/src/main/kotlin/com/looker/droidify/ui/appDetail/AppDetailFragment.kt @@ -1,4 +1,4 @@ -package com.looker.droidify.screen +package com.looker.droidify.ui.appDetail import android.content.ActivityNotFoundException import android.content.ComponentName @@ -20,6 +20,9 @@ import com.looker.droidify.content.ProductPreferences import com.looker.droidify.database.Database import com.looker.droidify.entity.* import com.looker.droidify.installer.AppInstaller +import com.looker.droidify.screen.MessageDialog +import com.looker.droidify.screen.ScreenFragment +import com.looker.droidify.screen.ScreenshotsFragment import com.looker.droidify.service.Connection import com.looker.droidify.service.DownloadService import com.looker.droidify.utility.RxUtils @@ -35,7 +38,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { +class AppDetailFragment() : ScreenFragment(), AppDetailAdapter.Callbacks { companion object { private const val EXTRA_PACKAGE_NAME = "packageName" private const val STATE_LAYOUT_MANAGER = "layoutManager" @@ -52,14 +55,14 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { private enum class Action( val id: Int, - val adapterAction: ProductAdapter.Action, + val adapterAction: AppDetailAdapter.Action, ) { - INSTALL(1, ProductAdapter.Action.INSTALL), - UPDATE(2, ProductAdapter.Action.UPDATE), - LAUNCH(3, ProductAdapter.Action.LAUNCH), - DETAILS(4, ProductAdapter.Action.DETAILS), - UNINSTALL(5, ProductAdapter.Action.UNINSTALL), - SHARE(6, ProductAdapter.Action.SHARE) + INSTALL(1, AppDetailAdapter.Action.INSTALL), + UPDATE(2, AppDetailAdapter.Action.UPDATE), + LAUNCH(3, AppDetailAdapter.Action.LAUNCH), + DETAILS(4, AppDetailAdapter.Action.DETAILS), + UNINSTALL(5, AppDetailAdapter.Action.UNINSTALL), + SHARE(6, AppDetailAdapter.Action.SHARE) } private class Installed( @@ -114,10 +117,10 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { this.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) isMotionEventSplittingEnabled = false isVerticalScrollBarEnabled = false - val adapter = ProductAdapter(this@ProductFragment) + val adapter = AppDetailAdapter(this@AppDetailFragment) this.adapter = adapter addOnScrollListener(scrollListener) - savedInstanceState?.getParcelable(STATE_ADAPTER) + savedInstanceState?.getParcelable(STATE_ADAPTER) ?.let(adapter::restoreState) layoutManagerState = savedInstanceState?.getParcelable(STATE_LAYOUT_MANAGER) recyclerView = this @@ -213,7 +216,7 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { } } val recyclerView = recyclerView!! - val adapter = recyclerView.adapter as ProductAdapter + val adapter = recyclerView.adapter as AppDetailAdapter if (firstChanged || productChanged || installedItemChanged) { adapter.setProducts( recyclerView.context, @@ -246,7 +249,7 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { val layoutManagerState = layoutManagerState ?: recyclerView?.layoutManager?.onSaveInstanceState() layoutManagerState?.let { outState.putParcelable(STATE_LAYOUT_MANAGER, it) } - val adapterState = (recyclerView?.adapter as? ProductAdapter)?.saveState() + val adapterState = (recyclerView?.adapter as? AppDetailAdapter)?.saveState() adapterState?.let { outState.putParcelable(STATE_ADAPTER, it) } } @@ -297,8 +300,8 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { } val adapterAction = - if (downloading) ProductAdapter.Action.CANCEL else primaryAction?.adapterAction - (recyclerView?.adapter as? ProductAdapter)?.setAction(adapterAction) + if (downloading) AppDetailAdapter.Action.CANCEL else primaryAction?.adapterAction + (recyclerView?.adapter as? AppDetailAdapter)?.setAction(adapterAction) for (action in sequenceOf( Action.INSTALL, @@ -344,9 +347,9 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { private suspend fun updateDownloadState(state: DownloadService.State?) { val status = when (state) { - is DownloadService.State.Pending -> ProductAdapter.Status.Pending - is DownloadService.State.Connecting -> ProductAdapter.Status.Connecting - is DownloadService.State.Downloading -> ProductAdapter.Status.Downloading( + is DownloadService.State.Pending -> AppDetailAdapter.Status.Pending + is DownloadService.State.Connecting -> AppDetailAdapter.Status.Connecting + is DownloadService.State.Downloading -> AppDetailAdapter.Status.Downloading( state.read, state.total ) @@ -357,7 +360,7 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { this.downloading = downloading updateButtons() } - (recyclerView?.adapter as? ProductAdapter)?.setStatus(status) + (recyclerView?.adapter as? AppDetailAdapter)?.setStatus(status) if (state is DownloadService.State.Success && isResumed) { withContext(Dispatchers.Default) { state.consume() @@ -383,10 +386,10 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { } } - override fun onActionClick(action: ProductAdapter.Action) { + override fun onActionClick(action: AppDetailAdapter.Action) { when (action) { - ProductAdapter.Action.INSTALL, - ProductAdapter.Action.UPDATE, + AppDetailAdapter.Action.INSTALL, + AppDetailAdapter.Action.UPDATE, -> { val installedItem = installed?.installedItem lifecycleScope.launch { @@ -399,7 +402,7 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { } Unit } - ProductAdapter.Action.LAUNCH -> { + AppDetailAdapter.Action.LAUNCH -> { val launcherActivities = installed?.launcherActivities.orEmpty() if (launcherActivities.size >= 2) { LaunchDialog(launcherActivities).show( @@ -411,25 +414,25 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { } Unit } - ProductAdapter.Action.DETAILS -> { + AppDetailAdapter.Action.DETAILS -> { startActivity( Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) .setData(Uri.parse("package:$packageName")) ) } - ProductAdapter.Action.UNINSTALL -> { + AppDetailAdapter.Action.UNINSTALL -> { lifecycleScope.launch { AppInstaller.getInstance(context)?.defaultInstaller?.uninstall(packageName) } Unit } - ProductAdapter.Action.CANCEL -> { + AppDetailAdapter.Action.CANCEL -> { val binder = downloadConnection.binder if (downloading && binder != null) { binder.cancel(packageName) } else Unit } - ProductAdapter.Action.SHARE -> { + AppDetailAdapter.Action.SHARE -> { val sendIntent: Intent = Intent().apply { this.action = Intent.ACTION_SEND putExtra( @@ -552,7 +555,7 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks { return MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.launch) .setItems(labels.toTypedArray()) { _, position -> - (parentFragment as ProductFragment) + (parentFragment as AppDetailFragment) .startLauncherActivity(names[position]) } .setNegativeButton(R.string.cancel, null) diff --git a/src/main/kotlin/com/looker/droidify/ui/appsList/AppListAdapter.kt b/src/main/kotlin/com/looker/droidify/ui/appsList/AppListAdapter.kt index 2e83c2f2..007b3194 100644 --- a/src/main/kotlin/com/looker/droidify/ui/appsList/AppListAdapter.kt +++ b/src/main/kotlin/com/looker/droidify/ui/appsList/AppListAdapter.kt @@ -2,11 +2,11 @@ package com.looker.droidify.ui.appsList import android.content.Context import android.graphics.drawable.Drawable -import android.graphics.drawable.GradientDrawable import android.view.Gravity import android.view.View import android.view.ViewGroup import android.view.animation.AnimationUtils +import androidx.core.content.res.ResourcesCompat import androidx.recyclerview.widget.RecyclerView import coil.load import coil.transform.RoundedCornersTransformation @@ -163,16 +163,16 @@ class AppListAdapter(private val onClick: (ProductItem) -> Unit) : if (productItem.canUpdate) { text = productItem.version if (background == null) { - resources.sizeScaled(4).let { setPadding(it, 0, it, 0) } - setTextColor(holder.status.context.getColorFromAttr(android.R.attr.colorBackground)) - background = GradientDrawable( - GradientDrawable.Orientation.TOP_BOTTOM, - null - ).apply { - color = - holder.status.context.getColorFromAttr(R.attr.colorAccent) - cornerRadius = holder.status.resources.sizeScaled(2).toFloat() - } + background = + ResourcesCompat.getDrawable( + holder.itemView.resources, + R.drawable.background_border, + context.theme + ) + setPadding(8, 15, 1, 15) + backgroundTintList = + context.getColorFromAttr(R.attr.colorSecondaryContainer) + setTextColor(context.getColorFromAttr(R.attr.colorSecondary)) } } else { text = productItem.installedVersion.nullIfEmpty() ?: productItem.version diff --git a/src/main/res/color/switch_track_tint.xml b/src/main/res/color/switch_track_tint.xml index 081abb26..a0899857 100644 --- a/src/main/res/color/switch_track_tint.xml +++ b/src/main/res/color/switch_track_tint.xml @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/src/main/res/layout/item_app_info_x.xml b/src/main/res/layout/item_app_info_x.xml index 27c82aff..954a2bfb 100644 --- a/src/main/res/layout/item_app_info_x.xml +++ b/src/main/res/layout/item_app_info_x.xml @@ -237,7 +237,5 @@ app:iconGravity="textStart" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/status_layout" - app:shapeAppearanceOverlay="@style/PillShapeAppearance" /> - + app:layout_constraintTop_toBottomOf="@id/status_layout"/> diff --git a/src/main/res/layout/product_item.xml b/src/main/res/layout/product_item.xml index e8fc394b..2a3e9833 100644 --- a/src/main/res/layout/product_item.xml +++ b/src/main/res/layout/product_item.xml @@ -2,7 +2,6 @@ @@ -45,10 +44,9 @@ android:id="@+id/status" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:maxWidth="70dp" + android:maxWidth="80dp" android:singleLine="true" - android:textAppearance="?textAppearanceCaption" - android:textColor="?android:attr/textColorSecondary" /> + android:textAppearance="?textAppearanceLabelMedium" /> diff --git a/src/main/res/layout/release_item.xml b/src/main/res/layout/release_item.xml index aec3a255..1cf8ad61 100644 --- a/src/main/res/layout/release_item.xml +++ b/src/main/res/layout/release_item.xml @@ -1,111 +1,99 @@ - + android:layout_height="wrap_content"> + android:baselineAligned="false" + android:gravity="center_vertical" + android:orientation="vertical" + android:padding="16dp"> - + android:gravity="bottom" + android:orientation="horizontal"> + android:orientation="horizontal"> + android:textAllCaps="true" + android:textAppearance="?textAppearanceLabelLarge" /> + android:textAppearance="?textAppearanceLabelMedium" /> - + + + + + + + + + + + - - - - - - - - - - - + diff --git a/src/main/res/layout/repository_item.xml b/src/main/res/layout/repository_item.xml index 847bf7ab..80009afe 100644 --- a/src/main/res/layout/repository_item.xml +++ b/src/main/res/layout/repository_item.xml @@ -1,10 +1,36 @@ - + android:layout_height="wrap_content" + android:layout_marginVertical="8dp" + android:layout_marginHorizontal="@dimen/text_margin"> + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/layout/screenshot_scrollview.xml b/src/main/res/layout/screenshot_scrollview.xml index fb0fdc3c..6713fa12 100644 --- a/src/main/res/layout/screenshot_scrollview.xml +++ b/src/main/res/layout/screenshot_scrollview.xml @@ -20,7 +20,7 @@ android:layout_weight="1" android:singleLine="true" android:text="@string/screenshots" - android:textColor="?attr/colorAccent" /> + android:textColor="?attr/colorPrimary" /> diff --git a/src/main/res/layout/switch_item.xml b/src/main/res/layout/switch_item.xml index 2491035f..daf75a88 100644 --- a/src/main/res/layout/switch_item.xml +++ b/src/main/res/layout/switch_item.xml @@ -1,14 +1,9 @@ - - - - + android:layout_height="wrap_content" + android:clickable="false" + android:layout_marginHorizontal="@dimen/text_margin" + android:singleLine="true" + android:textSize="15sp" /> \ No newline at end of file diff --git a/src/main/res/layout/tabs_toolbar.xml b/src/main/res/layout/tabs_toolbar.xml index b74aec7e..99cad229 100644 --- a/src/main/res/layout/tabs_toolbar.xml +++ b/src/main/res/layout/tabs_toolbar.xml @@ -7,9 +7,9 @@ + android:layout_height="48dp" /> #DDDDDD #505050 #2C2C2C + + #006D3E + #FFFFFF + #71FCAD + #00210F + #924C00 + #FFFFFF + #FFDCC1 + #2F1400 + #BA1B1B + #FFDAD4 + #FFFFFF + #410001 + #FBFDF8 + #191C1A + #E8F5E9 + #191C1A + #DDE5DC + #414942 + #707971 + #EFF1EC + #2E312E + #51DF93 + + #51DF93 + #00391D + #00522D + #71FCAD + #FFB77B + #4E2600 + #6F3800 + #FFDCC1 + #FFB4A9 + #930006 + #680003 + #FFDAD4 + #191C1A + #E1E3DE + #191C1A + #E1E3DE + #414942 + #C0C9C0 + #8A938A + #191C1A + #E1E3DE + #006D3E + + #51DF93 + #BA1B1B diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml index 8acc1761..83ebb715 100644 --- a/src/main/res/values/styles.xml +++ b/src/main/res/values/styles.xml @@ -6,21 +6,28 @@ @@ -118,12 +139,9 @@