Compare commits

..

No commits in common. "e75aa2eaa9bd9f423578691c619ebb9d0db03d8e" and "46e986500511fd640ab1e107225bf4dd1c8dad0a" have entirely different histories.

11 changed files with 475 additions and 243 deletions

View File

@ -377,7 +377,7 @@ internal class AppDrawer : Fragment() {
} }
} }
} }
appQuery = newQ.sort(Pair("clickCount", Sort.DESCENDING),Pair("lastUseDate",Sort.DESCENDING)).limit(18).find() appQuery = newQ.sort(Pair("clickCount", Sort.DESCENDING),Pair("lastUseDate",Sort.DESCENDING)).limit(20).find()
appQuery?.let { appQuery?.let {
if(it.size > 0) { if(it.size > 0) {
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {
@ -416,7 +416,7 @@ internal class AppDrawer : Fragment() {
} }
} }
contactQuery = newQ.sort(Pair("touchCount", Sort.DESCENDING),Pair("lastedTouchDateTime",Sort.DESCENDING)).limit(18).find() contactQuery = newQ.sort(Pair("touchCount", Sort.DESCENDING),Pair("lastedTouchDateTime",Sort.DESCENDING)).find()
contactQuery?.let { contactQuery?.let {
if (it.size > 0) if (it.size > 0)
WorkersDb.getRealm().apply { WorkersDb.getRealm().apply {

View File

@ -50,7 +50,6 @@ import com.google.android.material.button.MaterialButton
import com.google.android.material.button.MaterialButtonToggleGroup import com.google.android.material.button.MaterialButtonToggleGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.gson.Gson import com.google.gson.Gson
import io.realm.kotlin.ext.query
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R import rasel.lunar.launcher.R
import rasel.lunar.launcher.apps.AppDrawer.Companion.appNamesPrefs import rasel.lunar.launcher.apps.AppDrawer.Companion.appNamesPrefs
@ -63,9 +62,7 @@ import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_FAVORITE_APPS
import rasel.lunar.launcher.helpers.UniUtils.Companion.copyToClipboard import rasel.lunar.launcher.helpers.UniUtils.Companion.copyToClipboard
import rasel.lunar.launcher.helpers.UniUtils.Companion.screenHeight import rasel.lunar.launcher.helpers.UniUtils.Companion.screenHeight
import rasel.lunar.launcher.helpers.UniUtils.Companion.screenWidth import rasel.lunar.launcher.helpers.UniUtils.Companion.screenWidth
import rasel.lunar.launcher.model.AppInfo
import rasel.lunar.launcher.utils.BLog import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.workers.WorkersDb
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
@ -99,36 +96,7 @@ internal class AppMenu : BottomSheetDialogFragment() {
/* get default app name */ /* get default app name */
defAppName = packageManager.resolveActivity(Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER) defAppName = packageManager.resolveActivity(Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(packageName), 0)?.loadLabel(packageManager).toString() .setPackage(packageName), 0)?.loadLabel(packageManager).toString()
WorkersDb.getRealm().apply {
writeBlocking {
var result = query<AppInfo>("pkgName == $0",packageName).find()
if(result.size > 0) {
val app = result.first()
binding.totalTouch.text = "총 실행 횟수 : ".plus(app.clickCount.toString())
binding.lastTouchDate.text = "최종 실행 일시 : ".plus(SimpleDateFormat("yyyy-MM-dd HH:mm").format(Date(app.lastUseDate)))
// app.clickCount = app.clickCount + 15
// app.lastUseDate = Math.max(app.lastUseDate, System.currentTimeMillis())
// app.clickCount = app.clickCount + 15
// app.lastUseDate = Math.max(app.lastUseDate, System.currentTimeMillis())
}
}
}
fun update() {
WorkersDb.getRealm().apply {
writeBlocking {
var result = query<AppInfo>("pkgName == $0",packageName).find()
if(result.size > 0) {
val app = result.first()
app.clickCount = app.clickCount + 15
}
}
}
}
binding.totalTouch.setOnClickListener { update() }
binding.lastTouchDate.setOnClickListener { update() }
/* set application name and package name */ /* set application name and package name */
binding.appName.apply { binding.appName.apply {
setText(appNamesPrefs?.getString(packageName, defAppName)) setText(appNamesPrefs?.getString(packageName, defAppName))
@ -136,6 +104,9 @@ binding.totalTouch.setOnClickListener { update() }
} }
binding.appPackage.text = packageName binding.appPackage.text = packageName
/* favorite apps */
favoriteApps()
return binding.root return binding.root
} }
@ -158,7 +129,56 @@ binding.totalTouch.setOnClickListener { update() }
binding.appUninstall.setOnClickListener { uninstall() } binding.appUninstall.setOnClickListener { uninstall() }
} }
/* manage initial preview and clicks for favorite apps */
@SuppressLint("PrivateResource")
private fun favoriteApps() {
val sharedPreferences = requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
val enabledStroke =
ColorStateList.valueOf(requireContext().getColor(com.google.android.material.R.color.material_on_surface_stroke))
val disabledStroke =
ColorStateList.valueOf(requireContext().getColor(com.google.android.material.R.color.m3_chip_stroke_color))
for (position in 1..MAX_FAVORITE_APPS) {
val button = outlinedButton
val savedPackageName = sharedPreferences.getString(KEY_APP_NO_ + position, "")
/* set previews */
if (packageName == savedPackageName) button.isChecked = true
if (savedPackageName?.isNotEmpty() == true) button.strokeColor = enabledStroke
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
packageManager.getPackageInfo(savedPackageName!!, PackageManager.PackageInfoFlags.of(0))
else
packageManager.getPackageInfo(savedPackageName!!, 0)
} catch (e: PackageManager.NameNotFoundException) {
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
.edit().remove(KEY_APP_NO_ + position).apply()
button.strokeColor = disabledStroke
e.printStackTrace()
}
/* listen on clicks */
binding.favGroup.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?,
checkedId: Int, isChecked: Boolean ->
try {
if (checkedId == button.id) {
if (isChecked) {
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
.edit().putString(KEY_APP_NO_ + position, packageName).apply()
button.strokeColor = enabledStroke
} else {
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
.edit().remove(KEY_APP_NO_ + position).apply()
button.strokeColor = disabledStroke
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
private fun appName() { private fun appName() {
binding.appName.setOnFocusChangeListener { _, hasFocus -> binding.appName.setOnFocusChangeListener { _, hasFocus ->
@ -214,10 +234,10 @@ binding.totalTouch.setOnClickListener { update() }
/* show infos */ /* show infos */
dialogBinding.mixed.text = dialogBinding.mixed.text =
"${resources.getString(R.string.version)}: ${packageInfo.versionName} (${PackageInfoCompat.getLongVersionCode(packageInfo).toInt()})\n" + "${resources.getString(R.string.version)}: ${packageInfo.versionName} (${PackageInfoCompat.getLongVersionCode(packageInfo).toInt()})\n" +
"${resources.getString(R.string.sdk)}: ${appInfo.minSdkVersion} ~ ${appInfo.targetSdkVersion}\n" + "${resources.getString(R.string.sdk)}: ${appInfo.minSdkVersion} ~ ${appInfo.targetSdkVersion}\n" +
"${resources.getString(R.string.uid)}: ${appInfo.uid}\n" + "${resources.getString(R.string.uid)}: ${appInfo.uid}\n" +
"${resources.getString(R.string.first_install)}: ${dateTimeFormat(packageInfo.firstInstallTime)}\n" + "${resources.getString(R.string.first_install)}: ${dateTimeFormat(packageInfo.firstInstallTime)}\n" +
"${resources.getString(R.string.last_update)}: ${dateTimeFormat(packageInfo.lastUpdateTime)}" "${resources.getString(R.string.last_update)}: ${dateTimeFormat(packageInfo.lastUpdateTime)}"
/* show permissions */ /* show permissions */
dialogBinding.permissions.text = permissionsList dialogBinding.permissions.text = permissionsList
@ -362,6 +382,18 @@ binding.totalTouch.setOnClickListener { update() }
this.dismiss() this.dismiss()
} }
/* create and add an outlined button to the toggle group */
private val outlinedButton: MaterialButton get() {
val style = com.google.android.material.R.attr.materialButtonOutlinedStyle
val button = MaterialButton(requireContext(), null, style)
button.layoutParams = LinearLayoutCompat.LayoutParams(
LinearLayoutCompat.LayoutParams.WRAP_CONTENT,
LinearLayoutCompat.LayoutParams.WRAP_CONTENT, 1F
)
binding.favGroup.addView(button)
return button
}
/* long value to local date-time format */ /* long value to local date-time format */
private fun dateTimeFormat(long: Long) : String = SimpleDateFormat.getDateTimeInstance().format(Date(long)) private fun dateTimeFormat(long: Long) : String = SimpleDateFormat.getDateTimeInstance().format(Date(long))

View File

@ -93,16 +93,6 @@ internal class AppsAdapter(
/* on long click - open app menu */ /* on long click - open app menu */
setOnLongClickListener { setOnLongClickListener {
WorkersDb.getRealm().apply {
writeBlocking {
var result = query<AppInfo>("pkgName == $0",item.pkgName).find()
if(result.size > 0) {
val app = result.first()
app.clickCount = app.clickCount + 15
app.lastUseDate = Math.max(app.lastUseDate, System.currentTimeMillis())
}
}
}
AppMenu().apply { AppMenu().apply {
}.show(fragmentManager, item.pkgName) }.show(fragmentManager, item.pkgName)
true true

View File

@ -26,14 +26,12 @@ import android.view.ViewGroup
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.realm.kotlin.ext.query
import io.realm.kotlin.types.RealmObject import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.annotations.PrimaryKey import io.realm.kotlin.types.annotations.PrimaryKey
import rasel.lunar.launcher.databinding.ContactItemBinding import rasel.lunar.launcher.databinding.ContactItemBinding
import rasel.lunar.launcher.utils.BLog import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.utils.JamoUtils import rasel.lunar.launcher.utils.JamoUtils
import rasel.lunar.launcher.workers.RecentCallGetter import rasel.lunar.launcher.workers.RecentCallGetter
import rasel.lunar.launcher.workers.WorkersDb
import java.util.Date import java.util.Date
@ -64,22 +62,11 @@ internal class ContactAdapter (
holder.view.root.apply { holder.view.root.apply {
/* on click - open app */ /* on click - open app */
setOnClickListener { setOnClickListener {
ContactMenu().show(fragmentManager, item.id.toString()) ContactMenu().show(fragmentManager, item.id.toString())
} }
/* on long click - open app menu */ /* on long click - open app menu */
setOnLongClickListener { setOnLongClickListener {
WorkersDb.getRealm().writeBlocking {
if (item.id!=null && item.id?.length ?: 0 > 0) {
val result = query<SimpleContact>().query("id == $0", item.id).find()
if(result.size > 0){
var contact = result.first()
contact.touchCount = contact.touchCount + 1
contact.lastedTouchDateTime = System.currentTimeMillis()
}
}
}
// BLog.LOGE("item.id.toString() >> ${item.id.toString()}") // BLog.LOGE("item.id.toString() >> ${item.id.toString()}")
ContactMenu().show(fragmentManager, item.id.toString()) ContactMenu().show(fragmentManager, item.id.toString())
true true

View File

@ -18,63 +18,65 @@
package rasel.lunar.launcher.apps package rasel.lunar.launcher.apps
import android.annotation.SuppressLint
import android.app.ActivityOptions
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.res.ColorStateList
import android.graphics.Rect
import android.icu.text.SimpleDateFormat
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.ContactsContract import android.provider.ContactsContract
import android.provider.Settings
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.widget.LinearLayoutCompat
import androidx.core.content.FileProvider
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import io.realm.kotlin.ext.query import com.google.android.material.button.MaterialButton
import com.google.android.material.button.MaterialButtonToggleGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import rasel.lunar.launcher.LauncherActivity.Companion.lActivity import rasel.lunar.launcher.LauncherActivity.Companion.lActivity
import rasel.lunar.launcher.R
import rasel.lunar.launcher.databinding.ActivityBrowserDialogBinding
import rasel.lunar.launcher.databinding.ContactMenuBinding import rasel.lunar.launcher.databinding.ContactMenuBinding
import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APP_NO_
import rasel.lunar.launcher.helpers.Constants.Companion.MAX_FAVORITE_APPS
import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_FAVORITE_APPS
import rasel.lunar.launcher.helpers.UniUtils.Companion.screenHeight
import rasel.lunar.launcher.helpers.UniUtils.Companion.screenWidth
import rasel.lunar.launcher.utils.BLog import rasel.lunar.launcher.utils.BLog
import rasel.lunar.launcher.workers.WorkersDb import java.io.File
import java.text.SimpleDateFormat import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.util.Date import java.util.Date
internal class ContactMenu : BottomSheetDialogFragment() { internal class ContactMenu : BottomSheetDialogFragment() {
private lateinit var binding: ContactMenuBinding private lateinit var binding: ContactMenuBinding
private lateinit var contactId: String private lateinit var packageName: String
private lateinit var packageManager: PackageManager
private lateinit var appInfo: ApplicationInfo
private lateinit var defAppName: String
var contactName : String = "" var contactName : String = ""
var contactPhoneNumber : String = "" var contactPhoneNumber : String = ""
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = ContactMenuBinding.inflate(inflater, container, false) binding = ContactMenuBinding.inflate(inflater, container, false)
/* get package name from fragment's tag */ /* get package name from fragment's tag */
contactId = tag.toString() packageName = tag.toString()
WorkersDb.getRealm().writeBlocking {
if (contactId != null && contactId.length ?: 0 > 0) {
val result = query<SimpleContact>().query("id == $0", contactId).find()
if(result.size > 0){
var contact = result.first()
binding.totalTouch.text = "총 연락 횟수 : ".plus(contact.touchCount.toString())
binding.lastTouchDate.text = "마지막 연락 시간 : ".plus(SimpleDateFormat("yyyy-MM-dd HH:mm").format(Date(contact.lastedTouchDateTime)))
}
}
}
fun update() {
WorkersDb.getRealm().writeBlocking {
if (contactId != null && contactId.length ?: 0 > 0) {
val result = query<SimpleContact>().query("id == $0", contactId).find()
if(result.size > 0){
var contact = result.first()
contact.touchCount = contact.touchCount + 15
}
}
}
}
binding.totalTouch.setOnClickListener { update() }
binding.lastTouchDate.setOnClickListener { update() }
val resolver = lActivity!!.contentResolver val resolver = lActivity!!.contentResolver
val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
val projection = arrayOf( val projection = arrayOf(
@ -82,9 +84,9 @@ internal class ContactMenu : BottomSheetDialogFragment() {
ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.NUMBER,
) )
BLog.LOGE("GetContact", "packageName ${contactId}") BLog.LOGE("GetContact", "packageName ${packageName}")
try { try {
val cursor = resolver.query(phoneUri, projection, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, null , null) val cursor = resolver.query(phoneUri, projection, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + packageName, null , null)
if (cursor != null) { if (cursor != null) {
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
val nameIndex = cursor.getColumnIndex(projection[0]) val nameIndex = cursor.getColumnIndex(projection[0])
@ -118,8 +120,6 @@ internal class ContactMenu : BottomSheetDialogFragment() {
// //
appName() appName()
binding.detailedInfo.setOnClickListener { detailedInfo() } binding.detailedInfo.setOnClickListener { detailedInfo() }
binding.call.setOnClickListener { callPhone() }
binding.sms.setOnClickListener { sendSms() }
// binding.activityBrowser.setOnClickListener { activityBrowser() } // binding.activityBrowser.setOnClickListener { activityBrowser() }
// binding.appStore.setOnClickListener { appStore() } // binding.appStore.setOnClickListener { appStore() }
// binding.appFreeform.setOnClickListener { freeform() } // binding.appFreeform.setOnClickListener { freeform() }
@ -128,7 +128,56 @@ internal class ContactMenu : BottomSheetDialogFragment() {
// binding.appUninstall.setOnClickListener { uninstall() } // binding.appUninstall.setOnClickListener { uninstall() }
} }
/* manage initial preview and clicks for favorite apps */
@SuppressLint("PrivateResource")
private fun favoriteApps() {
val sharedPreferences = requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
val enabledStroke =
ColorStateList.valueOf(requireContext().getColor(com.google.android.material.R.color.material_on_surface_stroke))
val disabledStroke =
ColorStateList.valueOf(requireContext().getColor(com.google.android.material.R.color.m3_chip_stroke_color))
for (position in 1..MAX_FAVORITE_APPS) {
val button = outlinedButton
val savedPackageName = sharedPreferences.getString(KEY_APP_NO_ + position, "")
/* set previews */
if (packageName == savedPackageName) button.isChecked = true
if (savedPackageName?.isNotEmpty() == true) button.strokeColor = enabledStroke
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
packageManager.getPackageInfo(savedPackageName!!, PackageManager.PackageInfoFlags.of(0))
else
packageManager.getPackageInfo(savedPackageName!!, 0)
} catch (e: PackageManager.NameNotFoundException) {
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
.edit().remove(KEY_APP_NO_ + position).apply()
button.strokeColor = disabledStroke
e.printStackTrace()
}
/* listen on clicks */
binding.favGroup.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?,
checkedId: Int, isChecked: Boolean ->
try {
if (checkedId == button.id) {
if (isChecked) {
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
.edit().putString(KEY_APP_NO_ + position, packageName).apply()
button.strokeColor = enabledStroke
} else {
requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0)
.edit().remove(KEY_APP_NO_ + position).apply()
button.strokeColor = disabledStroke
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
private fun appName() { private fun appName() {
binding.appName.text = contactName binding.appName.text = contactName
@ -138,21 +187,195 @@ internal class ContactMenu : BottomSheetDialogFragment() {
private fun detailedInfo() { private fun detailedInfo() {
var intent = Intent(Intent.ACTION_VIEW); var intent = Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + "/" + contactId)); intent.setData(Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + "/" + packageName));
startActivity(intent); startActivity(intent);
} }
private fun sendSms() { /* activity browser dialog */
var intent = Intent(Intent.ACTION_SEND); private fun activityBrowser() {
intent.setData(Uri.parse("smsto:" + contactPhoneNumber)); val dialogBinding = ActivityBrowserDialogBinding.inflate(lActivity!!.layoutInflater)
startActivity(intent); val dialogBuilder = MaterialAlertDialogBuilder(lActivity!!)
} .setView(dialogBinding.root)
private fun callPhone() { .setPositiveButton(android.R.string.cancel, null)
var intent = Intent(Intent.ACTION_DIAL); .show()
intent.setData(Uri.parse("tel:" + contactPhoneNumber));
startActivity(intent); /* show app name */
dialogBinding.appName.text = packageManager.getApplicationLabel(appInfo)
/* get activity info */
val activityInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.getPackageInfo(
packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_ACTIVITIES.toLong())
)
} else {
packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES)
}
/* show activity list */
val activityAdapter: ArrayAdapter<String> =
ArrayAdapter(requireContext(), R.layout.list_item, R.id.itemText, ArrayList())
if (activityInfo.activities.isNotEmpty()) {
for (activity in activityInfo.activities) {
activityAdapter.add(
activity.toString().split(" ").toTypedArray()[1].replace("}", "")
)
}
dialogBinding.activityList.adapter = activityAdapter
}
/* listen item clicks */
dialogBinding.activityList.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, i: Int, _: Long ->
try {
/* open activity */
val intent = Intent()
intent.component = ComponentName(packageName, activityAdapter.getItem(i).toString())
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
requireContext().startActivity(intent)
} catch (exception: Exception) {
/* couldn't open activity */
exception.printStackTrace()
val exceptionShort = (exception.toString().split(": ").toTypedArray())[0]
Toast.makeText(requireContext(),
"${resources.getString(R.string.unable_to_launch)} -\n$exceptionShort", Toast.LENGTH_LONG).show()
}
dialogBuilder.dismiss()
}
} }
/* open app's page in app store/market */
private fun appStore() {
try {
val storeIntent = Intent(Intent.ACTION_VIEW)
storeIntent.data = Uri.parse("market://details?id=$packageName")
storeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
requireContext().startActivity(storeIntent)
} catch (activityNotFoundException: ActivityNotFoundException) {
/* no app store found exception */
Toast.makeText(requireContext(), requireContext().getString(R.string.null_app_store_message),
Toast.LENGTH_SHORT).show()
activityNotFoundException.printStackTrace()
}
this.dismiss()
}
/* launch app as a freeform window */
private fun freeform() {
val freeformIntent = requireContext().packageManager.getLaunchIntentForPackage(packageName)
freeformIntent!!.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT or
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
val rect = Rect(0, screenHeight / 2, screenWidth, screenHeight)
var activityOptions = activityOptions
activityOptions = activityOptions.setLaunchBounds(rect)
requireContext().startActivity(freeformIntent, activityOptions.toBundle())
this.dismiss()
}
/* open android's app info screen */
private fun appInfo() {
val infoIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
infoIntent.data = Uri.parse("package:$packageName")
infoIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
requireContext().startActivity(infoIntent)
this.dismiss()
}
private fun share() {
try {
// Create a temporary file to copy the APK
val apkLabel = packageManager.getApplicationLabel(appInfo).toString().lowercase().replace(" ", "_")
val tempApkFile = File(requireContext().externalCacheDir, "$apkLabel.apk")
// Copy the APK file
FileInputStream(File(appInfo.sourceDir)).use { `in` ->
FileOutputStream(tempApkFile).use { out ->
val buffer = ByteArray(1024)
var length: Int
while (`in`.read(buffer).also { length = it } > 0) {
out.write(buffer, 0, length)
}
}
}
// Generate a content URI using FileProvider
val contentUri =
FileProvider.getUriForFile(requireContext(), "${requireContext().packageName}.fileprovider", tempApkFile)
//requireContext().grantUriPermission(receivers.package.name, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
// Create a Share Intent
Intent(Intent.ACTION_SEND).apply {
type = "application/vnd.android.package-archive"
putExtra(Intent.EXTRA_STREAM, contentUri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}.let {
// Start the chooser activity
startActivity(Intent.createChooser(it, getString(R.string.share_apk_message)))
}
}
catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() }
catch (e: IOException) { e.printStackTrace() }
this.dismiss()
}
/* uninstall the app */
private fun uninstall() {
val uninstallIntent = Intent(Intent.ACTION_DELETE)
uninstallIntent.data = Uri.parse("package:$packageName")
uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
requireContext().startActivity(uninstallIntent)
this.dismiss()
}
/* create and add an outlined button to the toggle group */
private val outlinedButton: MaterialButton get() {
val style = com.google.android.material.R.attr.materialButtonOutlinedStyle
val button = MaterialButton(requireContext(), null, style)
button.layoutParams = LinearLayoutCompat.LayoutParams(
LinearLayoutCompat.LayoutParams.WRAP_CONTENT,
LinearLayoutCompat.LayoutParams.WRAP_CONTENT, 1F
)
binding.favGroup.addView(button)
return button
}
/* long value to local date-time format */
private fun dateTimeFormat(long: Long) : String = SimpleDateFormat.getDateTimeInstance().format(Date(long))
/* get and arrange all the permissions for an application */
private val permissionsList : String get() {
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong()))
} else {
packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
}
return if (packageInfo.requestedPermissions.isNotEmpty()) {
val stringBuilder = StringBuilder()
packageInfo.requestedPermissions.indices.forEach { i: Int ->
if (i != packageInfo.requestedPermissions.size - 1)
stringBuilder.append("${packageInfo.requestedPermissions[i]}\n\n")
/* don't add any new line after the last entry */
else
stringBuilder.append(packageInfo.requestedPermissions[i])
}
stringBuilder.toString()
} else {
""
}
}
/* get activity options for launching app in freeform mode */
private val activityOptions: ActivityOptions get() {
val activityOptions = ActivityOptions.makeBasic()
try {
val method =
ActivityOptions::class.java.getMethod("setLaunchWindowingMode", Int::class.javaPrimitiveType)
method.invoke(activityOptions, 5)
} catch (exception: Exception) {
exception.printStackTrace()
}
return activityOptions
}
} }

View File

@ -152,10 +152,9 @@ internal class RssItemAdapter (
}.dispatchUpdatesTo(this).apply { }.dispatchUpdatesTo(this).apply {
val visibleItemCount = (layoutManager?.findLastVisibleItemPosition() ?: 0) - (layoutManager?.findFirstVisibleItemPosition() ?: 0) val visibleItemCount = (layoutManager?.findLastVisibleItemPosition() ?: 0) - (layoutManager?.findFirstVisibleItemPosition() ?: 0)
val first = layoutManager?.findLastVisibleItemPosition() ?: 0
if (visibleItemCount > 0) { if (visibleItemCount > 0) {
this@RssItemAdapter.notifyItemRangeChanged(first, visibleItemCount) this@RssItemAdapter.notifyItemRangeChanged(0, visibleItemCount)
// recyclerView?.scrollToPosition(0) recyclerView?.scrollToPosition(0)
} }
} }
rssDataItemLis.clear() rssDataItemLis.clear()

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="800dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M309.5,494.1c-1.9,0 -3.5,0.3 -4.7,0.8 1.6,-0.5 3.4,-0.8 5.2,-0.8h-0.5zM845.1,707.5c0.1,-1 0.2,-2 0.4,-2.9 -0.2,0.4 -0.3,1.4 -0.4,2.9zM880.9,313.3c0,-0 0,-0.1 0,-0.1v-0.5c0,0.2 0,0.4 -0,0.6zM845.1,313.2c0,0 0,0.1 0,0.1 -0,-0.2 -0,-0.4 -0,-0.6v0.5zM866.7,849.4a348,348 0,0 0,-32.7 -107.5c-3.3,-6.6 -6.7,-13.1 -10.4,-19.5a0.2,0.2 0,0 0,-0 -0.1c-15.9,-26.9 -35.3,-51.8 -58,-74.1l-0,-0c-4.9,-4.8 -10,-9.6 -15.2,-14.1 -37.3,-32.7 -80.3,-56.9 -126.3,-71.7 8.3,-4.6 16.4,-9.8 24.1,-15.5 8.8,-6.5 17.2,-13.7 25,-21.5 41.4,-41.4 64.2,-96.4 64.2,-155 0,-58.5 -22.8,-113.6 -64.2,-155 -40.6,-40.6 -94.4,-63.3 -151.8,-64.2 -0.9,-0 -1.8,-0 -2.7,-0 -0.9,0 -1.8,0 -2.7,0 -57.3,0.8 -111.1,23.5 -151.8,64.2 -41.4,41.4 -64.2,96.4 -64.2,155 0,58.5 22.8,113.6 64.2,155 7.9,7.9 16.2,15.1 25,21.5 7.7,5.7 15.8,10.9 24.1,15.5 -45.9,14.7 -89,39 -126.3,71.7 -5.2,4.6 -10.3,9.3 -15.2,14.1 -22.7,22.3 -42.2,47.2 -58,74.1 -3.7,6.4 -7.1,12.9 -10.4,19.5a348,348 0,0 0,-32.7 107.5c-1.6,12 6.8,23 18.8,24.6 1,0.1 2,0.2 3,0.2 0.9,0 1.8,-0.1 2.6,-0.2 8.7,-1.9 15.7,-9 17,-18.3 10.1,-69.3 43.1,-132.3 90.6,-180.3 56.4,-57 133.1,-92.7 216,-92.9h0.5c82.7,0.3 159.3,36 215.5,92.9 47.5,48 80.5,111 90.6,180.3 1.4,9.3 8.3,16.3 17,18.2 0,0 0,0 0.1,0 0.9,0.1 1.7,0.2 2.6,0.2 1,0 2,-0.1 3,-0.2 12,-1.6 20.4,-12.6 18.8,-24.6zM518.2,545.9c-0.4,0 -0.9,0 -1.3,-0 -81.8,-0.6 -154.7,-57.4 -174.7,-133.7 -0.2,-0.8 -0.4,-1.7 -0.6,-2.5 -3.1,-12.6 -4.8,-25.7 -4.8,-39.2s1.7,-26.7 4.8,-39.5c0.2,-0.9 0.4,-1.7 0.6,-2.6 20,-78.1 93.7,-140.3 176,-140.3h0.9c82.3,0 155.9,62.1 176,140.3 0.2,0.9 0.4,1.7 0.6,2.6 3.1,12.8 4.8,26.1 4.8,39.5 0,13.4 -1.7,26.5 -4.8,39.2 -0.2,0.8 -0.4,1.7 -0.6,2.5 -19.9,76.2 -92.9,133.1 -174.7,133.7 -0.8,0 -1.5,0 -2.3,0z"
android:fillColor="#000000"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="800dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M885.7,741.4L515,741.4l-105.4,105.4c-0.8,0.8 -1.8,1.1 -2.6,1.7 -0.8,0.6 -1.3,1.4 -2.2,1.9 -0.4,0.2 -0.9,0.2 -1.3,0.4 -1.5,0.7 -3.1,1.2 -4.7,1.5 -1.2,0.3 -2.4,0.6 -3.6,0.7 -1.6,0.1 -3,-0.1 -4.6,-0.3 -1.4,-0.2 -2.7,-0.3 -4,-0.8 -1.2,-0.4 -2.3,-1 -3.4,-1.6 -1.6,-0.8 -3,-1.7 -4.3,-2.9 -0.3,-0.3 -0.8,-0.4 -1.1,-0.7 -0.5,-0.5 -0.7,-1.3 -1.2,-1.8 -0.7,-0.9 -1.7,-1.5 -2.3,-2.5L314.3,741.4L169.8,741.4c-49.4,0 -89.5,-40.1 -89.5,-89.5L80.4,226.9c0,-49.4 40.1,-89.5 89.5,-89.5h715.9c49.4,0 89.5,40.1 89.5,89.5v425.1c0,49.4 -40.1,89.5 -89.5,89.5zM307.1,729.3c-1.2,-2.1 -1.8,-4.3 -2.3,-6.5 0.6,3.5 1.9,6.6 3.9,9.3l-1.6,-2.8zM312,702.3c-0.6,0.5 -1.2,0.9 -1.7,1.5 0.5,-0.5 1.2,-1 1.7,-1.5zM304.3,720.2c-0.1,-1.2 0.2,-2.3 0.3,-3.5 -0.1,0.8 -0.5,1.5 -0.5,2.4 0,0.4 0.2,0.7 0.2,1.1zM306.6,709.2c-0.3,0.6 -0.7,1.2 -0.9,1.8 0.2,-0.6 0.6,-1.2 0.9,-1.8zM930.5,226.9c0,-24.7 -20,-44.7 -44.7,-44.7L169.8,182.1c-24.7,0 -44.7,20 -44.7,44.7L125.1,651.9c0,24.7 20,44.7 44.7,44.7h156.6c-0.3,0 -0.6,0.2 -0.9,0.2 8,-0.3 16,3.3 20.3,10.6l51.8,87.4 91.7,-91.8c4.6,-4.6 10.7,-6.7 16.7,-6.5h379.7c24.7,0 44.7,-20 44.7,-44.7L930.5,226.9zM317,698.9c0.9,-0.4 1.8,-0.6 2.7,-0.9 -0.9,0.3 -1.9,0.5 -2.7,0.9zM729.1,473c-24.7,0 -44.7,-20 -44.7,-44.7 0,-24.7 20,-44.7 44.7,-44.7 24.7,0 44.7,20 44.7,44.7s-20,44.7 -44.7,44.7zM527.8,473c-24.7,0 -44.7,-20 -44.7,-44.7 0,-24.7 20,-44.7 44.7,-44.7s44.7,20 44.7,44.7 -20,44.7 -44.7,44.7zM326.4,473c-24.7,0 -44.7,-20 -44.7,-44.7 0,-24.7 20,-44.7 44.7,-44.7s44.7,20 44.7,44.7 -20,44.7 -44.7,44.7z"
android:fillColor="#000000"/>
</vector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="800dp"
android:height="800dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M737.6,934.4c-342.4,0 -624.8,-258.4 -656.8,-600.8v-0.8c-0.8,-5.6 -1.6,-12.8 -2.4,-19.2 0,-4.8 -0.8,-10.4 -0.8,-14.4 0.8,-70.4 36,-135.2 95.2,-175.2 30.4,-20.8 66.4,-32.8 103.2,-34.4h12.8c63.2,0 123.2,28 163.2,76.8 44,52.8 58.4,123.2 40.8,192 -17.6,68 -69.6,121.6 -138.4,144l-22.4,7.2 14.4,18.4c63.2,80 140,143.2 228.8,188.8l18.4,9.6 4.8,-20c16,-72 80.8,-125.6 158.4,-129.6h8c94.4,0 173.6,72 181.6,164.8 2.4,25.6 -1.6,51.2 -9.6,76 -22.4,62.4 -77.6,107.2 -144,116.8 -4.8,0.8 -8.8,0.8 -13.6,1.6 -13.6,-2.4 -28,-1.6 -41.6,-1.6zM117.6,328c30.4,324 296.8,568 620,568 12.8,0 26.4,-0.8 40,-1.6h3.2c2.4,0 4.8,0 7.2,-0.8 52.8,-7.2 96,-43.2 114.4,-92 7.2,-19.2 9.6,-39.2 8,-60 -5.6,-72 -69.6,-130.4 -141.6,-130.4h-6.4c-62.4,4 -115.2,46.4 -130.4,105.6 -5.6,20.8 -27.2,36.8 -50.4,36.8 -8,0 -15.2,-1.6 -21.6,-4.8 -110.4,-56 -204.8,-140.8 -274.4,-244 -4,-5.6 -4,-12.8 -1.6,-18.4 3.2,-6.4 9.6,-11.2 16.8,-12 74.4,-4.8 139.2,-56 157.6,-125.6 15.2,-56.8 2.4,-115.2 -33.6,-158.4 -33.6,-40 -82.4,-63.2 -134.4,-63.2H280c-30.4,1.6 -60,12 -84.8,28.8 -48.8,32 -78.4,86.4 -78.4,144V312c-0.8,4.8 0,10.4 0.8,16z"
android:fillColor="#000000"/>
</vector>

View File

@ -8,52 +8,37 @@
android:clickable="true" android:clickable="true"
android:focusableInTouchMode="true"> android:focusableInTouchMode="true">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/appNameInputLayout"
<TextView android:layout_width="match_parent"
android:id="@+id/appName"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="@dimen/zero"
android:textSize="30dp"
android:gravity="center" android:gravity="center"
app:layout_constraintTop_toTopOf="parent" app:hintEnabled="false"
app:layout_constraintLeft_toLeftOf="parent" app:boxStrokeWidth="@dimen/zero"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintEnd_toEndOf="parent"
android:padding="@dimen/eight" app:layout_constraintStart_toStartOf="parent"
android:inputType="textNoSuggestions"/> app:layout_constraintTop_toTopOf="parent" >
<TextView
android:id="@+id/totalTouch"
android:layout_margin="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/appName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_vertical|left"
android:padding="@dimen/eight"
android:inputType="textNoSuggestions"
/>
<TextView
android:id="@+id/lastTouchDate" <com.google.android.material.textfield.TextInputEditText
android:layout_margin="20dp" android:id="@+id/appName"
app:layout_constraintRight_toRightOf="parent" android:layout_width="wrap_content"
app:layout_constraintTop_toBottomOf="@id/appName" android:layout_height="wrap_content"
android:layout_width="0dp" android:minWidth="@dimen/zero"
android:layout_height="wrap_content" android:gravity="center"
android:gravity="center_vertical|right" android:padding="@dimen/eight"
android:padding="@dimen/eight" android:inputType="textNoSuggestions"
android:inputType="textNoSuggestions" android:textAppearance="@style/TextAppearance.Material3.TitleLarge" />
/> </com.google.android.material.textfield.TextInputLayout>
<TextView
<com.google.android.material.button.MaterialButton
android:id="@+id/appPackage" android:id="@+id/appPackage"
android:textSize="20dp" style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/eight" android:layout_marginTop="@dimen/eight"
app:layout_constraintTop_toBottomOf="@id/totalTouch"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/> app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appNameInputLayout" />
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/activityBrowser" android:id="@+id/activityBrowser"
@ -83,10 +68,10 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appPackage" /> app:layout_constraintTop_toBottomOf="@+id/appPackage" />
<View <com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/favGroup" android:id="@+id/favGroup"
android:layout_width="@dimen/zero" android:layout_width="@dimen/zero"
android:layout_height="1dp" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/eight" android:layout_marginTop="@dimen/eight"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View File

@ -17,36 +17,12 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="@dimen/zero" android:minWidth="@dimen/zero"
android:textSize="28dp"
android:gravity="center" android:gravity="center"
android:padding="@dimen/eight" android:padding="@dimen/eight"
android:inputType="textNoSuggestions" android:inputType="textNoSuggestions"
/> />
<TextView
android:id="@+id/totalTouch"
android:layout_margin="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/appName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_vertical|left"
android:padding="@dimen/eight"
android:inputType="textNoSuggestions"
/>
<TextView
android:id="@+id/lastTouchDate"
android:layout_margin="20dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/appName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_vertical|right"
android:padding="@dimen/eight"
android:inputType="textNoSuggestions"
/>
<TextView <TextView
android:textSize="30dp"
android:id="@+id/phoneNumber" android:id="@+id/phoneNumber"
style="@style/Widget.Material3.Button.TextButton" style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -54,48 +30,115 @@
android:layout_marginTop="@dimen/eight" android:layout_marginTop="@dimen/eight"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/totalTouch" /> app:layout_constraintTop_toBottomOf="@+id/appName" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/activityBrowser"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/eight"
android:contentDescription="@null"
android:src="@drawable/ic_activity"
android:tooltipText="@string/activity_browser"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/detailedInfo"
app:layout_constraintTop_toBottomOf="@+id/phoneNumber" />
<LinearLayout <com.google.android.material.floatingactionbutton.FloatingActionButton
app:layout_constraintTop_toBottomOf="@id/phoneNumber" android:id="@+id/detailedInfo"
android:gravity="center" style="@style/Widget.Material3.ExtendedFloatingActionButton.Surface"
android:orientation="horizontal" android:layout_width="wrap_content"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content"> android:layout_marginTop="@dimen/eight"
<rasel.lunar.launcher.view.CircleImageView android:layout_marginEnd="@dimen/eight"
app:civ_circle_background_color="#77FFFFFF" android:contentDescription="@null"
app:civ_border_width="8dp" android:src="@drawable/ic_info"
app:civ_border_color="#77FFFFFF" android:tooltipText="@string/detailed_info"
android:adjustViewBounds="true" app:layout_constraintEnd_toStartOf="@id/activityBrowser"
android:layout_width="80dp" app:layout_constraintHorizontal_chainStyle="packed"
android:layout_height="80dp" app:layout_constraintStart_toStartOf="parent"
android:id="@+id/detailedInfo" app:layout_constraintTop_toBottomOf="@+id/phoneNumber" />
android:layout_margin="@dimen/eight"
android:src="@drawable/contact" <com.google.android.material.button.MaterialButtonToggleGroup
/> android:id="@+id/favGroup"
<rasel.lunar.launcher.view.CircleImageView android:layout_width="@dimen/zero"
app:civ_circle_background_color="#77FFFFFF" android:layout_height="wrap_content"
app:civ_border_width="8dp" android:layout_marginTop="@dimen/eight"
app:civ_border_color="#77FFFFFF" app:layout_constraintEnd_toEndOf="parent"
android:adjustViewBounds="true" app:layout_constraintStart_toStartOf="parent"
android:layout_width="80dp" app:layout_constraintTop_toBottomOf="@+id/detailedInfo"
android:layout_height="80dp" app:singleSelection="true" />
android:id="@+id/sms"
android:layout_margin="@dimen/eight" <com.google.android.material.floatingactionbutton.FloatingActionButton
android:src="@drawable/message" android:id="@+id/appInfo"
/> style="@style/Widget.Material3.ExtendedFloatingActionButton.Surface"
<rasel.lunar.launcher.view.CircleImageView android:layout_width="wrap_content"
app:civ_circle_background_color="#77FFFFFF" android:layout_height="wrap_content"
app:civ_border_width="8dp" android:layout_marginTop="@dimen/eight"
app:civ_border_color="#77FFFFFF" android:layout_marginEnd="@dimen/eight"
android:adjustViewBounds="true" android:contentDescription="@null"
android:layout_width="80dp" android:src="@drawable/ic_info2"
android:layout_height="80dp" android:tooltipText="@string/app_info"
android:id="@+id/call" app:layout_constraintEnd_toStartOf="@id/appFreeform"
android:layout_margin="@dimen/eight" app:layout_constraintHorizontal_chainStyle="packed"
android:src="@drawable/phonecall" app:layout_constraintStart_toStartOf="parent"
/> app:layout_constraintTop_toBottomOf="@+id/favGroup" />
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/appFreeform"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/eight"
android:layout_marginEnd="@dimen/eight"
android:contentDescription="@null"
android:src="@drawable/ic_pip"
android:tooltipText="@string/freeform"
app:layout_constraintEnd_toStartOf="@id/appStore"
app:layout_constraintStart_toEndOf="@id/appInfo"
app:layout_constraintTop_toBottomOf="@+id/favGroup" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/appStore"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/eight"
android:layout_marginEnd="@dimen/eight"
android:contentDescription="@null"
android:src="@drawable/ic_store"
android:tooltipText="@string/app_store"
app:layout_constraintEnd_toStartOf="@id/appShare"
app:layout_constraintStart_toEndOf="@id/appFreeform"
app:layout_constraintTop_toBottomOf="@+id/favGroup" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/appShare"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/eight"
android:layout_marginEnd="@dimen/eight"
android:contentDescription="@null"
android:src="@drawable/ic_share"
android:tooltipText="@string/share"
app:layout_constraintEnd_toStartOf="@id/appUninstall"
app:layout_constraintStart_toEndOf="@id/appStore"
app:layout_constraintTop_toBottomOf="@+id/favGroup" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/appUninstall"
style="@style/Widget.Material3.ExtendedFloatingActionButton.Surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/eight"
android:contentDescription="@null"
android:src="@drawable/ic_delete"
android:tooltipText="@string/uninstall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/appShare"
app:layout_constraintTop_toBottomOf="@+id/favGroup"
app:tint="@android:color/holo_red_light" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>