Initial commit.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.github.droidworksstudio.launcher
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
|
||||
@HiltAndroidApp
|
||||
class Application: Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.github.droidworksstudio.launcher
|
||||
|
||||
object Constants {
|
||||
const val PACKAGE_NAME = "com.github.droidworksstudio.launcher"
|
||||
|
||||
const val PREFS_FILENAME = "droidworksstudioLauncher.pref"
|
||||
const val FIRST_LAUNCH = "FIRST_LAUNCH"
|
||||
const val SHOW_DATE = "SHOW_DATE"
|
||||
const val SHOW_TIME = "SHOW_TIME"
|
||||
const val SHOW_DAILY_WORD = "SHOW_DAILY_WORD"
|
||||
const val SHOW_BATTERY = "SHOW_BATTERY"
|
||||
const val SHOW_STATUS_BAR = "SHOW_STATUS_BAR"
|
||||
const val DOUBLE_TAP_LOCK = "DOUBLE_TAP_LOCK"
|
||||
|
||||
const val DATE_COLOR = "DATE_COLOR"
|
||||
const val TIME_COLOR = "TIME_COLOR"
|
||||
const val BATTERY_COLOR = "BATTERY_COLOR"
|
||||
const val DAILY_WORD_COLOR = "DAILY_WORD_COLOR"
|
||||
const val APP_COLOR = "APP_COLOR"
|
||||
|
||||
const val DATE_TEXT_SIZE = "DATE_TEXT_SIZE"
|
||||
const val TIME_TEXT_SIZE = "TIME_TEXT_SIZE"
|
||||
const val APP_TEXT_SIZE = "APP_TEXT_SIZE"
|
||||
|
||||
const val SHOW_APP_ICON = "SHOW_APP_ICON"
|
||||
|
||||
const val AUTOMATIC_KEYBOARD = "AUTOMATIC_KEYBOARD"
|
||||
const val AUTOMATIC_OPEN_APP = "AUTOMATIC_OPEN_APP"
|
||||
|
||||
const val HOME_DATE_ALIGNMENT = "HOME_DATE_ALIGNMENT"
|
||||
const val HOME_TIME_ALIGNMENT = "HOME_TIME_ALIGNMENT"
|
||||
const val HOME_APP_ALIGNMENT = "HOME_APP_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_MANAGER = "android.app.StatusBarManager"
|
||||
const val NOTIFICATION_METHOD = "expandNotificationsPanel"
|
||||
|
||||
const val QUICKSETTINGS_SERVICE = "statusbar"
|
||||
const val QUICKSETTINGS_MANAGER = "android.app.StatusBarManager"
|
||||
const val QUICKSETTINGS_METHOD = "expandSettingsPanel"
|
||||
|
||||
const val REQUEST_CODE_ENABLE_ADMIN = 123
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.github.droidworksstudio.launcher.accessibility
|
||||
|
||||
import android.accessibilityservice.AccessibilityService
|
||||
import android.accessibilityservice.AccessibilityServiceInfo
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import androidx.annotation.RequiresApi
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class MyAccessibilityService : AccessibilityService() {
|
||||
|
||||
private var info: AccessibilityServiceInfo = AccessibilityServiceInfo()
|
||||
|
||||
override fun onServiceConnected() {
|
||||
mInstance = WeakReference(this)
|
||||
|
||||
info.apply {
|
||||
eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED or AccessibilityEvent.TYPE_VIEW_FOCUSED
|
||||
|
||||
feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC
|
||||
|
||||
notificationTimeout = 100
|
||||
}
|
||||
|
||||
this.serviceInfo = info
|
||||
}
|
||||
|
||||
override fun onUnbind(intent: Intent?): Boolean {
|
||||
mInstance = WeakReference(null)
|
||||
|
||||
return super.onUnbind(intent)
|
||||
}
|
||||
|
||||
override fun onInterrupt() {}
|
||||
|
||||
override fun onAccessibilityEvent(event: AccessibilityEvent?) {}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.P)
|
||||
fun lockScreen(): Boolean = performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN)
|
||||
|
||||
companion object {
|
||||
private var mInstance: WeakReference<MyAccessibilityService> = WeakReference(null)
|
||||
fun instance(): MyAccessibilityService? {
|
||||
return mInstance.get()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.github.droidworksstudio.launcher.data
|
||||
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import com.github.droidworksstudio.launcher.data.dao.AppInfoDAO
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
|
||||
@Database(entities = [AppInfo::class], version = 1)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun appDao(): AppInfoDAO
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.github.droidworksstudio.launcher.data.dao
|
||||
|
||||
|
||||
import android.util.Log
|
||||
import androidx.room.*
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface AppInfoDAO {
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(app: AppInfo)
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insertAll(apps: List<AppInfo>)
|
||||
@Update
|
||||
suspend fun update(app: AppInfo)
|
||||
@Delete
|
||||
suspend fun delete(app: AppInfo)
|
||||
|
||||
@Query("SELECT * FROM app ORDER BY app_name ASC")
|
||||
fun getAllApps(): List<AppInfo>
|
||||
|
||||
@Query("SELECT * FROM app ORDER BY app_name ASC")
|
||||
fun getAllAppsFlow(): Flow<List<AppInfo>>
|
||||
|
||||
@Query("SELECT * FROM app WHERE is_hidden = 0 ORDER BY app_name ASC")
|
||||
fun getDrawAppsFlow(): Flow<List<AppInfo>>
|
||||
|
||||
@Query("SELECT * FROM app WHERE is_favorite = 1 ORDER BY app_order ASC, id ASC")
|
||||
fun getFavoriteAppsFlow(): Flow<List<AppInfo>>
|
||||
|
||||
@Query("SELECT * FROM app WHERE is_hidden = 1 ORDER BY id ASC")
|
||||
fun getHiddenAppsFlow(): Flow<List<AppInfo>>
|
||||
|
||||
@Query("SELECT * FROM app WHERE is_lock = 1 ORDER BY app_order ASC")
|
||||
fun getLockAppsFlow(): Flow<List<AppInfo>>
|
||||
|
||||
@Query("SELECT * FROM app WHERE app_name LIKE :query AND is_hidden = 0")
|
||||
fun searchApps(query: String?): Flow<List<AppInfo>>
|
||||
|
||||
@Update
|
||||
fun updateAppInfo(appInfo: AppInfo)
|
||||
|
||||
@Update
|
||||
suspend fun updateAppOrder(appInfo: List<AppInfo>)
|
||||
|
||||
@Transaction
|
||||
suspend fun updateAppName(appInfo: AppInfo, newAppName: String) {
|
||||
appInfo.appName = newAppName
|
||||
update(appInfo)
|
||||
Log.d("Tag", "${appInfo.appName} : Repo Order: ${appInfo.appOrder}")
|
||||
}
|
||||
|
||||
@Transaction
|
||||
suspend fun updateAppHidden(appInfo: AppInfo, appHidden: Boolean) {
|
||||
appInfo.hidden = appHidden
|
||||
update(appInfo)
|
||||
Log.d("Tag", "${appInfo.appName} : Repo Order: ${appInfo.hidden}")
|
||||
}
|
||||
|
||||
@Transaction
|
||||
suspend fun updateLockApp(appInfo: AppInfo, appLock: Boolean) {
|
||||
appInfo.lock = appLock
|
||||
update(appInfo)
|
||||
Log.d("Tag", "${appInfo.appName} : Repo Order: ${appInfo.lock}")
|
||||
}
|
||||
|
||||
@Query("SELECT MAX(`app_order`) FROM app")
|
||||
fun getMaxOrder(): Int
|
||||
|
||||
@Query("SELECT * FROM app WHERE is_favorite = 1")
|
||||
fun getFavoriteAppInfo(): List<AppInfo>
|
||||
|
||||
@Query("SELECT * FROM app WHERE package_name = :packageName")
|
||||
suspend fun getAppByPackageName(packageName: String): AppInfo?
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.github.droidworksstudio.launcher.data.entities
|
||||
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "app")
|
||||
data class AppInfo(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@field:ColumnInfo(name = "id")
|
||||
var id: Int = 0,
|
||||
|
||||
@field:ColumnInfo(name = "app_name")
|
||||
var appName: String,
|
||||
|
||||
@field:ColumnInfo(name = "package_name")
|
||||
var packageName: String,
|
||||
|
||||
@field:ColumnInfo(name = "is_favorite")
|
||||
var favorite: Boolean,
|
||||
|
||||
@field:ColumnInfo(name = "is_hidden")
|
||||
var hidden: Boolean,
|
||||
|
||||
@ColumnInfo(name = "is_lock")
|
||||
var lock: Boolean,
|
||||
|
||||
@ColumnInfo(name = "create_time")
|
||||
var createTime: String = "",
|
||||
|
||||
@ColumnInfo(name = "app_order")
|
||||
var appOrder: Int = -1
|
||||
)
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.github.droidworksstudio.launcher.di
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.room.Room
|
||||
import com.github.droidworksstudio.launcher.data.AppDatabase
|
||||
import com.github.droidworksstudio.launcher.data.dao.AppInfoDAO
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.BottomDialogHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
object DatabaseModule {
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideLocalDatabase(
|
||||
@ApplicationContext context: Context
|
||||
): AppDatabase =
|
||||
Room.databaseBuilder(
|
||||
context,
|
||||
AppDatabase::class.java,
|
||||
"app_database"
|
||||
).build()
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideAppDao(appDatabase: AppDatabase): AppInfoDAO = appDatabase.appDao()
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providePackageManager(@ApplicationContext context: Context): PackageManager {
|
||||
return context.packageManager
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providePreferenceHelper(@ApplicationContext context: Context): PreferenceHelper {
|
||||
return PreferenceHelper(context)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideContext(@ApplicationContext context: Context): Context {
|
||||
return context
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideAppHelper(): AppHelper {
|
||||
return AppHelper()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideBottomDialogHelper(): BottomDialogHelper {
|
||||
return BottomDialogHelper()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
package com.github.droidworksstudio.launcher.helper
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.SearchManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.AlarmClock
|
||||
import android.provider.CalendarContract
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowInsets
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.LinearLayoutCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.github.droidworksstudio.launcher.Constants
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.accessibility.MyAccessibilityService
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.ui.activities.FakeHomeActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
class AppHelper @Inject constructor() {
|
||||
|
||||
fun resetDefaultLauncher(context: Context) {
|
||||
try {
|
||||
val packageManager = context.packageManager
|
||||
val componentName = ComponentName(context, FakeHomeActivity::class.java)
|
||||
packageManager.setComponentEnabledSetting(
|
||||
componentName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
val selector = Intent(Intent.ACTION_MAIN)
|
||||
selector.addCategory(Intent.CATEGORY_HOME)
|
||||
context.startActivity(selector)
|
||||
packageManager.setComponentEnabledSetting(
|
||||
componentName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant", "PrivateApi")
|
||||
fun expandNotificationDrawer(context: Context) {
|
||||
try {
|
||||
val statusBarService = context.getSystemService(Constants.NOTIFICATION_SERVICE)
|
||||
val statusBarManager = Class.forName(Constants.NOTIFICATION_MANAGER)
|
||||
val method = statusBarManager.getMethod(Constants.NOTIFICATION_METHOD)
|
||||
method.invoke(statusBarService)
|
||||
} catch (exception: Exception) {
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
// initActionService(context)?.openNotifications()
|
||||
// }
|
||||
exception.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant", "PrivateApi")
|
||||
private fun expandQuickSettings(context: Context) {
|
||||
try {
|
||||
val statusBarService = context.getSystemService(Constants.QUICKSETTINGS_SERVICE)
|
||||
val statusBarManager = Class.forName(Constants.QUICKSETTINGS_MANAGER)
|
||||
val method = statusBarManager.getMethod(Constants.QUICKSETTINGS_METHOD)
|
||||
method.invoke(statusBarService)
|
||||
} catch (exception: Exception) {
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
// initActionService(context)?.openQuickSettings()
|
||||
// }
|
||||
exception.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun searchView(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_WEB_SEARCH)
|
||||
intent.putExtra(SearchManager.QUERY, "")
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun dayNightMod(context: Context, view: View) {
|
||||
when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
|
||||
Configuration.UI_MODE_NIGHT_YES -> {
|
||||
view.setBackgroundColor(context.resources.getColor(R.color.whiteTrans25))
|
||||
}
|
||||
|
||||
Configuration.UI_MODE_NIGHT_NO -> {
|
||||
view.setBackgroundColor(context.resources.getColor(R.color.blackTrans50))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateUI(view: View, gravity: Int, selectColor: Int, textSize: Float, isVisible: Boolean) {
|
||||
val layoutParams = view.layoutParams as LinearLayoutCompat.LayoutParams
|
||||
layoutParams.gravity = gravity
|
||||
view.layoutParams = layoutParams
|
||||
|
||||
if (view is TextView) {
|
||||
view.setTextColor(selectColor)
|
||||
view.textSize = textSize
|
||||
view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
|
||||
view.isClickable = if (isVisible) view.isClickable else !view.isClickable
|
||||
}
|
||||
}
|
||||
|
||||
fun launchApp(context: Context, appInfo: AppInfo) {
|
||||
val intent = context.packageManager.getLaunchIntentForPackage(appInfo.packageName)
|
||||
if (intent != null) {
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
showToast(context, "Failed to open the application")
|
||||
}
|
||||
}
|
||||
fun launchClock(context: Context) {
|
||||
try {
|
||||
val intent = Intent(AlarmClock.ACTION_SHOW_ALARMS)
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Log.e("launchClock", "Error launching clock app: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun launchCalendar(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.data = CalendarContract.CONTENT_URI
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
val pickerIntent = Intent(Intent.ACTION_MAIN)
|
||||
pickerIntent.addCategory(Intent.CATEGORY_APP_CALENDAR)
|
||||
try {
|
||||
context.startActivity(pickerIntent)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun unInstallApp(context: Context, appInfo: AppInfo) {
|
||||
val intent = Intent(Intent.ACTION_DELETE)
|
||||
intent.data = Uri.parse("package:${appInfo.packageName}")
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun appInfo(context: Context, appInfo: AppInfo) {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||
intent.data = Uri.fromParts("package", appInfo.packageName, null)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun gravityToString(gravity: Int): String? {
|
||||
return when (gravity) {
|
||||
Gravity.CENTER -> "CENTER"
|
||||
Gravity.START -> "LEFT"
|
||||
Gravity.END -> "RIGHT"
|
||||
Gravity.TOP -> "TOP"
|
||||
Gravity.BOTTOM -> "BOTTOM"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun getGravityFromSelectedItem(selectedItem: String): Int {
|
||||
return when (selectedItem) {
|
||||
"Left" -> Gravity.START
|
||||
"Center" -> Gravity.CENTER
|
||||
"Right" -> Gravity.END
|
||||
else -> Gravity.START
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun showToast(context: Context,message: String) {
|
||||
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
fun showStatusBar(window: Window) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window.insetsController?.show(WindowInsets.Type.statusBars())
|
||||
} else
|
||||
@Suppress("DEPRECATION", "InlinedApi")
|
||||
window.decorView.apply {
|
||||
systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
}
|
||||
}
|
||||
|
||||
fun hideStatusBar(window: Window) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
||||
window.insetsController?.hide(WindowInsets.Type.statusBars())
|
||||
else {
|
||||
@Suppress("DEPRECATION")
|
||||
window.decorView.apply {
|
||||
systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE or View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showSoftKeyboard(context: Context, view: View) {
|
||||
if (view.requestFocus()) {
|
||||
val inputMethodManager: InputMethodManager =
|
||||
context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
|
||||
}
|
||||
}
|
||||
|
||||
fun hideKeyboard(context: Context, view: View) {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
}
|
||||
|
||||
fun View.hideKeyboard() {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(this.windowToken, 0)
|
||||
}
|
||||
fun enableAppAsAccessibilityService(context: Context, accessibilityState: Boolean) {
|
||||
|
||||
val myAccessibilityService = MyAccessibilityService.instance()
|
||||
|
||||
val state: String = if (myAccessibilityService != null) {
|
||||
context.getString(R.string.accessibility_settings_disable)
|
||||
}else{
|
||||
context.getString(R.string.accessibility_settings_enable)
|
||||
}
|
||||
|
||||
val builder = MaterialAlertDialogBuilder(context)
|
||||
|
||||
builder.setTitle(R.string.accessibility_settings_title)
|
||||
builder.setMessage(R.string.accessibility_service_desc)
|
||||
builder.setPositiveButton(state) { _, _ ->
|
||||
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.github.droidworksstudio.launcher.helper
|
||||
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.WindowManager
|
||||
import javax.inject.Inject
|
||||
|
||||
class BottomDialogHelper @Inject constructor() {
|
||||
|
||||
fun setupDialogStyle(dialog: Dialog?) {
|
||||
|
||||
val window = dialog?.window
|
||||
if (window != null) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
||||
window.statusBarColor = Color.TRANSPARENT
|
||||
}
|
||||
}
|
||||
|
||||
fun getColorText(color: Int): SpannableString {
|
||||
val colorText = "#${Integer.toHexString(color)}"
|
||||
val spannableString = SpannableString(colorText)
|
||||
spannableString.setSpan(
|
||||
ForegroundColorSpan(color),
|
||||
0,
|
||||
colorText.length,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
return spannableString
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.github.droidworksstudio.launcher.helper
|
||||
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import javax.inject.Inject
|
||||
|
||||
class FingerprintHelper @Inject constructor(private val fragment: Fragment) {
|
||||
|
||||
private lateinit var callback: Callback
|
||||
|
||||
interface Callback {
|
||||
fun onAuthenticationSucceeded(appInfo: AppInfo)
|
||||
fun onAuthenticationFailed()
|
||||
fun onAuthenticationError(errorCode: Int, errorMessage: CharSequence?)
|
||||
}
|
||||
|
||||
fun startFingerprintAuth(appInfo: AppInfo, callback: Callback) {
|
||||
this.callback = callback
|
||||
|
||||
val authenticationCallback = object : BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||
callback.onAuthenticationSucceeded(appInfo)
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
callback.onAuthenticationFailed()
|
||||
}
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errorMessage: CharSequence) {
|
||||
callback.onAuthenticationError(errorCode, errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
val executor = ContextCompat.getMainExecutor(fragment.requireContext())
|
||||
val biometricPrompt = BiometricPrompt(fragment, executor, authenticationCallback)
|
||||
|
||||
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(fragment.getString(R.string.authentication_title))
|
||||
.setNegativeButtonText(fragment.getString(R.string.authentication_cancel))
|
||||
.build()
|
||||
|
||||
val canAuthenticate = BiometricManager.from(fragment.requireContext())
|
||||
.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
if (canAuthenticate == BiometricManager.BIOMETRIC_SUCCESS) {
|
||||
biometricPrompt.authenticate(promptInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.github.droidworksstudio.launcher.helper
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.view.Gravity
|
||||
import com.github.droidworksstudio.launcher.Constants
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
|
||||
class PreferenceHelper @Inject constructor(@ApplicationContext context: Context) {
|
||||
|
||||
private val prefs: SharedPreferences = context.getSharedPreferences(Constants.PREFS_FILENAME, 0)
|
||||
|
||||
var firstLaunch: Boolean
|
||||
get() = prefs.getBoolean(Constants.FIRST_LAUNCH, true)
|
||||
set(value) = prefs.edit().putBoolean(Constants.FIRST_LAUNCH, value).apply()
|
||||
|
||||
var showStatusBar: Boolean
|
||||
get() = prefs.getBoolean(Constants.SHOW_STATUS_BAR, true)
|
||||
set(value) = prefs.edit().putBoolean(Constants.SHOW_STATUS_BAR, value).apply()
|
||||
var showTime: Boolean
|
||||
get() = prefs.getBoolean(Constants.SHOW_TIME, true)
|
||||
set(value) = prefs.edit().putBoolean(Constants.SHOW_TIME, value).apply()
|
||||
|
||||
var showDate: Boolean
|
||||
get() = prefs.getBoolean(Constants.SHOW_DATE, true)
|
||||
set(value) = prefs.edit().putBoolean(Constants.SHOW_DATE, value).apply()
|
||||
|
||||
var showBattery: Boolean
|
||||
get() = prefs.getBoolean(Constants.SHOW_BATTERY, true)
|
||||
set(value) = prefs.edit().putBoolean(Constants.SHOW_BATTERY, value).apply()
|
||||
|
||||
var showDailyWord: Boolean
|
||||
get() = prefs.getBoolean(Constants.SHOW_DAILY_WORD, true)
|
||||
set(value) = prefs.edit().putBoolean(Constants.SHOW_DAILY_WORD, value).apply()
|
||||
|
||||
var dateColor: Int
|
||||
get() = prefs.getInt(Constants.DATE_COLOR, 0xFFFFFFFF.toInt())
|
||||
set(value) = prefs.edit().putInt(Constants.DATE_COLOR, value).apply()
|
||||
|
||||
var timeColor: Int
|
||||
get() = prefs.getInt(Constants.TIME_COLOR, 0xFFFFFFFF.toInt())
|
||||
set(value) = prefs.edit().putInt(Constants.TIME_COLOR, value).apply()
|
||||
|
||||
var batteryColor: Int
|
||||
get() = prefs.getInt(Constants.BATTERY_COLOR, 0xFFFFFFFF.toInt())
|
||||
set(value) = prefs.edit().putInt(Constants.BATTERY_COLOR, value).apply()
|
||||
var dailyWordColor: Int
|
||||
get() = prefs.getInt(Constants.DAILY_WORD_COLOR, 0xFFFFFFFF.toInt())
|
||||
set(value) = prefs.edit().putInt(Constants.DAILY_WORD_COLOR, value).apply()
|
||||
|
||||
var appColor: Int
|
||||
get() = prefs.getInt(Constants.APP_COLOR, 0xFFFFFFFF.toInt())
|
||||
set(value) = prefs.edit().putInt(Constants.APP_COLOR, value).apply()
|
||||
|
||||
var showAppIcon: Boolean
|
||||
get() = prefs.getBoolean(Constants.SHOW_APP_ICON, true)
|
||||
set(value) = prefs.edit().putBoolean(Constants.SHOW_APP_ICON, value).apply()
|
||||
|
||||
var automaticKeyboard: Boolean
|
||||
get() = prefs.getBoolean(Constants.AUTOMATIC_KEYBOARD, true)
|
||||
set(value) = prefs.edit().putBoolean(Constants.AUTOMATIC_KEYBOARD, value).apply()
|
||||
|
||||
var automaticOpenApp: Boolean
|
||||
get() = prefs.getBoolean(Constants.AUTOMATIC_OPEN_APP, false)
|
||||
set(value) = prefs.edit().putBoolean(Constants.AUTOMATIC_OPEN_APP, value).apply()
|
||||
|
||||
var homeAppAlignment: Int
|
||||
get() = prefs.getInt(Constants.HOME_APP_ALIGNMENT, Gravity.START)
|
||||
set(value) = prefs.edit().putInt(Constants.HOME_APP_ALIGNMENT, value).apply()
|
||||
|
||||
var homeDateAlignment: Int
|
||||
get() = prefs.getInt(Constants.HOME_DATE_ALIGNMENT, Gravity.START)
|
||||
set(value) = prefs.edit().putInt(Constants.HOME_DATE_ALIGNMENT, value).apply()
|
||||
|
||||
var homeTimeAlignment: Int
|
||||
get() = prefs.getInt(Constants.HOME_TIME_ALIGNMENT, Gravity.START)
|
||||
set(value) = prefs.edit().putInt(Constants.HOME_TIME_ALIGNMENT, value).apply()
|
||||
|
||||
var homeDailyWordAlignment: Int
|
||||
get() = prefs.getInt(Constants.HOME_DAILY_WORD_ALIGNMENT, Gravity.START)
|
||||
set(value) = prefs.edit().putInt(Constants.HOME_DAILY_WORD_ALIGNMENT,value).apply()
|
||||
|
||||
var dateTextSize: Float
|
||||
get() = prefs.getFloat(Constants.DATE_TEXT_SIZE, 32f)
|
||||
set(value) = prefs.edit().putFloat(Constants.DATE_TEXT_SIZE, value).apply()
|
||||
|
||||
var timeTextSize: Float
|
||||
get() = prefs.getFloat(Constants.TIME_TEXT_SIZE, 48f)
|
||||
set(value) = prefs.edit().putFloat(Constants.TIME_TEXT_SIZE, value).apply()
|
||||
|
||||
var appTextSize: Float
|
||||
get() = prefs.getFloat(Constants.APP_TEXT_SIZE, 24f)
|
||||
set(value) = prefs.edit().putFloat(Constants.APP_TEXT_SIZE, value).apply()
|
||||
|
||||
var tapLockScreen: Boolean
|
||||
get() = prefs.getBoolean(Constants.DOUBLE_TAP_LOCK, false)
|
||||
set(value) = prefs.edit().putBoolean(Constants.DOUBLE_TAP_LOCK, value).apply()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.github.droidworksstudio.launcher.listener
|
||||
|
||||
import android.app.admin.DeviceAdminReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
|
||||
class DeviceAdmin : DeviceAdminReceiver() {
|
||||
override fun onEnabled(context: Context, intent: Intent) {
|
||||
super.onEnabled(context, intent)
|
||||
Toast.makeText(context, "Enabled", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onDisabled(context: Context, intent: Intent) {
|
||||
super.onDisabled(context, intent)
|
||||
Toast.makeText(context, "Disabled", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.github.droidworksstudio.launcher.listener
|
||||
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
|
||||
class OnItemClickedListener {
|
||||
|
||||
interface OnAppsClickedListener{
|
||||
fun onAppClicked(appInfo: AppInfo)
|
||||
}
|
||||
|
||||
interface OnAppLongClickedListener{
|
||||
fun onAppLongClicked(appInfo: AppInfo)
|
||||
}
|
||||
|
||||
interface BottomSheetDismissListener {
|
||||
fun onBottomSheetDismissed()
|
||||
}
|
||||
|
||||
interface OnAppStateClickListener{
|
||||
fun onAppStateClicked(appInfo: AppInfo)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.github.droidworksstudio.launcher.listener
|
||||
|
||||
class OnItemMoveListener {
|
||||
interface OnItemActionListener {
|
||||
fun onViewMoved(oldPosition: Int, newPosition: Int): Boolean
|
||||
fun onViewSwiped(position: Int)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.github.droidworksstudio.launcher.listener
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal open class OnSwipeTouchListener(c: Context?) : View.OnTouchListener {
|
||||
private var longPressOn = false
|
||||
|
||||
private val gestureDetector: GestureDetector
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
|
||||
if (motionEvent.action == MotionEvent.ACTION_UP)
|
||||
longPressOn = false
|
||||
return gestureDetector.onTouchEvent(motionEvent)
|
||||
}
|
||||
|
||||
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
|
||||
private val swipeThreshold: Int = 100
|
||||
private val swipeVelocityThreshold: Int = 100
|
||||
|
||||
override fun onDown(e: MotionEvent): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||
onDoubleClick()
|
||||
return super.onDoubleTap(e)
|
||||
}
|
||||
|
||||
override fun onLongPress(e: MotionEvent) {
|
||||
longPressOn = true
|
||||
val scope = CoroutineScope(Dispatchers.Main)
|
||||
scope.launch {
|
||||
if (longPressOn) {
|
||||
onLongClick()
|
||||
}
|
||||
}
|
||||
super.onLongPress(e)
|
||||
}
|
||||
|
||||
override fun onFling(
|
||||
e1: MotionEvent?,
|
||||
event1: MotionEvent,
|
||||
velocityX: Float,
|
||||
velocityY: Float
|
||||
): Boolean {
|
||||
try {
|
||||
val diffY = event1.y - event1.y
|
||||
val diffX = event1.x - event1.x
|
||||
if (kotlin.math.abs(diffX) > kotlin.math.abs(diffY)) {
|
||||
if (kotlin.math.abs(diffX) > swipeThreshold && kotlin.math.abs(velocityX) > swipeVelocityThreshold) {
|
||||
if (diffX > 0) onSwipeRight() else onSwipeLeft()
|
||||
}
|
||||
} else {
|
||||
if (kotlin.math.abs(diffY) > swipeThreshold && kotlin.math.abs(velocityY) > swipeVelocityThreshold) {
|
||||
if (diffY < 0) onSwipeUp() else onSwipeDown()
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
exception.printStackTrace()
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
open fun onSwipeRight() {}
|
||||
open fun onSwipeLeft() {}
|
||||
open fun onSwipeUp() {}
|
||||
open fun onSwipeDown() {}
|
||||
open fun onLongClick() {}
|
||||
open fun onDoubleClick() {}
|
||||
|
||||
init {
|
||||
gestureDetector = GestureDetector(c, GestureListener())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.github.droidworksstudio.launcher.listener
|
||||
|
||||
interface ScrollEventListener {
|
||||
fun onTopReached()
|
||||
fun onBottomReached()
|
||||
fun onScroll(isTopReached: Boolean, isBottomReached: Boolean)
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package com.github.droidworksstudio.launcher.repository
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.UserManager
|
||||
import android.util.Log
|
||||
import com.github.droidworksstudio.launcher.Constants
|
||||
import com.github.droidworksstudio.launcher.data.dao.AppInfoDAO
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class AppInfoRepository @Inject constructor(
|
||||
private val appDao: AppInfoDAO
|
||||
) {
|
||||
|
||||
@Inject
|
||||
lateinit var packageManager: PackageManager
|
||||
|
||||
fun getDrawApps(): Flow<List<AppInfo>> {
|
||||
return appDao.getDrawAppsFlow()
|
||||
}
|
||||
|
||||
fun getFavoriteApps(): Flow<List<AppInfo>> {
|
||||
return appDao.getFavoriteAppsFlow()
|
||||
}
|
||||
|
||||
fun getHiddenApps(): Flow<List<AppInfo>> {
|
||||
return appDao.getHiddenAppsFlow()
|
||||
}
|
||||
|
||||
suspend fun updateInfo(appInfo: AppInfo) {
|
||||
appDao.update(appInfo)
|
||||
}
|
||||
|
||||
suspend fun updateAppOrder(appInfoList: List<AppInfo>) {
|
||||
withContext(Dispatchers.IO) {
|
||||
appDao.updateAppOrder(appInfoList)
|
||||
}
|
||||
}
|
||||
|
||||
fun searchNote(query: String?): Flow<List<AppInfo>> {
|
||||
return appDao.searchApps(query)
|
||||
}
|
||||
|
||||
suspend fun updateFavoriteAppInfo(appInfo: AppInfo) = withContext(Dispatchers.IO) {
|
||||
|
||||
if (appInfo.favorite) {
|
||||
val maxOrder = appDao.getMaxOrder()
|
||||
val newOrder = maxOrder + 1
|
||||
appInfo.appOrder = newOrder
|
||||
appDao.updateAppInfo(appInfo)
|
||||
Log.d("Tag", "${appInfo.appName} : DAO Order: ${appInfo.appOrder}")
|
||||
Log.d("Tag", "${appInfo.appName} : DAO Favorite: ${appInfo.favorite}")
|
||||
} else {
|
||||
appInfo.appOrder = -1
|
||||
appDao.updateAppInfo(appInfo)
|
||||
Log.d("Tag", "${appInfo.appName} : DAO Order Remove: ${appInfo.appOrder}")
|
||||
Log.d("Tag", "${appInfo.appName} : DAO Favorite Remove: ${appInfo.favorite}")
|
||||
}
|
||||
|
||||
val favoriteAppInfos = appDao.getFavoriteAppInfo().sortedBy { it.appOrder }
|
||||
|
||||
for ((index, info) in favoriteAppInfos.withIndex()) {
|
||||
info.appOrder = index
|
||||
appDao.updateAppInfo(info)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateAppName(appInfo: AppInfo, newAppName: String) = withContext(Dispatchers.IO) {
|
||||
appInfo.appName = newAppName
|
||||
appDao.updateAppName(appInfo, newAppName)
|
||||
}
|
||||
|
||||
suspend fun updateAppHidden(appInfo: AppInfo, appHidden: Boolean) =
|
||||
withContext(Dispatchers.IO) {
|
||||
appInfo.hidden = appHidden
|
||||
appDao.updateAppHidden(appInfo, appHidden)
|
||||
}
|
||||
|
||||
suspend fun updateAppLock(appInfo: AppInfo, appLock: Boolean) = withContext(Dispatchers.IO) {
|
||||
appInfo.lock = appLock
|
||||
appDao.updateLockApp(appInfo, appLock)
|
||||
}
|
||||
|
||||
private suspend fun getInstalledPackages(): Set<String> = withContext(Dispatchers.IO) {
|
||||
|
||||
val packages = HashSet<String>()
|
||||
val apps = packageManager.getInstalledApplications(PackageManager.GET_META_DATA)
|
||||
for (app in apps) {
|
||||
packages.add(app.packageName)
|
||||
}
|
||||
packages
|
||||
}
|
||||
|
||||
suspend fun initInstalledAppInfo(context: Context): List<AppInfo> = withContext(Dispatchers.IO) {
|
||||
val appList: MutableList<AppInfo> = mutableListOf()
|
||||
|
||||
val allApps = appDao.getAllAppsFlow().firstOrNull()
|
||||
|
||||
val existingPackageNames = allApps?.map { it.packageName } ?: emptyList()
|
||||
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val launcherApps =
|
||||
context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
|
||||
val excludedPackageName = Constants.PACKAGE_NAME
|
||||
|
||||
val newAppList: List<AppInfo> = userManager.userProfiles
|
||||
.flatMap { profile ->
|
||||
launcherApps.getActivityList(null, profile)
|
||||
.mapNotNull { app ->
|
||||
val packageName = app.applicationInfo.packageName
|
||||
if (packageName !in existingPackageNames && packageName != excludedPackageName) {
|
||||
AppInfo(
|
||||
appName = app.label.toString(),
|
||||
packageName = packageName,
|
||||
favorite = false,
|
||||
hidden = false,
|
||||
lock = false
|
||||
)
|
||||
} else {
|
||||
val existingApp = getAppByPackageName(packageName)
|
||||
existingApp?.let { appList.add(it) }
|
||||
existingApp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appDao.insertAll(newAppList.sortedBy { it.appName })
|
||||
Log.d("Tag", "State: ${newAppList.sortedBy { it.appName }}")
|
||||
|
||||
val deletedApps = allApps?.filter { it.packageName !in existingPackageNames }
|
||||
deletedApps?.forEach { appDao.delete(it) }
|
||||
|
||||
appList.sortBy { it.appName }
|
||||
appList
|
||||
}
|
||||
|
||||
suspend fun compareInstalledApp(): List<AppInfo> = withContext(Dispatchers.IO) {
|
||||
val installedPackages = getInstalledPackages()
|
||||
val uninstalledApps = mutableListOf<AppInfo>()
|
||||
|
||||
val allApps = appDao.getAllApps()
|
||||
|
||||
val newApps = mutableListOf<AppInfo>()
|
||||
|
||||
for (app in allApps) {
|
||||
val packageName = app.packageName
|
||||
if (!installedPackages.contains(packageName)) {
|
||||
appDao.delete(app)
|
||||
uninstalledApps.add(app)
|
||||
}
|
||||
}
|
||||
|
||||
val newPackageNames = installedPackages.filterNot { packageName ->
|
||||
allApps.any { app -> app.packageName == packageName }
|
||||
}
|
||||
|
||||
for (packageName in newPackageNames) {
|
||||
val app = appDao.getAppByPackageName(packageName)
|
||||
app?.let {
|
||||
newApps.add(app)
|
||||
}
|
||||
}
|
||||
|
||||
appDao.insertAll(newApps)
|
||||
uninstalledApps
|
||||
}
|
||||
|
||||
private suspend fun getAppByPackageName(packageName: String): AppInfo? {
|
||||
return appDao.getAppByPackageName(packageName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.github.droidworksstudio.launcher.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
|
||||
class FakeHomeActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_fake_home)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.github.droidworksstudio.launcher.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
|
||||
class LauncherActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_mock)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.github.droidworksstudio.launcher.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.navigateUp
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.databinding.ActivityMainBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.ui.drawer.DrawFragment
|
||||
import com.github.droidworksstudio.launcher.ui.viewpager.ViewPagerAdapter
|
||||
import com.github.droidworksstudio.launcher.viewmodel.AppViewModel
|
||||
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
private val viewModel: AppViewModel by viewModels()
|
||||
private val preferenceViewModel: PreferenceViewModel by viewModels()
|
||||
|
||||
private lateinit var navController: NavController
|
||||
|
||||
@Inject
|
||||
lateinit var preferenceHelper: PreferenceHelper
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
private val viewPagerAdapter: ViewPagerAdapter by lazy { ViewPagerAdapter(supportFragmentManager, lifecycle) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
initializeDependencies()
|
||||
setupNavController()
|
||||
setupViewPagerAdapter()
|
||||
}
|
||||
|
||||
private fun initializeDependencies() {
|
||||
|
||||
preferenceViewModel.setShowStatusBar(preferenceHelper.showStatusBar)
|
||||
preferenceViewModel.setFirstLaunch(preferenceHelper.firstLaunch)
|
||||
|
||||
window.addFlags(FLAG_LAYOUT_NO_LIMITS)
|
||||
|
||||
}
|
||||
|
||||
private fun setupDataBase() {
|
||||
lifecycleScope.launch {
|
||||
viewModel.initializeInstalledAppInfo(this@MainActivity)
|
||||
}
|
||||
//GlobalScope.launch { }
|
||||
preferenceHelper.firstLaunch = false
|
||||
}
|
||||
|
||||
private fun observeUI() {
|
||||
preferenceViewModel.setShowStatusBar(preferenceHelper.showStatusBar)
|
||||
preferenceViewModel.showStatusBarLiveData.observe(this) {
|
||||
if (it) appHelper.showStatusBar(this.window)
|
||||
else appHelper.hideStatusBar(this.window) }
|
||||
}
|
||||
|
||||
private fun setupNavController() {
|
||||
navController = findNavController(R.id.nav_host_fragment_content_main)
|
||||
appBarConfiguration = AppBarConfiguration(navController.graph)
|
||||
//setupActionBarWithNavController(navController, appBarConfiguration)
|
||||
}
|
||||
|
||||
private fun setupViewPagerAdapter() {
|
||||
binding.pager.apply {
|
||||
adapter = viewPagerAdapter
|
||||
offscreenPageLimit = 1
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_main, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_settings -> true
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
val navController = findNavController(R.id.nav_host_fragment_content_main)
|
||||
return navController.navigateUp(appBarConfiguration)
|
||||
|| super.onSupportNavigateUp()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setupDataBase()
|
||||
observeUI()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
backToHomeScreen()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onUserLeaveHint() {
|
||||
backToHomeScreen()
|
||||
super.onUserLeaveHint()
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onBackPressed() {
|
||||
val currentItem = binding.pager.currentItem
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.nav_host_fragment_content_main) as NavHostFragment
|
||||
val currentFragment = navHostFragment.childFragmentManager.fragments[0]
|
||||
|
||||
if (currentFragment is DrawFragment) {
|
||||
@Suppress("DEPRECATION")
|
||||
super.onBackPressed()
|
||||
} else {
|
||||
binding.pager.currentItem = currentItem - 1
|
||||
}
|
||||
}
|
||||
|
||||
private fun backToHomeScreen() {
|
||||
if (navController.currentDestination?.id != R.id.HomeFragment)
|
||||
navController.popBackStack(R.id.HomeFragment, false)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.github.droidworksstudio.launcher.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.navigateUp
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.databinding.ActivitySettingsBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivitySettingsBinding
|
||||
|
||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
private lateinit var navController: NavController
|
||||
|
||||
private val preferenceViewModel: PreferenceViewModel by viewModels()
|
||||
|
||||
@Inject
|
||||
lateinit var preferenceHelper: PreferenceHelper
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
navController = findNavController(R.id.nav_host_fragment_content_settings)
|
||||
appBarConfiguration = AppBarConfiguration(navController.graph)
|
||||
|
||||
initializeDependencies()
|
||||
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
val navController = findNavController(R.id.nav_host_fragment_content_settings)
|
||||
return navController.navigateUp(appBarConfiguration)
|
||||
|| super.onSupportNavigateUp()
|
||||
}
|
||||
|
||||
private fun initializeDependencies() {
|
||||
|
||||
preferenceViewModel.setShowStatusBar(preferenceHelper.showStatusBar)
|
||||
}
|
||||
private fun observeUI(){
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
||||
|
||||
preferenceViewModel.setShowStatusBar(preferenceHelper.showStatusBar)
|
||||
preferenceViewModel.showStatusBarLiveData.observe(this) {
|
||||
if (it) appHelper.showStatusBar(this.window)
|
||||
else appHelper.hideStatusBar(this.window) }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
observeUI()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.github.droidworksstudio.launcher.ui.bottomsheetdialog
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.databinding.BottomsheetdialogAlignmentSettingsBinding
|
||||
import com.github.droidworksstudio.launcher.databinding.BottomsheetdialogColorSettingsBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.BottomDialogHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AlignmentBottomSheetDialogFragment(context: Context) : BottomSheetDialogFragment() {
|
||||
|
||||
private var _binding: BottomsheetdialogAlignmentSettingsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
@Inject
|
||||
lateinit var preferenceHelper: PreferenceHelper
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
@Inject
|
||||
lateinit var bottomDialogHelper: BottomDialogHelper
|
||||
|
||||
private val preferenceViewModel: PreferenceViewModel by viewModels()
|
||||
|
||||
private var selectedAlignment: String = ""
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = BottomsheetdialogAlignmentSettingsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
initView()
|
||||
observeClickListener()
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
bottomDialogHelper.setupDialogStyle(dialog)
|
||||
|
||||
binding.selectDateTextSize.apply {
|
||||
text = appHelper.gravityToString(preferenceHelper.homeDateAlignment)
|
||||
}
|
||||
|
||||
binding.selectTimeTextSize.apply {
|
||||
text = appHelper.gravityToString(preferenceHelper.homeTimeAlignment)
|
||||
}
|
||||
|
||||
binding.selectAppTextSize.apply {
|
||||
text = appHelper.gravityToString(preferenceHelper.homeAppAlignment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeClickListener(){
|
||||
binding.bottomAlignmentDateView.setOnClickListener {
|
||||
selectedAlignment = REQUEST_KEY_DATE_ALIGNMENT
|
||||
showListDialog(selectedAlignment)
|
||||
}
|
||||
|
||||
binding.bottomAlignmentTimeView.setOnClickListener {
|
||||
selectedAlignment = REQUEST_KEY_TIME_ALIGNMENT
|
||||
showListDialog(selectedAlignment)
|
||||
}
|
||||
|
||||
binding.bottomAlignmentAppView.setOnClickListener {
|
||||
selectedAlignment = REQUEST_KEY_APP_ALIGNMENT
|
||||
showListDialog(selectedAlignment)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun showListDialog(selectedAlignment: String) {
|
||||
val items = resources.getStringArray(R.array.alignment_options)
|
||||
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
|
||||
dialog.setTitle(DIALOG_TITLE)
|
||||
dialog.setItems(items) { _, which ->
|
||||
val selectedItem = items[which]
|
||||
val gravity = appHelper.getGravityFromSelectedItem(selectedItem)
|
||||
|
||||
when (selectedAlignment) {
|
||||
REQUEST_KEY_APP_ALIGNMENT -> {
|
||||
setAlignment(
|
||||
selectedAlignment,
|
||||
selectedItem,
|
||||
gravity,
|
||||
binding.selectAppTextSize
|
||||
)
|
||||
}
|
||||
|
||||
REQUEST_KEY_TIME_ALIGNMENT -> {
|
||||
setAlignment(
|
||||
selectedAlignment,
|
||||
selectedItem,
|
||||
gravity,
|
||||
binding.selectTimeTextSize
|
||||
)
|
||||
}
|
||||
|
||||
REQUEST_KEY_DATE_ALIGNMENT -> {
|
||||
setAlignment(
|
||||
selectedAlignment,
|
||||
selectedItem,
|
||||
gravity,
|
||||
binding.selectDateTextSize
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
private fun setAlignment(
|
||||
alignmentType: String,
|
||||
selectedItem: String,
|
||||
gravity: Int,
|
||||
textView: TextView
|
||||
) {
|
||||
val alignmentPreference: (Int) -> Unit
|
||||
val alignmentGetter: () -> Int
|
||||
|
||||
when (alignmentType) {
|
||||
REQUEST_KEY_APP_ALIGNMENT -> {
|
||||
alignmentPreference = { preferenceViewModel.setHomeAppAlignment(it) }
|
||||
alignmentGetter = { preferenceHelper.homeAppAlignment }
|
||||
}
|
||||
|
||||
REQUEST_KEY_TIME_ALIGNMENT -> {
|
||||
alignmentPreference = { preferenceViewModel.setHomeTimeAppAlignment(it) }
|
||||
alignmentGetter = { preferenceHelper.homeTimeAlignment }
|
||||
}
|
||||
|
||||
REQUEST_KEY_DATE_ALIGNMENT -> {
|
||||
alignmentPreference = { preferenceViewModel.setHomeDateAlignment(it) }
|
||||
alignmentGetter = { preferenceHelper.homeDateAlignment }
|
||||
}
|
||||
|
||||
else -> return
|
||||
}
|
||||
|
||||
alignmentPreference(gravity)
|
||||
textView.text = appHelper.gravityToString(alignmentGetter())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DIALOG_TITLE = "Select Alignment"
|
||||
private const val REQUEST_KEY_DATE_ALIGNMENT = "REQUEST_KEY_DATE_ALIGNMENT"
|
||||
private const val REQUEST_KEY_TIME_ALIGNMENT = "REQUEST_KEY_TIME_ALIGNMENT"
|
||||
private const val REQUEST_KEY_APP_ALIGNMENT = "REQUEST_KEY_APP_ALIGNMENT"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.github.droidworksstudio.launcher.ui.bottomsheetdialog
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.BottomsheetDialogBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.BottomDialogHelper
|
||||
import com.github.droidworksstudio.launcher.helper.FingerprintHelper
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
import com.github.droidworksstudio.launcher.viewmodel.AppViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AppInfoBottomSheetFragment(private val appInfo: AppInfo) : BottomSheetDialogFragment(),
|
||||
FingerprintHelper.Callback {
|
||||
|
||||
private var _binding: BottomsheetDialogBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val viewModel: AppViewModel by viewModels()
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
@Inject
|
||||
lateinit var bottomDialogHelper: BottomDialogHelper
|
||||
|
||||
@Inject
|
||||
lateinit var fingerHelper: FingerprintHelper
|
||||
|
||||
private var appStateClickListener: OnItemClickedListener.OnAppStateClickListener? = null
|
||||
|
||||
private var dismissListener: OnItemClickedListener.BottomSheetDismissListener? = null
|
||||
|
||||
fun setOnAppStateClickListener(listener: OnItemClickedListener.OnAppStateClickListener) {
|
||||
appStateClickListener = listener
|
||||
}
|
||||
|
||||
fun setOnBottomSheetDismissedListener(listener: OnItemClickedListener.BottomSheetDismissListener) {
|
||||
dismissListener = listener
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = BottomsheetDialogBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
initView()
|
||||
observeClickListener()
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
bottomDialogHelper.setupDialogStyle(dialog)
|
||||
|
||||
binding.run {
|
||||
bottomSheetFavHidden.text = getString(if (!appInfo.favorite) R.string.bottom_dialog_add_to_home else R.string.bottom_dialog_remove_from_home)
|
||||
bottomSheetHidden.text = getString(if (!appInfo.hidden) R.string.bottom_dialog_add_to_hidden else R.string.bottom_dialog_remove_to_hidden)
|
||||
bottomSheetLock.text = getString(if (!appInfo.lock) R.string.bottom_dialog_add_to_lock else R.string.bottom_dialog_remove_to_unlock)
|
||||
bottomSheetRename.setText(appInfo.appName)
|
||||
bottomSheetOrder.text = appInfo.appOrder.toString()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun observeClickListener() {
|
||||
val packageName = appInfo.packageName
|
||||
|
||||
val packageManager = context?.packageManager
|
||||
val applicationInfo = packageManager?.getApplicationInfo(packageName, 0)
|
||||
val appName = applicationInfo?.let { packageManager.getApplicationLabel(it).toString() }
|
||||
|
||||
binding.bottomSheetFavHidden.setOnClickListener {
|
||||
appStateClickListener?.onAppStateClicked(appInfo)
|
||||
|
||||
appInfo.favorite = !appInfo.favorite
|
||||
|
||||
viewModel.updateAppInfoFavorite(appInfo)
|
||||
|
||||
Log.d("Tag", "${appInfo.appName} : Bottom Favorite: ${appInfo.favorite}")
|
||||
Log.d("Tag", "${appInfo.appName} : Bottom Order: ${appInfo.appOrder}")
|
||||
|
||||
dismiss()
|
||||
}
|
||||
|
||||
binding.bottomSheetRename.addTextChangedListener(object : TextWatcher {
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
appInfo.appName = s.toString()
|
||||
|
||||
if (s.isNullOrEmpty()) {
|
||||
viewModel.updateAppInfoAppName(appInfo, appName.toString())
|
||||
} else {
|
||||
viewModel.updateAppInfoAppName(appInfo, s.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
if (s.isNullOrEmpty()) {
|
||||
binding.bottomSheetRename.setHintTextColor(ContextCompat.getColor(requireContext(), R.color.white))
|
||||
binding.bottomSheetRename.hint = appName
|
||||
appInfo.appName = appName ?: ""
|
||||
} else {
|
||||
appInfo.appName = s.toString()
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
binding.bottomSheetRenameDone.setOnClickListener {
|
||||
appStateClickListener?.onAppStateClicked(appInfo)
|
||||
viewModel.updateAppInfoAppName(appInfo, appInfo.appName)
|
||||
dismiss()
|
||||
Log.d("Tag", "${appInfo.appName} Bottom State: ${appInfo.appName}")
|
||||
}
|
||||
|
||||
binding.bottomSheetHidden.setOnClickListener {
|
||||
appStateClickListener?.onAppStateClicked(appInfo)
|
||||
appInfo.hidden = !appInfo.hidden
|
||||
|
||||
viewModel.updateAppHidden(appInfo, appInfo.hidden)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
binding.bottomSheetLock.setOnClickListener {
|
||||
if (appInfo.lock) {
|
||||
fingerHelper.startFingerprintAuth(appInfo, this)
|
||||
}
|
||||
else {
|
||||
appInfo.lock = true
|
||||
viewModel.updateAppLock(appInfo, appInfo.lock)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
binding.bottomSheetUninstall.setOnClickListener {
|
||||
appStateClickListener?.onAppStateClicked(appInfo)
|
||||
appHelper.unInstallApp(requireContext(), appInfo)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
binding.bottomSheetInfo.setOnClickListener {
|
||||
appHelper.appInfo(requireContext(), appInfo)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(appInfo: AppInfo) {
|
||||
appInfo.lock = false
|
||||
|
||||
viewModel.updateAppLock(appInfo, appInfo.lock)
|
||||
dismiss()
|
||||
|
||||
appHelper.showToast(requireContext(), getString(R.string.authentication_succeeded))
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
appHelper.showToast(requireContext(), getString(R.string.authentication_failed))
|
||||
}
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errorMessage: CharSequence?) {
|
||||
appHelper.showToast(requireContext(), getString(R.string.authentication_error))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package com.github.droidworksstudio.launcher.ui.bottomsheetdialog
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.github.droidworksstudio.launcher.databinding.BottomsheetdialogColorSettingsBinding
|
||||
import com.github.droidworksstudio.launcher.helper.BottomDialogHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import net.mm2d.color.chooser.ColorChooserDialog
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ColorBottomSheetDialogFragment(context: Context) : BottomSheetDialogFragment() {
|
||||
|
||||
private var _binding: BottomsheetdialogColorSettingsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
@Inject
|
||||
lateinit var preferenceHelper: PreferenceHelper
|
||||
|
||||
@Inject
|
||||
lateinit var bottomDialogHelper: BottomDialogHelper
|
||||
|
||||
private val preferenceViewModel: PreferenceViewModel by viewModels()
|
||||
|
||||
private var color: Int = Color.WHITE
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = BottomsheetdialogColorSettingsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
initView()
|
||||
observeClickListener()
|
||||
}
|
||||
|
||||
private fun initView(){
|
||||
bottomDialogHelper.setupDialogStyle(dialog)
|
||||
|
||||
binding.selectDateTextColor.apply {
|
||||
text = bottomDialogHelper.getColorText(preferenceHelper.dateColor)
|
||||
setTextColor(preferenceHelper.dateColor)
|
||||
}
|
||||
|
||||
binding.selectTimeTextColor.apply {
|
||||
text = bottomDialogHelper.getColorText(preferenceHelper.timeColor)
|
||||
setTextColor(preferenceHelper.timeColor)
|
||||
}
|
||||
|
||||
binding.selectAppTextColor.apply {
|
||||
text = bottomDialogHelper.getColorText(preferenceHelper.appColor)
|
||||
setTextColor(preferenceHelper.appColor)
|
||||
}
|
||||
|
||||
binding.selectBatteryTextColor.apply {
|
||||
text = bottomDialogHelper.getColorText(preferenceHelper.batteryColor)
|
||||
setTextColor(preferenceHelper.batteryColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun observeClickListener(){
|
||||
binding.bottomColorDateView.setOnClickListener {
|
||||
showColorPickerDialog(
|
||||
binding.selectDateTextColor,
|
||||
REQUEST_KEY_DATE_COLOR,
|
||||
preferenceHelper.dateColor
|
||||
)
|
||||
}
|
||||
|
||||
binding.bottomColorTimeView.setOnClickListener {
|
||||
showColorPickerDialog(
|
||||
binding.selectTimeTextColor,
|
||||
REQUEST_KEY_TIME_COLOR,
|
||||
preferenceHelper.timeColor
|
||||
)
|
||||
}
|
||||
|
||||
binding.bottomColorAppView.setOnClickListener {
|
||||
showColorPickerDialog(
|
||||
binding.selectAppTextColor,
|
||||
REQUEST_KEY_APP_COLOR,
|
||||
preferenceHelper.appColor
|
||||
)
|
||||
}
|
||||
|
||||
binding.bottomColorBatteryView.setOnClickListener {
|
||||
showColorPickerDialog(
|
||||
binding.selectBatteryTextColor,
|
||||
REQUEST_KEY_BATTERY_COLOR,
|
||||
preferenceHelper.batteryColor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showColorPickerDialog(view: View, requestCode: String, color: Int) {
|
||||
ColorChooserDialog.show(
|
||||
this, requestCode, color, true, tabs = intArrayOf(
|
||||
ColorChooserDialog.TAB_HSV,
|
||||
ColorChooserDialog.TAB_PALETTE
|
||||
)
|
||||
)
|
||||
|
||||
ColorChooserDialog.registerListener(this, requestCode, { pickedColor ->
|
||||
this.color = pickedColor
|
||||
(view as TextView).apply {
|
||||
//text = getColorText(pickedColor)
|
||||
text = bottomDialogHelper.getColorText(pickedColor)
|
||||
setTextColor(pickedColor)
|
||||
}
|
||||
when (requestCode) {
|
||||
REQUEST_KEY_DAILY_WORD_COLOR -> {
|
||||
preferenceViewModel.setDailyWordColor(pickedColor)
|
||||
Log.d("Tag", "Settings Daily Color: ${Integer.toHexString(pickedColor)}")
|
||||
}
|
||||
|
||||
REQUEST_KEY_BATTERY_COLOR -> {
|
||||
preferenceViewModel.setBatteryColor(pickedColor)
|
||||
Log.d("Tag", "Settings Battery Color: ${Integer.toHexString(pickedColor)}")
|
||||
}
|
||||
|
||||
REQUEST_KEY_APP_COLOR -> {
|
||||
preferenceViewModel.setAppColor(pickedColor)
|
||||
Log.d("Tag", "Settings Daily Color: ${Integer.toHexString(pickedColor)}")
|
||||
}
|
||||
|
||||
REQUEST_KEY_DATE_COLOR -> {
|
||||
preferenceViewModel.setDateColor(pickedColor)
|
||||
Log.d("Tag", "Settings Date Color: ${Integer.toHexString(pickedColor)}")
|
||||
}
|
||||
|
||||
REQUEST_KEY_TIME_COLOR -> {
|
||||
preferenceViewModel.setTimeColor(pickedColor)
|
||||
Log.d("Tag", "Settings Time Color: ${Integer.toHexString(color)}")
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Toast.makeText(context, "onCancel", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_KEY_DATE_COLOR = "REQUEST_DATE_COLOR"
|
||||
private const val REQUEST_KEY_TIME_COLOR = "REQUEST_TIME_COLOR"
|
||||
private const val REQUEST_KEY_DAILY_WORD_COLOR = "REQUEST_DAILY_WORD_COLOR"
|
||||
private const val REQUEST_KEY_APP_COLOR = "REQUEST_APP_COLOR"
|
||||
private const val REQUEST_KEY_BATTERY_COLOR = "REQUEST_BATTERY_COLOR"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.github.droidworksstudio.launcher.ui.bottomsheetdialog
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.github.droidworksstudio.launcher.databinding.BottomsheetdialogTextSettingsBinding
|
||||
import com.github.droidworksstudio.launcher.helper.BottomDialogHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
@AndroidEntryPoint
|
||||
class TextBottomSheetDialogFragment(context: Context) : BottomSheetDialogFragment() {
|
||||
|
||||
private var _binding: BottomsheetdialogTextSettingsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
@Inject
|
||||
lateinit var preferenceHelper: PreferenceHelper
|
||||
|
||||
@Inject
|
||||
lateinit var bottomDialogHelper: BottomDialogHelper
|
||||
|
||||
private val preferenceViewModel: PreferenceViewModel by viewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = BottomsheetdialogTextSettingsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
initView()
|
||||
}
|
||||
|
||||
private fun initView(){
|
||||
bottomDialogHelper.setupDialogStyle(dialog)
|
||||
|
||||
binding.selectDateTextSize.setText(preferenceHelper.dateTextSize.toString())
|
||||
binding.selectTimeTextSize.setText(preferenceHelper.timeTextSize.toString())
|
||||
binding.selectAppTextSize.setText(preferenceHelper.appTextSize.toString())
|
||||
}
|
||||
|
||||
private fun observeValueChange(){
|
||||
val dateValue = binding.selectDateTextSize.text.toString()
|
||||
val timeValue = binding.selectTimeTextSize.text.toString()
|
||||
val appValue = binding.selectAppTextSize.text.toString()
|
||||
|
||||
val dateFloatValue = parseFloatValue(dateValue, preferenceHelper.dateTextSize)
|
||||
val timeFloatValue = parseFloatValue(timeValue, preferenceHelper.timeTextSize)
|
||||
val appFloatValue = parseFloatValue(appValue, preferenceHelper.appTextSize)
|
||||
dismiss()
|
||||
|
||||
preferenceViewModel.setDateTextSize(dateFloatValue)
|
||||
preferenceViewModel.setTimeTextSize(timeFloatValue)
|
||||
preferenceViewModel.setAppTextSize(appFloatValue)
|
||||
}
|
||||
|
||||
private fun parseFloatValue(text: String, defaultValue: Float): Float {
|
||||
if (text.isEmpty() || text == "0") {
|
||||
return defaultValue
|
||||
}
|
||||
return text.toFloat()
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
|
||||
observeValueChange()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.github.droidworksstudio.launcher.ui.drawer
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.ItemDrawBinding
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
|
||||
class DrawAdapter(private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
|
||||
private val onAppLongClickedListener: OnItemClickedListener.OnAppLongClickedListener) :
|
||||
ListAdapter<AppInfo, RecyclerView.ViewHolder>(DiffCallback()) {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: android.view.ViewGroup,
|
||||
viewType: Int
|
||||
): RecyclerView.ViewHolder {
|
||||
val binding = ItemDrawBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return DrawViewHolder(binding, onAppClickedListener, onAppLongClickedListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
|
||||
val appInfo = getItem(position)
|
||||
(holder as DrawViewHolder).bind(appInfo)
|
||||
}
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<AppInfo>() {
|
||||
override fun areItemsTheSame(oldItem: AppInfo, newItem: AppInfo) =
|
||||
oldItem.id == newItem.id
|
||||
|
||||
override fun areContentsTheSame(oldItem: AppInfo, newItem: AppInfo) =
|
||||
oldItem == newItem
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun updateDataWithStateFlow(newData: List<AppInfo>) {
|
||||
submitList(newData.toMutableList())
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package com.github.droidworksstudio.launcher.ui.drawer
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.coroutineScope
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.FragmentDrawBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.FingerprintHelper
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AppInfoBottomSheetFragment
|
||||
import com.github.droidworksstudio.launcher.viewmodel.AppViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass as the second destination in the navigation.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class DrawFragment : Fragment(), OnItemClickedListener.OnAppsClickedListener,
|
||||
OnItemClickedListener.OnAppLongClickedListener,
|
||||
OnItemClickedListener.BottomSheetDismissListener,
|
||||
OnItemClickedListener.OnAppStateClickListener,
|
||||
FingerprintHelper.Callback{
|
||||
private var _binding: FragmentDrawBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val viewModel: AppViewModel by viewModels()
|
||||
|
||||
private val drawAdapter: DrawAdapter by lazy { DrawAdapter(this, this) }
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
@Inject
|
||||
lateinit var fingerHelper: FingerprintHelper
|
||||
|
||||
private lateinit var context: Context
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
_binding = FragmentDrawBinding.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()
|
||||
|
||||
setupRecyclerView()
|
||||
setupSearch()
|
||||
observeClickListener()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
|
||||
binding.drawAdapter.apply {
|
||||
adapter = drawAdapter
|
||||
layoutManager = StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
|
||||
setHasFixedSize(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeDrawerApps() {
|
||||
viewModel.compareInstalledAppInfo()
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
|
||||
viewModel.drawApps.collect{
|
||||
drawAdapter.submitList(it)
|
||||
drawAdapter.updateDataWithStateFlow(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSearch() {
|
||||
binding.searchView1.addTextChangedListener(object: TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||
// Do Nothing
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
searchApp(s.toString())
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
// Do Nothing
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun observeClickListener(){
|
||||
binding.drawSearchButton.setOnClickListener {appHelper.showSoftKeyboard(context, binding.searchView1)}
|
||||
}
|
||||
|
||||
private fun searchApp(query: String?) {
|
||||
|
||||
val searchQuery = "%$query%"
|
||||
viewLifecycleOwner.lifecycle.coroutineScope.launchWhenCreated {
|
||||
viewModel.searchAppInfo(searchQuery).collect { drawAdapter.submitList(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectedApp(appInfo: AppInfo) {
|
||||
binding.searchView1.text?.clear()
|
||||
|
||||
val bottomSheetFragment = AppInfoBottomSheetFragment(appInfo)
|
||||
bottomSheetFragment.setOnBottomSheetDismissedListener(this)
|
||||
bottomSheetFragment.setOnAppStateClickListener(this)
|
||||
bottomSheetFragment.show(parentFragmentManager, "BottomSheetDialog")
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
binding.searchView1.text?.clear()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
observeDrawerApps()
|
||||
binding.drawAdapter.scrollToPosition(0)
|
||||
appHelper.hideKeyboard(context, binding.searchView1)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onAppClicked(appInfo: AppInfo) {
|
||||
observeBioAuthCheck(appInfo)
|
||||
}
|
||||
|
||||
override fun onAppLongClicked(appInfo: AppInfo) {
|
||||
showSelectedApp(appInfo)
|
||||
}
|
||||
|
||||
override fun onBottomSheetDismissed() {
|
||||
}
|
||||
|
||||
override fun onAppStateClicked(appInfo: AppInfo) {
|
||||
viewModel.update(appInfo)
|
||||
Log.d("Tag", "${appInfo.appName} : Draw Favorite: ${appInfo.favorite}")
|
||||
}
|
||||
|
||||
private fun observeBioAuthCheck(appInfo: AppInfo) {
|
||||
if (!appInfo.lock) {
|
||||
appHelper.launchApp(context, appInfo)
|
||||
} else {
|
||||
fingerHelper.startFingerprintAuth(appInfo,this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(appInfo: AppInfo) {
|
||||
Toast.makeText(context, getString(R.string.authentication_succeeded), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
appHelper.launchApp(context, appInfo)
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
Toast.makeText(context, getString(R.string.authentication_failed), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errorMessage: CharSequence?) {
|
||||
Toast.makeText(context, getString(R.string.authentication_error), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.github.droidworksstudio.launcher.ui.drawer
|
||||
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.ItemDrawBinding
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
|
||||
class DrawViewHolder(private val binding: ItemDrawBinding,
|
||||
private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
|
||||
private val onAppLongClickedListener: OnItemClickedListener.OnAppLongClickedListener) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(appInfo: AppInfo) {
|
||||
binding.apply {
|
||||
appDrawName.text = appInfo.appName
|
||||
Log.d("Tag", "Draw Adapter: ${appInfo.appName + appInfo.id}")
|
||||
}
|
||||
|
||||
itemView.setOnClickListener {
|
||||
onAppClickedListener.onAppClicked(appInfo)
|
||||
}
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
onAppLongClickedListener.onAppLongClicked(appInfo)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.github.droidworksstudio.launcher.ui.favorite
|
||||
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.ItemFavoriteBinding
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemMoveListener
|
||||
|
||||
class FavoriteAdapter(private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
|
||||
) : ListAdapter<AppInfo, RecyclerView.ViewHolder>(DiffCallback()) ,OnItemMoveListener.OnItemActionListener{
|
||||
|
||||
private lateinit var touchHelper: ItemTouchHelper
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: android.view.ViewGroup,
|
||||
viewType: Int
|
||||
): RecyclerView.ViewHolder {
|
||||
val binding = ItemFavoriteBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return FavoriteViewHolder(binding, onAppClickedListener, touchHelper)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val currentItem = getItem(position)
|
||||
when (holder) {
|
||||
is FavoriteViewHolder -> {
|
||||
holder.bind(currentItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DiffCallback : androidx.recyclerview.widget.DiffUtil.ItemCallback<AppInfo>() {
|
||||
override fun areItemsTheSame(oldItem: AppInfo, newItem: AppInfo) =
|
||||
oldItem.id == newItem.id
|
||||
|
||||
override fun areContentsTheSame(oldItem: AppInfo, newItem: AppInfo) =
|
||||
oldItem == newItem
|
||||
}
|
||||
|
||||
fun setItemTouchHelper(touchHelper: ItemTouchHelper) {
|
||||
this.touchHelper = touchHelper
|
||||
}
|
||||
|
||||
override fun onViewMoved(oldPosition: Int, newPosition: Int): Boolean {
|
||||
Log.d("Tag", "List Adapter$newPosition")
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onViewSwiped(position: Int) {
|
||||
Log.d("Tag", "onViewMoved")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package com.github.droidworksstudio.launcher.ui.favorite
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.FragmentFavoriteBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.FingerprintHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemMoveListener
|
||||
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AppInfoBottomSheetFragment
|
||||
import com.github.droidworksstudio.launcher.viewmodel.AppViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Collections
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FavoriteFragment : Fragment(), OnItemClickedListener.OnAppsClickedListener,
|
||||
OnItemClickedListener.BottomSheetDismissListener,
|
||||
OnItemClickedListener.OnAppStateClickListener,
|
||||
FingerprintHelper.Callback,OnItemMoveListener.OnItemActionListener{
|
||||
private var _binding: FragmentFavoriteBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val viewModel: AppViewModel by viewModels()
|
||||
|
||||
private lateinit var context: Context
|
||||
|
||||
@Inject
|
||||
lateinit var preferenceHelper: PreferenceHelper
|
||||
|
||||
@Inject
|
||||
lateinit var fingerHelper: FingerprintHelper
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
private val favoriteAdapter: FavoriteAdapter by lazy { FavoriteAdapter(this) }
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
_binding = FragmentFavoriteBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
appHelper.dayNightMod(requireContext(), binding.favoriteView)
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
context = requireContext()
|
||||
|
||||
setupRecyclerView()
|
||||
observeFavorite()
|
||||
observeHomeAppOrder()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
|
||||
binding.favoriteAdapter.apply {
|
||||
adapter = favoriteAdapter
|
||||
layoutManager = StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
|
||||
setHasFixedSize(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDragAndDrop(oldPosition: Int, newPosition: Int) {
|
||||
val items = favoriteAdapter.currentList.toMutableList()
|
||||
Collections.swap(items, oldPosition, newPosition)
|
||||
|
||||
items.forEachIndexed { index, appInfo ->
|
||||
appInfo.appOrder = index
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.updateAppOrder(items)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun observeHomeAppOrder() {
|
||||
//binding.favoriteAdapter.adapter = favoriteAdapter
|
||||
val listener: OnItemMoveListener.OnItemActionListener = favoriteAdapter
|
||||
|
||||
val simpleItemTouchCallback = object : ItemTouchHelper.Callback() {
|
||||
|
||||
override fun onChildDraw(
|
||||
canvas: Canvas, recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder, dX: Float,
|
||||
dY: Float, actionState: Int, isCurrentlyActive: Boolean
|
||||
) {
|
||||
if (isCurrentlyActive) {
|
||||
viewHolder.itemView.alpha = 0.5f
|
||||
} else {
|
||||
viewHolder.itemView.alpha = 1f
|
||||
}
|
||||
super.onChildDraw(
|
||||
canvas, recyclerView, viewHolder,
|
||||
dX, dY,
|
||||
actionState, isCurrentlyActive
|
||||
)
|
||||
}
|
||||
|
||||
override fun getMovementFlags(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder
|
||||
): Int {
|
||||
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
|
||||
val swipeFlags = 0
|
||||
return makeMovementFlags(dragFlags, swipeFlags)
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
|
||||
val oldPosition = viewHolder.bindingAdapterPosition
|
||||
val newPosition = target.bindingAdapterPosition
|
||||
|
||||
handleDragAndDrop(oldPosition, newPosition)
|
||||
|
||||
return listener.onViewMoved(
|
||||
viewHolder.bindingAdapterPosition,
|
||||
target.bindingAdapterPosition
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
listener.onViewSwiped(viewHolder.adapterPosition)
|
||||
}
|
||||
|
||||
override fun isLongPressDragEnabled() = false
|
||||
}
|
||||
|
||||
val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback)
|
||||
|
||||
favoriteAdapter.setItemTouchHelper(itemTouchHelper)
|
||||
itemTouchHelper.attachToRecyclerView(binding.favoriteAdapter)
|
||||
}
|
||||
|
||||
private fun observeFavorite() {
|
||||
viewModel.compareInstalledAppInfo()
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.favoriteApps.collect {
|
||||
favoriteAdapter.submitList(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeBioAuthCheck(appInfo: AppInfo) {
|
||||
if (!appInfo.lock) {
|
||||
appHelper.launchApp(context, appInfo)
|
||||
} else {
|
||||
fingerHelper.startFingerprintAuth(appInfo, this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectedApp(appInfo: AppInfo) {
|
||||
val bottomSheetFragment = AppInfoBottomSheetFragment(appInfo)
|
||||
bottomSheetFragment.setOnBottomSheetDismissedListener(this)
|
||||
bottomSheetFragment.setOnAppStateClickListener(this)
|
||||
bottomSheetFragment.show(parentFragmentManager, "BottomSheetDialog")
|
||||
|
||||
}
|
||||
|
||||
override fun onBottomSheetDismissed() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onAppStateClicked(appInfo: AppInfo) {
|
||||
viewModel.update(appInfo)
|
||||
}
|
||||
|
||||
override fun onAppClicked(appInfo: AppInfo) {
|
||||
observeBioAuthCheck(appInfo)
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(appInfo: AppInfo) {
|
||||
Toast.makeText(context, getString(R.string.authentication_succeeded), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
appHelper.launchApp(context, appInfo)
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
Toast.makeText(context, getString(R.string.authentication_failed), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errorMessage: CharSequence?) {
|
||||
Toast.makeText(context, getString(R.string.authentication_error), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onViewMoved(oldPosition: Int, newPosition: Int): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onViewSwiped(position: Int) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.github.droidworksstudio.launcher.ui.favorite
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.util.Log
|
||||
import android.view.MotionEvent
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.ItemFavoriteBinding
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
class FavoriteViewHolder(private val binding: ItemFavoriteBinding,
|
||||
private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
|
||||
private val touchHelper: ItemTouchHelper,
|
||||
) :
|
||||
RecyclerView.ViewHolder(binding.root){
|
||||
|
||||
init {
|
||||
binding.appFavoriteDragIcon.setOnTouchListener { _, event ->
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
touchHelper.startDrag(this)
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(appInfo: AppInfo) {
|
||||
binding.apply {
|
||||
appFavoriteName.text = appInfo.appName
|
||||
//appFavoriteDragIcon.visibility = View.GONE
|
||||
Log.d("Tag", "Draw Adapter: ${appInfo.appName}")
|
||||
}
|
||||
|
||||
itemView.setOnClickListener {
|
||||
onAppClickedListener.onAppClicked(appInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.github.droidworksstudio.launcher.ui.hidden
|
||||
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.ItemHiddenBinding
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
|
||||
class HiddenAdapter(
|
||||
private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
|
||||
private val onAppLongClickedListener: OnItemClickedListener.OnAppLongClickedListener
|
||||
) : ListAdapter<AppInfo, RecyclerView.ViewHolder>(DiffCallback()) {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: android.view.ViewGroup,
|
||||
viewType: Int
|
||||
): RecyclerView.ViewHolder {
|
||||
val binding = ItemHiddenBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return HiddenViewHolder(binding, onAppClickedListener, onAppLongClickedListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
getItem(position)
|
||||
when (holder) {
|
||||
is HiddenViewHolder -> {
|
||||
|
||||
val appInfo = getItem(position) as AppInfo
|
||||
holder.bind(appInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<AppInfo>() {
|
||||
override fun areItemsTheSame(oldItem: AppInfo, newItem: AppInfo) =
|
||||
oldItem.id == newItem.id
|
||||
|
||||
override fun areContentsTheSame(oldItem: AppInfo, newItem: AppInfo) =
|
||||
oldItem == newItem
|
||||
}
|
||||
|
||||
fun updateData(newData: List<AppInfo>) {
|
||||
notifyItemChanged(newData.size)
|
||||
submitList(newData)
|
||||
Log.d("Tag", "Collected Hidden Adapter : $newData")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.github.droidworksstudio.launcher.ui.hidden
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.FragmentHiddenBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.FingerprintHelper
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AppInfoBottomSheetFragment
|
||||
import com.github.droidworksstudio.launcher.viewmodel.AppViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class HiddenFragment : Fragment(), OnItemClickedListener.OnAppsClickedListener,
|
||||
OnItemClickedListener.OnAppLongClickedListener,
|
||||
OnItemClickedListener.BottomSheetDismissListener,
|
||||
OnItemClickedListener.OnAppStateClickListener,
|
||||
FingerprintHelper.Callback{
|
||||
private var _binding: FragmentHiddenBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val hiddenAdapter: HiddenAdapter by lazy { HiddenAdapter(this, this) }
|
||||
|
||||
private val viewModel: AppViewModel by viewModels()
|
||||
|
||||
private lateinit var context: Context
|
||||
|
||||
@Inject
|
||||
lateinit var fingerHelper: FingerprintHelper
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
_binding = FragmentHiddenBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
appHelper.dayNightMod(requireContext(), binding.hiddenView)
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
context = requireContext()
|
||||
|
||||
setupRecyclerView()
|
||||
observeHiddenApps()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
binding.hiddenAdapter.apply {
|
||||
adapter = hiddenAdapter
|
||||
layoutManager = StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
|
||||
setHasFixedSize(false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun observeHiddenApps() {
|
||||
viewModel.compareInstalledAppInfo()
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
|
||||
viewModel.hiddenApps.collect {
|
||||
hiddenAdapter.updateData(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeBioAuthCheck(appInfo: AppInfo) {
|
||||
if (!appInfo.lock) {
|
||||
appHelper.launchApp(context, appInfo)
|
||||
} else {
|
||||
fingerHelper.startFingerprintAuth(appInfo,this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSelectedApp(appInfo: AppInfo) {
|
||||
val bottomSheetFragment = AppInfoBottomSheetFragment(appInfo)
|
||||
bottomSheetFragment.setOnBottomSheetDismissedListener(this)
|
||||
bottomSheetFragment.setOnAppStateClickListener(this)
|
||||
bottomSheetFragment.show(parentFragmentManager, "BottomSheetDialog")
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
binding.hiddenAdapter.scrollToPosition(0)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
observeHiddenApps()
|
||||
}
|
||||
|
||||
override fun onAppLongClicked(appInfo: AppInfo) {
|
||||
showSelectedApp(appInfo)
|
||||
}
|
||||
|
||||
override fun onBottomSheetDismissed() {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun onAppStateClicked(appInfo: AppInfo) {
|
||||
viewModel.update(appInfo)
|
||||
}
|
||||
|
||||
override fun onAppClicked(appInfo: AppInfo) {
|
||||
observeBioAuthCheck(appInfo)
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(appInfo: AppInfo) {
|
||||
Toast.makeText(context, getString(R.string.authentication_succeeded), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
appHelper.launchApp(context, appInfo)
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
Toast.makeText(context, getString(R.string.authentication_failed), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errorMessage: CharSequence?) {
|
||||
Toast.makeText(context, getString(R.string.authentication_error), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.github.droidworksstudio.launcher.ui.hidden
|
||||
|
||||
import android.util.Log
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.ItemHiddenBinding
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
|
||||
class HiddenViewHolder(private val binding: ItemHiddenBinding,
|
||||
private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
|
||||
private val onAppLongClickedListener: OnItemClickedListener.OnAppLongClickedListener) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(appInfo: AppInfo) {
|
||||
binding.apply {
|
||||
appHiddenName.text = appInfo.appName
|
||||
Log.d("Tag", "Draw Adapter: ${appInfo.appName}")
|
||||
}
|
||||
|
||||
itemView.setOnClickListener {
|
||||
onAppClickedListener.onAppClicked(appInfo)
|
||||
}
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
onAppLongClickedListener.onAppLongClicked(appInfo)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.github.droidworksstudio.launcher.ui.home
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.ItemHomeBinding
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
import javax.inject.Inject
|
||||
|
||||
class HomeAdapter @Inject constructor(private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
|
||||
private val onAppLongClickedListener: OnItemClickedListener.OnAppLongClickedListener,
|
||||
private val preferenceHelperProvider: PreferenceHelper
|
||||
) :
|
||||
ListAdapter<AppInfo,RecyclerView.ViewHolder>(DiffCallback()) {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: android.view.ViewGroup,
|
||||
viewType: Int
|
||||
): RecyclerView.ViewHolder {
|
||||
val binding = ItemHomeBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
val preferenceHelper = preferenceHelperProvider
|
||||
|
||||
return HomeViewHolder(binding, onAppClickedListener, onAppLongClickedListener, preferenceHelper)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
|
||||
val appInfo = getItem(position)
|
||||
(holder as HomeViewHolder).bind(appInfo)
|
||||
}
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<AppInfo>() {
|
||||
override fun areItemsTheSame(oldItem: AppInfo, newItem: AppInfo) =
|
||||
oldItem.id == newItem.id
|
||||
|
||||
override fun areContentsTheSame(oldItem: AppInfo, newItem: AppInfo) =
|
||||
oldItem == newItem
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun updateDataWithStateFlow(newData: List<AppInfo>) {
|
||||
submitList(newData.toMutableList())
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
package com.github.droidworksstudio.launcher.ui.home
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.BatteryManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateFormat
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.accessibility.MyAccessibilityService
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.FragmentHomeBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.FingerprintHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
import com.github.droidworksstudio.launcher.listener.OnSwipeTouchListener
|
||||
import com.github.droidworksstudio.launcher.listener.ScrollEventListener
|
||||
import com.github.droidworksstudio.launcher.ui.activities.SettingsActivity
|
||||
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AppInfoBottomSheetFragment
|
||||
import com.github.droidworksstudio.launcher.viewmodel.AppViewModel
|
||||
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass as the default destination in the navigation.
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class HomeFragment : Fragment(), OnItemClickedListener.OnAppsClickedListener,
|
||||
OnItemClickedListener.OnAppLongClickedListener,
|
||||
OnItemClickedListener.BottomSheetDismissListener,
|
||||
OnItemClickedListener.OnAppStateClickListener,
|
||||
FingerprintHelper.Callback, ScrollEventListener {
|
||||
|
||||
private var _binding: FragmentHomeBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
|
||||
@Inject
|
||||
lateinit var preferenceHelper: PreferenceHelper
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
@Inject
|
||||
lateinit var fingerHelper: FingerprintHelper
|
||||
|
||||
private val viewModel: AppViewModel by viewModels()
|
||||
private val preferenceViewModel: PreferenceViewModel by viewModels()
|
||||
|
||||
private val homeAdapter: HomeAdapter by lazy { HomeAdapter(this, this, preferenceHelper) }
|
||||
|
||||
private lateinit var batteryReceiver: BroadcastReceiver
|
||||
|
||||
private lateinit var context: Context
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
initializeInjectedDependencies()
|
||||
setupBattery()
|
||||
setupRecyclerView()
|
||||
observeUserInterfaceSettings()
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private fun initializeInjectedDependencies() {
|
||||
context = requireContext()
|
||||
|
||||
binding.nestScrollView.scrollEventListener = this
|
||||
|
||||
binding.nestScrollView.registerRecyclerView(binding.appListAdapter, this)
|
||||
|
||||
preferenceViewModel.setShowTime(preferenceHelper.showTime)
|
||||
preferenceViewModel.setShowDate(preferenceHelper.showDate)
|
||||
preferenceViewModel.setShowDailyWord(preferenceHelper.showDailyWord)
|
||||
|
||||
binding.mainView.setOnTouchListener(getSwipeGestureListener(context))
|
||||
|
||||
binding.clock.setOnClickListener { appHelper.launchClock(context) }
|
||||
binding.date.setOnClickListener { appHelper.launchCalendar(context) }
|
||||
}
|
||||
|
||||
private fun setupBattery() {
|
||||
batteryReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
|
||||
val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
|
||||
|
||||
val batteryLevel = level * 100 / scale.toFloat()
|
||||
val batteryLevelText = getString(R.string.battery_level, batteryLevel.toString())
|
||||
binding.battery.text = batteryLevelText
|
||||
}
|
||||
}
|
||||
|
||||
val batteryIntentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
||||
requireActivity().registerReceiver(batteryReceiver, batteryIntentFilter)
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
val marginTopInPixels = 128
|
||||
val params: ViewGroup.MarginLayoutParams = binding.appListAdapter.layoutParams as ViewGroup.MarginLayoutParams
|
||||
params.topMargin = marginTopInPixels
|
||||
binding.appListAdapter.layoutParams = params
|
||||
|
||||
binding.appListAdapter.apply {
|
||||
adapter = homeAdapter
|
||||
setHasFixedSize(false)
|
||||
layoutManager = StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
|
||||
//itemAnimator = false
|
||||
isNestedScrollingEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeFavoriteAppList() {
|
||||
viewModel.compareInstalledAppInfo()
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launchWhenCreated {
|
||||
viewModel.favoriteApps.flowOn(Dispatchers.Main).collect {
|
||||
homeAdapter.submitList(it)
|
||||
homeAdapter.updateDataWithStateFlow(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeUserInterfaceSettings() {
|
||||
preferenceViewModel.setShowTime(preferenceHelper.showTime)
|
||||
preferenceViewModel.setShowDate(preferenceHelper.showDate)
|
||||
preferenceViewModel.setShowDailyWord(preferenceHelper.showDailyWord)
|
||||
preferenceViewModel.setShowBattery(preferenceHelper.showBattery)
|
||||
|
||||
preferenceViewModel.showTimeLiveData.observe(viewLifecycleOwner) {
|
||||
Log.d("Tag", "ShowTime Home: $it")
|
||||
//updateViewVisibility(binding.clock, showTime)
|
||||
appHelper.updateUI(binding.clock,
|
||||
preferenceHelper.homeTimeAlignment,
|
||||
preferenceHelper.timeColor,
|
||||
preferenceHelper.timeTextSize,
|
||||
preferenceHelper.showTime
|
||||
)
|
||||
}
|
||||
|
||||
preferenceViewModel.showDateLiveData.observe(viewLifecycleOwner) {
|
||||
appHelper.updateUI(binding.date,
|
||||
preferenceHelper.homeDateAlignment,
|
||||
preferenceHelper.dateColor,
|
||||
preferenceHelper.timeTextSize,
|
||||
preferenceHelper.showDate
|
||||
)
|
||||
}
|
||||
preferenceViewModel.showBatteryLiveData.observe(viewLifecycleOwner){
|
||||
//binding.battery.setTextColor(preferenceHelper.batteryColor)
|
||||
appHelper.updateUI(binding.battery, Gravity.END,
|
||||
preferenceHelper.batteryColor,
|
||||
preferenceHelper.timeTextSize,
|
||||
preferenceHelper.showBattery
|
||||
)
|
||||
}
|
||||
|
||||
preferenceViewModel.showDailyWordLiveData.observe(viewLifecycleOwner) {
|
||||
// updateViewVisibility(binding.word, showDailyWord)
|
||||
// appHelper.updateUI(binding.word, preferenceHelper.homeDailyWordAlignment, preferenceHelper.dailyWordColor, preferenceHelper.showDailyWord)
|
||||
}
|
||||
val is24HourFormat = DateFormat.is24HourFormat(requireContext())
|
||||
val localLocale = Locale.getDefault()
|
||||
val best12 = DateFormat.getBestDateTimePattern(localLocale, "hmma")
|
||||
val best24 = DateFormat.getBestDateTimePattern(localLocale, "HHmm")
|
||||
|
||||
val timePattern = if (is24HourFormat) best24 else best12
|
||||
binding.clock.format12Hour = timePattern
|
||||
binding.clock.format24Hour = timePattern
|
||||
val datePattern = DateFormat.getBestDateTimePattern(localLocale, "eeeddMMM")
|
||||
binding.date.format12Hour = datePattern
|
||||
binding.date.format24Hour = datePattern
|
||||
}
|
||||
|
||||
private fun observeBioAuthCheck(appInfo: AppInfo) {
|
||||
if (!appInfo.lock) appHelper.launchApp(context, appInfo) else fingerHelper.startFingerprintAuth(appInfo, this)
|
||||
}
|
||||
|
||||
private fun showSelectedApp(appInfo: AppInfo) {
|
||||
val bottomSheetFragment = AppInfoBottomSheetFragment(appInfo)
|
||||
bottomSheetFragment.setOnBottomSheetDismissedListener(this)
|
||||
bottomSheetFragment.setOnAppStateClickListener(this)
|
||||
bottomSheetFragment.show(parentFragmentManager, "BottomSheetDialog")
|
||||
|
||||
}
|
||||
|
||||
private fun getSwipeGestureListener(context: Context): View.OnTouchListener {
|
||||
return object : OnSwipeTouchListener(context) {
|
||||
override fun onLongClick() {
|
||||
super.onLongClick()
|
||||
val intent = Intent(requireActivity(), SettingsActivity::class.java)
|
||||
requireActivity().startActivity(intent)
|
||||
return
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.P)
|
||||
override fun onDoubleClick() {
|
||||
super.onDoubleClick()
|
||||
if(preferenceHelper.tapLockScreen) { MyAccessibilityService.instance()?.lockScreen() } else { return }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
requireActivity().unregisterReceiver(batteryReceiver)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
observeUserInterfaceSettings()
|
||||
observeFavoriteAppList()
|
||||
}
|
||||
|
||||
override fun onAppClicked(appInfo: AppInfo) {
|
||||
observeBioAuthCheck(appInfo)
|
||||
}
|
||||
|
||||
override fun onAppLongClicked(appInfo: AppInfo) {
|
||||
showSelectedApp(appInfo)
|
||||
Log.d("Tag", "Home LiveData Favorite : ${appInfo.favorite}")
|
||||
}
|
||||
|
||||
override fun onBottomSheetDismissed() {
|
||||
}
|
||||
|
||||
override fun onAppStateClicked(appInfo: AppInfo) {
|
||||
viewModel.update(appInfo)
|
||||
Log.d("Tag", "${appInfo.appName} : Home Favorite: ${appInfo.favorite}")
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(appInfo: AppInfo) {
|
||||
appHelper.launchApp(context, appInfo)
|
||||
appHelper.showToast(context, getString(R.string.authentication_succeeded))
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
appHelper.showToast(context, getString(R.string.authentication_failed))
|
||||
}
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errorMessage: CharSequence?) {
|
||||
appHelper.showToast(context, getString(R.string.authentication_error))
|
||||
}
|
||||
|
||||
override fun onTopReached() {
|
||||
appHelper.expandNotificationDrawer(context)
|
||||
}
|
||||
|
||||
override fun onBottomReached() {
|
||||
appHelper.searchView(context)
|
||||
}
|
||||
|
||||
override fun onScroll(isTopReached: Boolean, isBottomReached: Boolean) {
|
||||
Log.d("Tag", "onScroll")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.github.droidworksstudio.launcher.ui.home
|
||||
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.LinearLayoutCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.databinding.ItemHomeBinding
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class HomeViewHolder @Inject constructor(
|
||||
private val binding: ItemHomeBinding,
|
||||
private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
|
||||
private val onAppLongClickedListener: OnItemClickedListener.OnAppLongClickedListener,
|
||||
private val preferenceHelper: PreferenceHelper
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(appInfo: AppInfo) {
|
||||
|
||||
binding.apply {
|
||||
val layoutParams = LinearLayoutCompat.LayoutParams(
|
||||
LinearLayoutCompat.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayoutCompat.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
gravity = preferenceHelper.homeAppAlignment
|
||||
}
|
||||
|
||||
appHomeName.layoutParams = layoutParams
|
||||
appHomeName.text = appInfo.appName
|
||||
appHomeName.setTextColor(preferenceHelper.appColor)
|
||||
appHomeName.textSize = preferenceHelper.appTextSize
|
||||
Log.d("Tag", "Home Adapter Color: ${preferenceHelper.appColor}")
|
||||
appHomeIcon.visibility = View.GONE
|
||||
}
|
||||
|
||||
itemView.setOnClickListener { onAppClickedListener.onAppClicked(appInfo) }
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
onAppLongClickedListener.onAppLongClicked(appInfo)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.github.droidworksstudio.launcher.ui.settings
|
||||
|
||||
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.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.github.droidworksstudio.launcher.R
|
||||
import com.github.droidworksstudio.launcher.databinding.FragmentSettingsBinding
|
||||
import com.github.droidworksstudio.launcher.helper.AppHelper
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import com.github.droidworksstudio.launcher.listener.ScrollEventListener
|
||||
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.AlignmentBottomSheetDialogFragment
|
||||
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.ColorBottomSheetDialogFragment
|
||||
import com.github.droidworksstudio.launcher.ui.bottomsheetdialog.TextBottomSheetDialogFragment
|
||||
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsFragment : Fragment(), ScrollEventListener {
|
||||
|
||||
private var _binding: FragmentSettingsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
//private val viewModel: AppViewModel by viewModels()
|
||||
private val preferenceViewModel: PreferenceViewModel by viewModels()
|
||||
|
||||
@Inject
|
||||
lateinit var preferenceHelper: PreferenceHelper
|
||||
|
||||
@Inject
|
||||
lateinit var appHelper: AppHelper
|
||||
|
||||
private lateinit var navController: NavController
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
// Inflate the layout for this fragment
|
||||
_binding = FragmentSettingsBinding.inflate(inflater, container, false)
|
||||
_binding = binding
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
// Called after the fragment view is created
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// Set according to the system theme mode
|
||||
appHelper.dayNightMod(requireContext(), binding.nestScrollView)
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
initializeInjectedDependencies()
|
||||
observeClickListener()
|
||||
}
|
||||
|
||||
private fun initializeInjectedDependencies() {
|
||||
navController = findNavController()
|
||||
binding.nestScrollView.scrollEventListener = this
|
||||
|
||||
// Set initial values and listeners for switches
|
||||
binding.statueBarSwitchCompat.isChecked = preferenceHelper.showStatusBar
|
||||
binding.timeSwitchCompat.isChecked = preferenceHelper.showTime
|
||||
binding.dateSwitchCompat.isChecked = preferenceHelper.showDate
|
||||
binding.batterySwitchCompat.isChecked = preferenceHelper.showBattery
|
||||
binding.gesturesLockSwitchCompat1.isChecked = preferenceHelper.tapLockScreen
|
||||
}
|
||||
|
||||
private fun observeClickListener() {
|
||||
setupSwitchListeners()
|
||||
|
||||
// Click listener for reset default launcher
|
||||
binding.setLauncherSelector.setOnClickListener {
|
||||
appHelper.resetDefaultLauncher(requireContext())
|
||||
}
|
||||
|
||||
binding.favoriteText.setOnClickListener {
|
||||
findNavController().navigate(R.id.action_SettingsFragment_to_FavoriteFragment)
|
||||
}
|
||||
|
||||
binding.hiddenText.setOnClickListener {
|
||||
findNavController().navigate(R.id.action_SettingsFragment_to_HiddenFragment)
|
||||
}
|
||||
|
||||
binding.setAppWallpaper.setOnClickListener {
|
||||
val intent = Intent(Intent.ACTION_SET_WALLPAPER)
|
||||
startActivity(Intent.createChooser(intent, "Select Wallpaper"))
|
||||
}
|
||||
|
||||
binding.selectAppearanceTextSize.setOnClickListener {
|
||||
val bottomSheetFragment = TextBottomSheetDialogFragment(this.requireContext())
|
||||
bottomSheetFragment.show(parentFragmentManager, "BottomSheetDialog")
|
||||
}
|
||||
|
||||
binding.selectAppearanceAlignment.setOnClickListener {
|
||||
val bottomSheetFragment = AlignmentBottomSheetDialogFragment(this.requireContext())
|
||||
bottomSheetFragment.show(parentFragmentManager, "BottomSheetDialog")
|
||||
}
|
||||
|
||||
binding.selectAppearanceColor.setOnClickListener {
|
||||
val bottomSheetFragment = ColorBottomSheetDialogFragment(this.requireContext())
|
||||
bottomSheetFragment.show(parentFragmentManager, "BottomSheetDialog")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSwitchListeners() {
|
||||
binding.statueBarSwitchCompat.setOnCheckedChangeListener { _, isChecked ->
|
||||
preferenceViewModel.setShowStatusBar(isChecked)
|
||||
}
|
||||
|
||||
binding.timeSwitchCompat.setOnCheckedChangeListener { _, isChecked ->
|
||||
preferenceViewModel.setShowTime(isChecked)
|
||||
}
|
||||
|
||||
binding.dateSwitchCompat.setOnCheckedChangeListener { _, isChecked ->
|
||||
preferenceViewModel.setShowDate(isChecked)
|
||||
}
|
||||
binding.batterySwitchCompat.setOnCheckedChangeListener { _, isChecked ->
|
||||
preferenceViewModel.setShowBattery(isChecked)
|
||||
}
|
||||
binding.gesturesLockSwitchCompat1.setOnCheckedChangeListener { _, isChecked ->
|
||||
appHelper.enableAppAsAccessibilityService(requireContext(), preferenceHelper.tapLockScreen)
|
||||
preferenceViewModel.setDoubleTapLock(isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTopReached() {
|
||||
requireActivity().onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
override fun onBottomReached() {
|
||||
Log.d("Tag", "onBottomReached")
|
||||
}
|
||||
|
||||
override fun onScroll(isTopReached: Boolean, isBottomReached: Boolean) {
|
||||
Log.d("Tag", "onScroll")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.github.droidworksstudio.launcher.ui.viewpager
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.github.droidworksstudio.launcher.ui.drawer.DrawFragment
|
||||
import com.github.droidworksstudio.launcher.ui.home.HomeFragment
|
||||
|
||||
|
||||
class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
||||
FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||
|
||||
private val fragments: ArrayList<Fragment> = arrayListOf(
|
||||
HomeFragment(),
|
||||
DrawFragment(),
|
||||
)
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return fragments.size
|
||||
}
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return fragments[position]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.github.droidworksstudio.launcher.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewConfiguration
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.droidworksstudio.launcher.listener.ScrollEventListener
|
||||
|
||||
class GestureNestedScrollView(context: Context, attrs: AttributeSet) : NestedScrollView(context, attrs){
|
||||
|
||||
private var startY: Float = 0f
|
||||
private var startTouchY: Float = 0f
|
||||
private var isTopReached: Boolean = false
|
||||
private var isBottomReached: Boolean = false
|
||||
private var isScrollingUp: Boolean = false
|
||||
private var isPullingDown: Boolean = false
|
||||
private var isPullingUp: Boolean = false
|
||||
|
||||
var scrollEventListener: ScrollEventListener? = null
|
||||
|
||||
|
||||
init {
|
||||
isNestedScrollingEnabled = true
|
||||
}
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
||||
when (ev.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
startY = ev.y
|
||||
startTouchY = ev.y
|
||||
isScrollingUp = false
|
||||
isPullingDown = false
|
||||
isPullingUp = false
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val deltaY = ev.y - startY
|
||||
isTopReached = !canScrollVertically(-1)
|
||||
isBottomReached = !canScrollVertically(1)
|
||||
isScrollingUp = deltaY < 0 && isTopReached
|
||||
|
||||
val distanceY = ev.y - startTouchY
|
||||
val threshold = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
|
||||
isPullingDown = distanceY > threshold && isTopReached
|
||||
isPullingUp = distanceY < -threshold && isBottomReached
|
||||
}
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(ev: MotionEvent): Boolean {
|
||||
when (ev.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
startY = ev.y
|
||||
startTouchY = ev.y
|
||||
isScrollingUp = false
|
||||
isPullingDown = false
|
||||
isPullingUp = false
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val deltaY = ev.y - startY
|
||||
isTopReached = !canScrollVertically(-1)
|
||||
isBottomReached = !canScrollVertically(1)
|
||||
isScrollingUp = deltaY < 0 && isTopReached
|
||||
|
||||
val distanceY = ev.y - startTouchY
|
||||
val threshold = 200
|
||||
isPullingDown = distanceY > threshold && isTopReached
|
||||
isPullingUp = distanceY < -threshold && isBottomReached
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
startY = 0f
|
||||
if (isPullingDown) {
|
||||
scrollEventListener?.onTopReached()
|
||||
return true
|
||||
} else if (isPullingUp) {
|
||||
scrollEventListener?.onBottomReached()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onTouchEvent(ev)
|
||||
}
|
||||
|
||||
fun isTopReached(): Boolean {
|
||||
return !canScrollVertically(-1)
|
||||
// return isTopReached && isScrollingUp
|
||||
}
|
||||
|
||||
fun isBottomReached(): Boolean {
|
||||
return !canScrollVertically(1)
|
||||
// return isBottomReached && !isScrollingUp
|
||||
}
|
||||
|
||||
fun registerRecyclerView(recyclerView: RecyclerView, eventListener: ScrollEventListener) {
|
||||
scrollEventListener = eventListener
|
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
scrollEventListener?.onScroll(isTopReached(), isBottomReached())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.github.droidworksstudio.launcher.viewmodel
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.droidworksstudio.launcher.data.entities.AppInfo
|
||||
import com.github.droidworksstudio.launcher.repository.AppInfoRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AppViewModel @Inject constructor(
|
||||
private val appInfoRepository: AppInfoRepository
|
||||
) : ViewModel() {
|
||||
|
||||
val drawApps: Flow<List<AppInfo>> = appInfoRepository.getDrawApps().conflate()
|
||||
val favoriteApps: Flow<List<AppInfo>> = appInfoRepository.getFavoriteApps().conflate()
|
||||
val hiddenApps: Flow<List<AppInfo>> = appInfoRepository.getHiddenApps().conflate()
|
||||
fun initializeInstalledAppInfo(context: Context) {
|
||||
viewModelScope.launch {
|
||||
appInfoRepository.initInstalledAppInfo(context)
|
||||
}
|
||||
}
|
||||
fun updateAppInfoFavorite(appInfo: AppInfo) {
|
||||
viewModelScope.launch {
|
||||
appInfoRepository.updateFavoriteAppInfo(appInfo)
|
||||
Log.d("Tag", "ViewModel Home Order : ${appInfo.appOrder}")
|
||||
}
|
||||
}
|
||||
fun updateAppInfoAppName(appInfo: AppInfo, newAppName: String) {
|
||||
viewModelScope.launch {
|
||||
appInfoRepository.updateAppName(appInfo, newAppName)
|
||||
Log.d("Tag", "ViewModel Home Name : ${appInfo.appName}")
|
||||
}
|
||||
}
|
||||
fun updateAppHidden(appInfo: AppInfo, appHidden: Boolean) {
|
||||
viewModelScope.launch {
|
||||
appInfoRepository.updateAppHidden(appInfo, appHidden)
|
||||
}
|
||||
}
|
||||
fun updateAppLock(appInfo: AppInfo, appLock: Boolean) {
|
||||
viewModelScope.launch {
|
||||
appInfoRepository.updateAppLock(appInfo, appLock)
|
||||
}
|
||||
}
|
||||
fun compareInstalledAppInfo() {
|
||||
viewModelScope.launch {
|
||||
appInfoRepository.compareInstalledApp()
|
||||
}
|
||||
}
|
||||
suspend fun updateAppOrder(appInfoList: List<AppInfo>) {
|
||||
withContext(Dispatchers.IO) {
|
||||
appInfoRepository.updateAppOrder(appInfoList)
|
||||
}
|
||||
}
|
||||
fun update(appInfo: AppInfo) {
|
||||
viewModelScope.launch {
|
||||
appInfoRepository.updateInfo(appInfo)
|
||||
}
|
||||
}
|
||||
fun searchAppInfo(query: String?) = appInfoRepository.searchNote(query)
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.github.droidworksstudio.launcher.viewmodel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class PreferenceViewModel @Inject constructor(
|
||||
private val preferenceHelper: PreferenceHelper)
|
||||
: ViewModel() {
|
||||
|
||||
val firstLaunchLiveData: MutableLiveData<Boolean> = MutableLiveData()
|
||||
val showStatusBarLiveData: MutableLiveData<Boolean> = MutableLiveData()
|
||||
val showTimeLiveData: MutableLiveData<Boolean> = MutableLiveData()
|
||||
val showDateLiveData: MutableLiveData<Boolean> = MutableLiveData()
|
||||
val showDailyWordLiveData: MutableLiveData<Boolean> = MutableLiveData()
|
||||
val showBatteryLiveData: MutableLiveData<Boolean> = MutableLiveData()
|
||||
val homeAppAlignmentLiveData: MutableLiveData<Int> = MutableLiveData()
|
||||
val homeDateAlignmentLiveData: MutableLiveData<Int> = MutableLiveData()
|
||||
val homeTimeAlignmentLiveData: MutableLiveData<Int> = MutableLiveData()
|
||||
val dateColorLiveData: MutableLiveData<Int> = MutableLiveData()
|
||||
val timeColorLiveData: MutableLiveData<Int> = MutableLiveData()
|
||||
val batteryColorLiveData: MutableLiveData<Int> = MutableLiveData()
|
||||
val dailyWordColorLiveData: MutableLiveData<Int> = MutableLiveData()
|
||||
val appColorLiveData: MutableLiveData<Int> = MutableLiveData()
|
||||
val dateTextSizeLiveData: MutableLiveData<Float> = MutableLiveData()
|
||||
val timeTextSizeLiveData: MutableLiveData<Float> = MutableLiveData()
|
||||
val appTextSizeLiveData: MutableLiveData<Float> = MutableLiveData()
|
||||
val tapLockScreenLiveData: MutableLiveData<Boolean> = MutableLiveData()
|
||||
|
||||
fun setFirstLaunch(firstLaunch: Boolean) {
|
||||
preferenceHelper.firstLaunch = firstLaunch
|
||||
firstLaunchLiveData.postValue(preferenceHelper.firstLaunch)
|
||||
}
|
||||
|
||||
fun setShowStatusBar(showStatusBar: Boolean) {
|
||||
preferenceHelper.showStatusBar = showStatusBar
|
||||
showStatusBarLiveData.postValue(preferenceHelper.showStatusBar)
|
||||
}
|
||||
|
||||
fun setShowTime(showTime: Boolean) {
|
||||
preferenceHelper.showTime = showTime
|
||||
showTimeLiveData.postValue(preferenceHelper.showTime)
|
||||
}
|
||||
|
||||
fun setShowDate(showDate: Boolean) {
|
||||
preferenceHelper.showDate = showDate
|
||||
showDateLiveData.postValue(preferenceHelper.showDate)
|
||||
}
|
||||
|
||||
fun setShowBattery(showBattery: Boolean){
|
||||
preferenceHelper.showBattery = showBattery
|
||||
showBatteryLiveData.postValue(preferenceHelper.showBattery)
|
||||
}
|
||||
|
||||
fun setShowDailyWord(showDailyWord: Boolean) {
|
||||
preferenceHelper.showDailyWord = showDailyWord
|
||||
showDailyWordLiveData.postValue(preferenceHelper.showDailyWord)
|
||||
}
|
||||
|
||||
fun setDailyWordColor(dailyWordColor: Int) {
|
||||
preferenceHelper.dailyWordColor = dailyWordColor
|
||||
dailyWordColorLiveData.postValue(preferenceHelper.dailyWordColor)
|
||||
}
|
||||
|
||||
fun setAppColor(appColor: Int) {
|
||||
preferenceHelper.appColor = appColor
|
||||
appColorLiveData.postValue(preferenceHelper.appColor)
|
||||
}
|
||||
|
||||
fun setDateColor(dateColor: Int) {
|
||||
preferenceHelper.dateColor = dateColor
|
||||
dateColorLiveData.postValue(preferenceHelper.dateColor)
|
||||
}
|
||||
|
||||
fun setTimeColor(timeColor: Int) {
|
||||
preferenceHelper.timeColor = timeColor
|
||||
timeColorLiveData.postValue(preferenceHelper.timeColor)
|
||||
}
|
||||
|
||||
fun setBatteryColor(batteryColor: Int){
|
||||
preferenceHelper.batteryColor = batteryColor
|
||||
batteryColorLiveData.postValue(preferenceHelper.batteryColor)
|
||||
}
|
||||
|
||||
fun setHomeAppAlignment(homeAppAlignment: Int) {
|
||||
preferenceHelper.homeAppAlignment = homeAppAlignment
|
||||
homeAppAlignmentLiveData.postValue(preferenceHelper.homeAppAlignment)
|
||||
}
|
||||
|
||||
fun setHomeDateAlignment(homeDateAlignment: Int) {
|
||||
preferenceHelper.homeDateAlignment = homeDateAlignment
|
||||
homeDateAlignmentLiveData.postValue(preferenceHelper.homeDateAlignment)
|
||||
}
|
||||
|
||||
fun setHomeTimeAppAlignment(homeTimeAlignment: Int) {
|
||||
preferenceHelper.homeTimeAlignment = homeTimeAlignment
|
||||
homeTimeAlignmentLiveData.postValue(preferenceHelper.homeTimeAlignment)
|
||||
}
|
||||
|
||||
fun setDateTextSize(dateTextSize: Float) {
|
||||
preferenceHelper.dateTextSize = dateTextSize
|
||||
dateTextSizeLiveData.postValue(preferenceHelper.dateTextSize)
|
||||
}
|
||||
|
||||
fun setTimeTextSize(timeTextSize: Float) {
|
||||
preferenceHelper.timeTextSize = timeTextSize
|
||||
timeTextSizeLiveData.postValue(preferenceHelper.timeTextSize)
|
||||
}
|
||||
|
||||
fun setAppTextSize(appTextSize: Float) {
|
||||
preferenceHelper.appTextSize = appTextSize
|
||||
appTextSizeLiveData.postValue(preferenceHelper.appTextSize)
|
||||
}
|
||||
|
||||
fun setDoubleTapLock(tapLockScreen: Boolean){
|
||||
preferenceHelper.tapLockScreen = tapLockScreen
|
||||
tapLockScreenLiveData.postValue((preferenceHelper.tapLockScreen))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user