Feat: Basic starter to add Widget support.
This commit is contained in:
13
.vscode/easycode.ignore
vendored
Normal file
13
.vscode/easycode.ignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
vendor/
|
||||||
|
cache/
|
||||||
|
.*/
|
||||||
|
*.min.*
|
||||||
|
*.test.*
|
||||||
|
*.spec.*
|
||||||
|
*.bundle.*
|
||||||
|
*.bundle-min.*
|
||||||
|
*.*.js
|
||||||
|
*.*.ts
|
||||||
|
*.log
|
||||||
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
|||||||
If the program does terminal interaction, make it output a short
|
If the program does terminal interaction, make it output a short
|
||||||
notice like this when it starts in an interactive mode:
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
AsterLauncher Copyright (C) 2024 neophtex
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ android {
|
|||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
|
dataBinding = true
|
||||||
}
|
}
|
||||||
|
|
||||||
applicationVariants.all {
|
applicationVariants.all {
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
tools:ignore="QueryAllPackagesPermission" />
|
tools:ignore="QueryAllPackagesPermission" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||||
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
||||||
|
<uses-permission android:name="android.permission.BIND_APPWIDGET"
|
||||||
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ object Constants {
|
|||||||
const val PACKAGE_NAME = "app.easy.launcher"
|
const val PACKAGE_NAME = "app.easy.launcher"
|
||||||
const val PACKAGE_NAME_DEBUG = "$PACKAGE_NAME.debug"
|
const val PACKAGE_NAME_DEBUG = "$PACKAGE_NAME.debug"
|
||||||
|
|
||||||
|
const val WIDGETS_PREFS = "EasyLauncherWidgets.pref"
|
||||||
|
const val APP_WIDGETS_ID = "APP_WIDGETS_ID"
|
||||||
|
|
||||||
const val PREFS_FILENAME = "EasyLauncher.pref"
|
const val PREFS_FILENAME = "EasyLauncher.pref"
|
||||||
const val FIRST_LAUNCH = "FIRST_LAUNCH"
|
const val FIRST_LAUNCH = "FIRST_LAUNCH"
|
||||||
const val SHOW_DATE = "SHOW_DATE"
|
const val SHOW_DATE = "SHOW_DATE"
|
||||||
@@ -39,8 +42,6 @@ object Constants {
|
|||||||
const val HOME_TIME_ALIGNMENT = "HOME_TIME_ALIGNMENT"
|
const val HOME_TIME_ALIGNMENT = "HOME_TIME_ALIGNMENT"
|
||||||
const val HOME_APP_ALIGNMENT = "HOME_APP_ALIGNMENT"
|
const val HOME_APP_ALIGNMENT = "HOME_APP_ALIGNMENT"
|
||||||
const val HOME_DAILY_WORD_ALIGNMENT = "HOME_DAILY_WORD_ALIGNMENT"
|
const val HOME_DAILY_WORD_ALIGNMENT = "HOME_DAILY_WORD_ALIGNMENT"
|
||||||
const val HOME_DRAW_ALIGNMENT = "HOME_DRAW_ALIGNMENT"
|
|
||||||
const val HOME_BATTERY_ALIGNMENT = "HOME_BATTERY_ALIGNMENT"
|
|
||||||
|
|
||||||
const val NOTIFICATION_SERVICE = "statusbar"
|
const val NOTIFICATION_SERVICE = "statusbar"
|
||||||
const val NOTIFICATION_MANAGER = "android.app.StatusBarManager"
|
const val NOTIFICATION_MANAGER = "android.app.StatusBarManager"
|
||||||
@@ -61,5 +62,6 @@ object Constants {
|
|||||||
const val URL_GOOGLE_PLAY_STORE = "https://play.google.com/store/search?c=apps&q"
|
const val URL_GOOGLE_PLAY_STORE = "https://play.google.com/store/search?c=apps&q"
|
||||||
const val APP_GOOGLE_PLAY_STORE = "market://search?c=apps&q"
|
const val APP_GOOGLE_PLAY_STORE = "market://search?c=apps&q"
|
||||||
|
|
||||||
|
const val APP_WIDGET_HOST_ID = 1024
|
||||||
const val REQUEST_CODE_ENABLE_ADMIN = 123
|
const val REQUEST_CODE_ENABLE_ADMIN = 123
|
||||||
}
|
}
|
||||||
@@ -101,11 +101,11 @@ class AppHelper @Inject constructor() {
|
|||||||
fun dayNightMod(context: Context, view: View) {
|
fun dayNightMod(context: Context, view: View) {
|
||||||
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
||||||
Configuration.UI_MODE_NIGHT_YES -> {
|
Configuration.UI_MODE_NIGHT_YES -> {
|
||||||
view.setBackgroundColor(context.resources.getColor(R.color.blackTrans50, context.theme))
|
view.setBackgroundColor(context.resources.getColor(R.color.blackTrans25, context.theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
Configuration.UI_MODE_NIGHT_NO -> {
|
Configuration.UI_MODE_NIGHT_NO -> {
|
||||||
view.setBackgroundColor(context.resources.getColor(R.color.whiteTrans50, context.theme))
|
view.setBackgroundColor(context.resources.getColor(R.color.whiteTrans25, context.theme))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun observeUI() {
|
private fun observeUI() {
|
||||||
binding.pager.currentItem = 0
|
binding.pager.currentItem = 1
|
||||||
preferenceViewModel.setShowStatusBar(preferenceHelper.showStatusBar)
|
preferenceViewModel.setShowStatusBar(preferenceHelper.showStatusBar)
|
||||||
preferenceViewModel.showStatusBarLiveData.observe(this) {
|
preferenceViewModel.showStatusBarLiveData.observe(this) {
|
||||||
if (it) appHelper.showStatusBar(this.window)
|
if (it) appHelper.showStatusBar(this.window)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class DrawFragment : Fragment(), OnItemClickedListener.OnAppsClickedListener,
|
|||||||
OnItemClickedListener.OnAppLongClickedListener,
|
OnItemClickedListener.OnAppLongClickedListener,
|
||||||
OnItemClickedListener.BottomSheetDismissListener,
|
OnItemClickedListener.BottomSheetDismissListener,
|
||||||
OnItemClickedListener.OnAppStateClickListener,
|
OnItemClickedListener.OnAppStateClickListener,
|
||||||
FingerprintHelper.Callback{
|
FingerprintHelper.Callback {
|
||||||
private var _binding: FragmentDrawBinding? = null
|
private var _binding: FragmentDrawBinding? = null
|
||||||
|
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
@@ -181,14 +181,12 @@ class DrawFragment : Fragment(), OnItemClickedListener.OnAppsClickedListener,
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
observeDrawerApps()
|
observeDrawerApps()
|
||||||
binding.drawAdapter.scrollToPosition(0)
|
|
||||||
if (preferenceHelper.automaticKeyboard) binding.searchViewText.showKeyboard()
|
if (preferenceHelper.automaticKeyboard) binding.searchViewText.showKeyboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
observeDrawerApps()
|
observeDrawerApps()
|
||||||
binding.drawAdapter.scrollToPosition(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
import com.github.droidworksstudio.launcher.ui.drawer.DrawFragment
|
import com.github.droidworksstudio.launcher.ui.drawer.DrawFragment
|
||||||
import com.github.droidworksstudio.launcher.ui.home.HomeFragment
|
import com.github.droidworksstudio.launcher.ui.home.HomeFragment
|
||||||
|
import com.github.droidworksstudio.launcher.ui.widgetmanager.WidgetManagerFragment
|
||||||
|
|
||||||
|
|
||||||
class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
||||||
FragmentStateAdapter(fragmentManager, lifecycle) {
|
FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||||
|
|
||||||
private val fragments: ArrayList<Fragment> = arrayListOf(
|
private val fragments: ArrayList<Fragment> = arrayListOf(
|
||||||
|
WidgetManagerFragment(),
|
||||||
HomeFragment(),
|
HomeFragment(),
|
||||||
DrawFragment(),
|
DrawFragment(),
|
||||||
)
|
)
|
||||||
@@ -23,5 +25,4 @@ class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
|||||||
override fun createFragment(position: Int): Fragment {
|
override fun createFragment(position: Int): Fragment {
|
||||||
return fragments[position]
|
return fragments[position]
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.github.droidworksstudio.launcher.ui.widgetmanager
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetHost
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.github.droidworksstudio.launcher.R
|
||||||
|
|
||||||
|
class WidgetAdapter(
|
||||||
|
private val context: Context,
|
||||||
|
private val appWidgetHost: AppWidgetHost,
|
||||||
|
private val onWidgetClick: (Int) -> Unit
|
||||||
|
) : RecyclerView.Adapter<WidgetAdapter.WidgetViewHolder>() {
|
||||||
|
|
||||||
|
private val widgetItems = mutableListOf<WidgetItem>()
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WidgetViewHolder {
|
||||||
|
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_widget, parent, false)
|
||||||
|
return WidgetViewHolder(itemView)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: WidgetViewHolder, position: Int) {
|
||||||
|
val widgetItem = widgetItems[position]
|
||||||
|
holder.bind(widgetItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = widgetItems.size
|
||||||
|
|
||||||
|
fun addWidget(widgetItem: WidgetItem) {
|
||||||
|
widgetItems.add(widgetItem)
|
||||||
|
notifyItemInserted(widgetItems.size - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeWidget(appWidgetId: Int) {
|
||||||
|
val position = widgetItems.indexOfFirst { it.appWidgetId == appWidgetId }
|
||||||
|
if (position != -1) {
|
||||||
|
widgetItems.removeAt(position)
|
||||||
|
notifyItemRemoved(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getWidgetIds(): List<Int> = widgetItems.map { it.appWidgetId }
|
||||||
|
|
||||||
|
inner class WidgetViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
fun bind(widgetItem: WidgetItem) {
|
||||||
|
val hostView = appWidgetHost.createView(context, widgetItem.appWidgetId, widgetItem.appWidgetInfo)
|
||||||
|
itemView.findViewById<FrameLayout>(R.id.widget_frame).addView(hostView)
|
||||||
|
|
||||||
|
itemView.setOnClickListener {
|
||||||
|
onWidgetClick(widgetItem.appWidgetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.github.droidworksstudio.launcher.ui.widgetmanager
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetProviderInfo
|
||||||
|
|
||||||
|
data class WidgetItem(val appWidgetId: Int, val appWidgetInfo: AppWidgetProviderInfo?)
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
package com.github.droidworksstudio.launcher.ui.widgetmanager
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.appwidget.AppWidgetHost
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.github.droidworksstudio.launcher.Constants
|
||||||
|
import com.github.droidworksstudio.launcher.databinding.FragmentWidgetManagerBinding
|
||||||
|
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple [Fragment] subclass as the second destination in the navigation.
|
||||||
|
*/
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class WidgetManagerFragment : Fragment(), WidgetOptionsDialogFragment.WidgetOptionsListener {
|
||||||
|
|
||||||
|
private var _binding: FragmentWidgetManagerBinding? = null
|
||||||
|
|
||||||
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private lateinit var pickWidgetLauncher: ActivityResultLauncher<Intent>
|
||||||
|
private lateinit var createWidgetLauncher: ActivityResultLauncher<Intent>
|
||||||
|
|
||||||
|
private lateinit var appWidgetManager: AppWidgetManager
|
||||||
|
private lateinit var appWidgetHost: AppWidgetHost
|
||||||
|
private lateinit var widgetAdapter: WidgetAdapter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var appHelper: AppHelper
|
||||||
|
|
||||||
|
private lateinit var context: Context
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
_binding = FragmentWidgetManagerBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
appHelper.dayNightMod(requireContext(), binding.drawBackground)
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
context = requireContext()
|
||||||
|
|
||||||
|
appWidgetManager = AppWidgetManager.getInstance(requireContext())
|
||||||
|
appWidgetHost = AppWidgetHost(requireContext(), Constants.APP_WIDGET_HOST_ID)
|
||||||
|
|
||||||
|
widgetAdapter = WidgetAdapter(requireContext(), appWidgetHost) { appWidgetId ->
|
||||||
|
showWidgetOptionsDialog(appWidgetId)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.widgetContainer.apply {
|
||||||
|
layoutManager = LinearLayoutManager(requireContext())
|
||||||
|
adapter = widgetAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load saved widgets
|
||||||
|
val savedWidgetIds = loadWidgetIds()
|
||||||
|
for (widgetId in savedWidgetIds) {
|
||||||
|
addWidget(widgetId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the ActivityResultLaunchers
|
||||||
|
pickWidgetLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
|
val data = result.data
|
||||||
|
data?.let {
|
||||||
|
val appWidgetId = it.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
|
||||||
|
if (appWidgetId != -1) {
|
||||||
|
val appWidgetInfo = appWidgetManager.getAppWidgetInfo(appWidgetId)
|
||||||
|
if (appWidgetInfo?.configure != null) {
|
||||||
|
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE)
|
||||||
|
intent.component = appWidgetInfo.configure
|
||||||
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
createWidgetLauncher.launch(intent)
|
||||||
|
} else {
|
||||||
|
addWidget(appWidgetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (result.resultCode == Activity.RESULT_CANCELED) {
|
||||||
|
val appWidgetId = result.data?.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
|
||||||
|
if (appWidgetId != null && appWidgetId != -1) {
|
||||||
|
appWidgetHost.deleteAppWidgetId(appWidgetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createWidgetLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
|
val data = result.data
|
||||||
|
data?.let {
|
||||||
|
val appWidgetId = it.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
|
||||||
|
if (appWidgetId != -1) {
|
||||||
|
addWidget(appWidgetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (result.resultCode == Activity.RESULT_CANCELED) {
|
||||||
|
val appWidgetId = result.data?.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
|
||||||
|
if (appWidgetId != null && appWidgetId != -1) {
|
||||||
|
appWidgetHost.deleteAppWidgetId(appWidgetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set long-click listener on the root view
|
||||||
|
binding.widgetParent.setOnLongClickListener {
|
||||||
|
selectWidget()
|
||||||
|
true // Indicate that the long-click event has been handled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectWidget() {
|
||||||
|
val appWidgetId = appWidgetHost.allocateAppWidgetId()
|
||||||
|
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_PICK)
|
||||||
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
pickWidgetLauncher.launch(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun addWidget(appWidgetId: Int) {
|
||||||
|
val appWidgetInfo = appWidgetManager.getAppWidgetInfo(appWidgetId)
|
||||||
|
appWidgetInfo?.let {
|
||||||
|
val widgetItem = WidgetItem(appWidgetId, it)
|
||||||
|
widgetAdapter.addWidget(widgetItem)
|
||||||
|
saveWidgetIds(widgetAdapter.getWidgetIds()) // Save the updated widget IDs
|
||||||
|
} ?: Log.e("WidgetManagerFragment", "Failed to get app widget info for ID: $appWidgetId")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoveWidget(appWidgetId: Int) {
|
||||||
|
appWidgetHost.deleteAppWidgetId(appWidgetId)
|
||||||
|
widgetAdapter.removeWidget(appWidgetId)
|
||||||
|
saveWidgetIds(widgetAdapter.getWidgetIds())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showWidgetOptionsDialog(appWidgetId: Int) {
|
||||||
|
val dialog = WidgetOptionsDialogFragment.newInstance(appWidgetId)
|
||||||
|
dialog.show(childFragmentManager, "WidgetOptionsDialog")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOpenAppWidget(appWidgetId: Int) {
|
||||||
|
// Implement the logic to open the widget's configuration or app
|
||||||
|
// This is typically dependent on the widget and its associated app
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveWidgetIds(widgetIds: List<Int>) {
|
||||||
|
val sharedPreferences = requireContext().getSharedPreferences(Constants.WIDGETS_PREFS, Activity.MODE_PRIVATE)
|
||||||
|
val editor = sharedPreferences.edit()
|
||||||
|
val widgetIdsSet = widgetIds.map { it.toString() }.toSet()
|
||||||
|
editor.putStringSet(Constants.APP_WIDGETS_ID, widgetIdsSet)
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadWidgetIds(): List<Int> {
|
||||||
|
val sharedPreferences = requireContext().getSharedPreferences(Constants.WIDGETS_PREFS, Activity.MODE_PRIVATE)
|
||||||
|
val widgetIdsSet = sharedPreferences.getStringSet(Constants.APP_WIDGETS_ID, emptySet())
|
||||||
|
return widgetIdsSet?.map { it.toInt() } ?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
_binding = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.github.droidworksstudio.launcher.ui.widgetmanager
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.widget.Button
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import com.github.droidworksstudio.launcher.Constants
|
||||||
|
import com.github.droidworksstudio.launcher.R
|
||||||
|
|
||||||
|
class WidgetOptionsDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
|
interface WidgetOptionsListener {
|
||||||
|
fun onRemoveWidget(appWidgetId: Int)
|
||||||
|
fun onOpenAppWidget(appWidgetId: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val appWidgetId = arguments?.getInt(ARG_APP_WIDGET_ID) ?: return super.onCreateDialog(savedInstanceState)
|
||||||
|
|
||||||
|
val builder = AlertDialog.Builder(requireContext())
|
||||||
|
builder.setTitle("Widget Options")
|
||||||
|
.setItems(arrayOf("Remove Widget", "Open Widget")) { _, which ->
|
||||||
|
val listener = parentFragment as? WidgetOptionsListener
|
||||||
|
when (which) {
|
||||||
|
0 -> listener?.onRemoveWidget(appWidgetId)
|
||||||
|
1 -> listener?.onOpenAppWidget(appWidgetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ARG_APP_WIDGET_ID = Constants.APP_WIDGETS_ID
|
||||||
|
|
||||||
|
fun newInstance(appWidgetId: Int): WidgetOptionsDialogFragment {
|
||||||
|
val fragment = WidgetOptionsDialogFragment()
|
||||||
|
val args = Bundle().apply {
|
||||||
|
putInt(ARG_APP_WIDGET_ID, appWidgetId)
|
||||||
|
}
|
||||||
|
fragment.arguments = args
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/src/main/res/layout/fragment_widget_manager.xml
Normal file
26
app/src/main/res/layout/fragment_widget_manager.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/draw_background"
|
||||||
|
tools:context=".ui.widgetmanager.WidgetManagerFragment">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_parent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:longClickable="true"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/widget_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"/>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
6
app/src/main/res/layout/item_widget.xml
Normal file
6
app/src/main/res/layout/item_widget.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/widget_frame"
|
||||||
|
android:padding="8dp"/>
|
||||||
29
app/src/main/res/layout/widget_options_dialog.xml
Normal file
29
app/src/main/res/layout/widget_options_dialog.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_open_app"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Open App"
|
||||||
|
android:textColor="?attr/colorPrimary"
|
||||||
|
android:backgroundTint="?attr/colorAccent"
|
||||||
|
app:backgroundTint="?attr/colorAccent"
|
||||||
|
app:rippleColor="?attr/colorAccent" />
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_remove_widget"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Remove Widget"
|
||||||
|
android:textColor="?attr/colorPrimary"
|
||||||
|
android:backgroundTint="?attr/colorAccent"
|
||||||
|
app:backgroundTint="?attr/colorAccent"
|
||||||
|
app:rippleColor="?attr/colorAccent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user