Weather is functional

This commit is contained in:
ottoptj 2024-08-01 06:12:35 +03:00
commit f23d71a477
13 changed files with 406 additions and 144 deletions

View file

@ -112,15 +112,15 @@ class AppMenuAdapter(
val app = apps[position] val app = apps[position]
if (app.second.second != 0) { if (app.second.second != 0) {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_work_app, null),null,null,null) holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_work_app, null),null, ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null)
} }
else { else {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null,null,null) holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null,ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null)
} }
when (preferences.getString("appMenuAlignment", "left")) { when (preferences.getString("appMenuAlignment", "left")) {
"left" -> { "left" -> {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(holder.textView.compoundDrawables.filterNotNull().first(),null, null, null) holder.textView.setCompoundDrawablesWithIntrinsicBounds(holder.textView.compoundDrawables.filterNotNull().first(),null, ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null), null)
holder.textView.gravity = Gravity.CENTER_VERTICAL or Gravity.START holder.textView.gravity = Gravity.CENTER_VERTICAL or Gravity.START
} }
"center" -> { "center" -> {
@ -129,7 +129,7 @@ class AppMenuAdapter(
} }
"right" -> { "right" -> {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(null,null, holder.textView.compoundDrawables.filterNotNull().first(), null) holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null, holder.textView.compoundDrawables.filterNotNull().first(), null)
holder.textView.gravity = Gravity.CENTER_VERTICAL or Gravity.END holder.textView.gravity = Gravity.CENTER_VERTICAL or Gravity.END
} }
} }

View file

@ -7,21 +7,21 @@ import android.content.IntentFilter
import android.os.BatteryManager import android.os.BatteryManager
import android.widget.TextClock import android.widget.TextClock
class BatteryReceiver(private val dateText: TextClock) : BroadcastReceiver() { class BatteryReceiver(private val activity: MainActivity) : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
intent?.let { intent?.let {
val level = it.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) val level = it.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
val scale = it.getIntExtra(BatteryManager.EXTRA_SCALE, -1) val scale = it.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
val batteryPct = level * 100 / scale.toFloat() val batteryPct = level * 100 / scale.toFloat()
dateText.format12Hour = "dd MMM yyyy | ${batteryPct.toInt()}%" activity.modifyDate("${batteryPct.toInt()}%", 2)
dateText.format24Hour = "dd MMM yyyy | ${batteryPct.toInt()}%"
} }
} }
companion object { companion object {
fun register(context: Context, textView: TextClock): BatteryReceiver { fun register(context: Context, activity: MainActivity): BatteryReceiver {
val receiver = BatteryReceiver(textView) val receiver = BatteryReceiver(activity)
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
context.registerReceiver(receiver, filter) context.registerReceiver(receiver, filter)
return receiver return receiver

View file

@ -35,7 +35,7 @@ class HiddenAppsAdapter(
inner class AppViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class AppViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val listItem: FrameLayout = itemView.findViewById(R.id.list_item) private val listItem: FrameLayout = itemView.findViewById(R.id.list_item)
val textView: TextView = listItem.findViewById(R.id.app_name) val textView: TextView = listItem.findViewById(R.id.app_name)
val actionMenuLayout: LinearLayout = listItem.findViewById(R.id.action_menu) private val actionMenuLayout: LinearLayout = listItem.findViewById(R.id.action_menu)
private val editView: LinearLayout = listItem.findViewById(R.id.rename_view) private val editView: LinearLayout = listItem.findViewById(R.id.rename_view)
val editText: EditText = editView.findViewById(R.id.app_name_edit) val editText: EditText = editView.findViewById(R.id.app_name_edit)
@ -103,14 +103,6 @@ class HiddenAppsAdapter(
val appInfo = app.first.activityInfo.applicationInfo val appInfo = app.first.activityInfo.applicationInfo
holder.textView.text = sharedPreferenceManager.getAppName(activity, app.first.applicationInfo.packageName,app.second.second, holder.itemView.context.packageManager.getApplicationLabel(appInfo)) holder.textView.text = sharedPreferenceManager.getAppName(activity, app.first.applicationInfo.packageName,app.second.second, holder.itemView.context.packageManager.getApplicationLabel(appInfo))
holder.editText.setText(holder.textView.text)
if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) {
holder.actionMenuLayout.findViewById<TextView>(R.id.uninstall).visibility = View.GONE
}
else {
holder.actionMenuLayout.findViewById<TextView>(R.id.uninstall).visibility = View.VISIBLE
}
holder.textView.visibility = View.VISIBLE holder.textView.visibility = View.VISIBLE
} }

View file

@ -31,6 +31,7 @@ class HiddenAppsFragment : Fragment(), HiddenAppsAdapter.OnItemClickListener {
private val appUtils = AppUtils() private val appUtils = AppUtils()
private val sharedPreferenceManager = SharedPreferenceManager() private val sharedPreferenceManager = SharedPreferenceManager()
private var adapter: HiddenAppsAdapter? = null private var adapter: HiddenAppsAdapter? = null
private var stringUtils = StringUtils()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -89,7 +90,7 @@ class HiddenAppsFragment : Fragment(), HiddenAppsAdapter.OnItemClickListener {
private fun filterItems(query: String?) { private fun filterItems(query: String?) {
val cleanQuery = query?.clean() val cleanQuery = stringUtils.cleanString(query)
val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>() val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
val updatedApps = appUtils.getHiddenApps(requireActivity()) val updatedApps = appUtils.getHiddenApps(requireActivity())
@ -104,9 +105,11 @@ class HiddenAppsFragment : Fragment(), HiddenAppsAdapter.OnItemClickListener {
newFilteredApps.addAll(updatedApps) newFilteredApps.addAll(updatedApps)
} else { } else {
updatedApps.forEach { updatedApps.forEach {
val cleanItemText = sharedPreferenceManager.getAppName(requireActivity(), it.first.applicationInfo.packageName, it.second.second, requireActivity().packageManager.getApplicationLabel(it.first.applicationInfo)).toString().clean() val cleanItemText = stringUtils.cleanString(sharedPreferenceManager.getAppName(requireActivity(), it.first.applicationInfo.packageName, it.second.second, requireActivity().packageManager.getApplicationLabel(it.first.applicationInfo)).toString())
if (cleanItemText.contains(cleanQuery, ignoreCase = true)) { if (cleanItemText != null) {
newFilteredApps.add(it) if (cleanItemText.contains(cleanQuery, ignoreCase = true)) {
newFilteredApps.add(it)
}
} }
} }
} }
@ -116,10 +119,6 @@ class HiddenAppsFragment : Fragment(), HiddenAppsAdapter.OnItemClickListener {
adapter?.updateApps(newFilteredApps) adapter?.updateApps(newFilteredApps)
} }
private fun String.clean(): String {
return this.replace("[^a-zA-Z0-9]".toRegex(), "")
}
private fun showConfirmationDialog(appInfo: LauncherActivityInfo, appName: String, profile: Int) { private fun showConfirmationDialog(appInfo: LauncherActivityInfo, appName: String, profile: Int) {
AlertDialog.Builder(requireContext()).apply { AlertDialog.Builder(requireContext()).apply {
setTitle("Confirmation") setTitle("Confirmation")

View file

@ -0,0 +1,109 @@
package eu.ottop.yamlauncher
import android.app.AlertDialog
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.fragment.app.setFragmentResult
import androidx.preference.Preference
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class LocationFragment : Fragment(), LocationListAdapter.OnItemClickListener {
private var adapter: LocationListAdapter? = null
private val weatherSystem = WeatherSystem()
private val sharedPreferenceManager = SharedPreferenceManager()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_location, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val searchView = view.findViewById<EditText>(R.id.locationSearch)
adapter = LocationListAdapter(requireContext(), weatherSystem.getSearchedLocations(
searchView.text.toString()
), this)
val recyclerView = view.findViewById<RecyclerView>(R.id.locationrecycler)
val appMenuEdgeFactory = AppMenuEdgeFactory(requireActivity())
recyclerView.edgeEffectFactory = appMenuEdgeFactory
recyclerView.adapter = adapter
recyclerView.scrollToPosition(0)
recyclerView.addOnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom ->
if (bottom - top > oldBottom - oldTop) {
searchView.clearFocus()
}
}
searchView.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) {
println(searchView.text.toString())
CoroutineScope(Dispatchers.IO).launch {
val locations = weatherSystem.getSearchedLocations(
searchView.text.toString()
)
withContext(Dispatchers.Main) {
adapter?.updateApps(locations)
}
}
}
override fun afterTextChanged(s: Editable?) {
}
})
}
private fun showConfirmationDialog(appName: String?, latitude: String?, longitude: String?) {
AlertDialog.Builder(requireContext()).apply {
setTitle("Confirmation")
setMessage("Are you sure you want to select $appName?")
setPositiveButton("Yes") { _, _ ->
// Perform action on confirmation
performConfirmedAction(appName, latitude, longitude)
}
setNegativeButton("Cancel") { _, _ ->
}
}.create().show()
}
private fun performConfirmedAction(appName: String?, latitude: String?, longitude: String?) {
sharedPreferenceManager.setWeatherLocation(requireContext(), "latitude=${latitude}&longitude=${longitude}", appName)
requireActivity().supportFragmentManager.popBackStack()
}
override fun onItemClick(name: String?, latitude: String?, longitude: String?) {
showConfirmationDialog(name, latitude, longitude)
}
}

View file

@ -2,9 +2,7 @@ package eu.ottop.yamlauncher
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherActivityInfo
import android.os.UserHandle
import android.view.Gravity import android.view.Gravity
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -13,84 +11,37 @@ import android.widget.EditText
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
class LocationListAdapter( class LocationListAdapter(
private val activity: Context, activity: Context,
var apps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>, var apps: MutableList<Map<String, String>>,
private val itemClickListener: OnItemClickListener, private val itemClickListener: OnItemClickListener
private val shortcutListener: OnShortcutListener,
private val itemLongClickListener: OnItemLongClickListener
) : ) :
RecyclerView.Adapter<LocationListAdapter.AppViewHolder>() { RecyclerView.Adapter<LocationListAdapter.AppViewHolder>() {
var menuMode: String = "app" private var preferences = PreferenceManager.getDefaultSharedPreferences(activity)
var shortcutTextView: TextView? = null
private val sharedPreferenceManager = SharedPreferenceManager()
private var preferences = PreferenceManager.getDefaultSharedPreferences(activity)
interface OnItemClickListener { interface OnItemClickListener {
fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle) fun onItemClick(name: String?, latitude: String?, longitude: String?)
}
interface OnShortcutListener {
fun onShortcut(appInfo: LauncherActivityInfo, userHandle: UserHandle, textView: TextView, userProfile: Int, shortcutView: TextView)
}
interface OnItemLongClickListener {
fun onItemLongClick(
appInfo: LauncherActivityInfo,
userHandle: UserHandle,
userProfile: Int,
textView: TextView,
actionMenuLayout: LinearLayout,
editView: LinearLayout,
position: Int
)
} }
inner class AppViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class AppViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val listItem: FrameLayout = itemView.findViewById(R.id.list_item) private val listItem: ConstraintLayout = itemView.findViewById(R.id.location_place)
val textView: TextView = listItem.findViewById(R.id.app_name) val textView: TextView = listItem.findViewById(R.id.location_name)
val actionMenuLayout: LinearLayout = listItem.findViewById(R.id.action_menu) val regionText: TextView = listItem.findViewById(R.id.region_name)
private val editView: LinearLayout = listItem.findViewById(R.id.rename_view)
val editText: EditText = editView.findViewById(R.id.app_name_edit)
init { init {
actionMenuLayout.visibility = View.INVISIBLE
editView.visibility = View.INVISIBLE
textView.setOnClickListener {
val position = bindingAdapterPosition
val app = apps[position].first
if (menuMode == "shortcut") {
shortcutListener.onShortcut(app, apps[position].second.first, textView, apps[position].second.second, shortcutTextView!!)
}
else if (menuMode == "app") {
itemClickListener.onItemClick(app, apps[position].second.first)
}
}
if (menuMode == "app") {
textView.setOnLongClickListener {
val position = bindingAdapterPosition
val app = apps[position].first
itemLongClickListener.onItemLongClick(
app,
apps[position].second.first,
apps[position].second.second,
textView,
actionMenuLayout,
editView,
position
)
return@setOnLongClickListener true
}
listItem.setOnClickListener {
val position = bindingAdapterPosition
val name = apps[position]["name"]
val latitude = apps[position]["latitude"]
val longitude = apps[position]["longitude"]
itemClickListener.onItemClick(name, latitude, longitude)
} }
} }
@ -98,63 +49,49 @@ class LocationListAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder {
val view = LayoutInflater.from(parent.context) val view = LayoutInflater.from(parent.context)
.inflate(R.layout.app_item_layout, parent, false) .inflate(R.layout.location_item_layout, parent, false)
return AppViewHolder(view) return AppViewHolder(view)
} }
override fun onBindViewHolder(holder: AppViewHolder, position: Int) { override fun onBindViewHolder(holder: AppViewHolder, position: Int) {
val app = apps[position] val app = apps[position]
if (app.second.second != 0) {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_work_app, null),null,null,null)
}
else {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null,null,null)
}
when (preferences.getString("appMenuAlignment", "left")) { when (preferences.getString("appMenuAlignment", "left")) {
"left" -> { "left" -> {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(holder.textView.compoundDrawables.filterNotNull().first(),null, null, null)
holder.textView.gravity = Gravity.CENTER_VERTICAL or Gravity.START holder.textView.gravity = Gravity.CENTER_VERTICAL or Gravity.START
holder.regionText.gravity = Gravity.CENTER_VERTICAL or Gravity.START
} }
"center" -> { "center" -> {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(holder.textView.compoundDrawables.filterNotNull().first(),null,holder.textView.compoundDrawables.filterNotNull().first(), null)
holder.textView.gravity = Gravity.CENTER holder.textView.gravity = Gravity.CENTER
holder.regionText.gravity = Gravity.CENTER
} }
"right" -> { "right" -> {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(null,null, holder.textView.compoundDrawables.filterNotNull().first(), null)
holder.textView.gravity = Gravity.CENTER_VERTICAL or Gravity.END holder.textView.gravity = Gravity.CENTER_VERTICAL or Gravity.END
holder.regionText.gravity = Gravity.CENTER_VERTICAL or Gravity.END
} }
} }
when (preferences.getString("appMenuSize", "medium")) { when (preferences.getString("appMenuSize", "medium")) {
"small" -> { "small" -> {
holder.textView.textSize = 24F holder.textView.textSize = 24F
holder.editText.textSize = 24F holder.regionText.textSize = 14F
} }
"medium" -> { "medium" -> {
holder.textView.textSize = 26F holder.textView.textSize = 26F
holder.editText.textSize = 26F holder.regionText.textSize = 16F
} }
"large" -> { "large" -> {
holder.textView.textSize = 28F holder.textView.textSize = 28F
holder.editText.textSize = 28F holder.regionText.textSize = 18F
} }
} }
val appInfo = app.first.activityInfo.applicationInfo holder.textView.text = app["name"]
holder.textView.text = sharedPreferenceManager.getAppName(activity, app.first.applicationInfo.packageName,app.second.second, holder.itemView.context.packageManager.getApplicationLabel(appInfo)) holder.regionText.text = "${app["region"]}${app["country"]}"
holder.editText.setText(holder.textView.text)
if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) {
holder.actionMenuLayout.findViewById<TextView>(R.id.uninstall).visibility = View.GONE
}
else {
holder.actionMenuLayout.findViewById<TextView>(R.id.uninstall).visibility = View.VISIBLE
}
holder.textView.visibility = View.VISIBLE holder.textView.visibility = View.VISIBLE
} }
@ -164,8 +101,9 @@ class LocationListAdapter(
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun updateApps(newApps: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>) { fun updateApps(newApps: MutableList<Map<String, String>>) {
apps = newApps.toMutableList() apps.clear()
apps = newApps
notifyDataSetChanged() notifyDataSetChanged()
} }
} }

View file

@ -57,6 +57,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private lateinit var searchView: EditText private lateinit var searchView: EditText
private var adapter: AppMenuAdapter? = null private var adapter: AppMenuAdapter? = null
private var job: Job? = null private var job: Job? = null
private var weatherJob: Job? = null
val cameraIntent = Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) val cameraIntent = Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
val phoneIntent = Intent(Intent.ACTION_DIAL) val phoneIntent = Intent(Intent.ACTION_DIAL)
private lateinit var batteryReceiver: BatteryReceiver private lateinit var batteryReceiver: BatteryReceiver
@ -79,6 +80,12 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private lateinit var preferences: SharedPreferences private lateinit var preferences: SharedPreferences
private val stringUtils = StringUtils()
private var dateElements = mutableListOf<String>()
private val weatherSystem = WeatherSystem()
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -105,6 +112,8 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
dateText = findViewById(R.id.text_date) dateText = findViewById(R.id.text_date)
dateElements = mutableListOf(dateText.format12Hour.toString(), dateText.format24Hour.toString(), "", "")
setClockAlignment(preferences.getString("clockAlignment", "left"), clock.id, clockMargin) setClockAlignment(preferences.getString("clockAlignment", "left"), clock.id, clockMargin)
setupApps() setupApps()
@ -121,7 +130,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
setSearchSize(preferences.getString("searchSize", "medium")) setSearchSize(preferences.getString("searchSize", "medium"))
batteryReceiver = BatteryReceiver.register(this, dateText) batteryReceiver = BatteryReceiver.register(this, this@MainActivity)
binding.homeView.setOnTouchListener { _, event -> binding.homeView.setOnTouchListener { _, event ->
gestureDetector.onTouchEvent(event) gestureDetector.onTouchEvent(event)
@ -137,6 +146,25 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
fun modifyDate(value: String, index: Int) {
dateElements[index] = value
dateText.format12Hour = "${dateElements[0]}${stringUtils.addStartTextIfNotEmpty(dateElements[2], " | ")}${stringUtils.addStartTextIfNotEmpty(dateElements[3], " | ")}"
dateText.format24Hour = "${dateElements[1]}${stringUtils.addStartTextIfNotEmpty(dateElements[2], " | ")}${stringUtils.addStartTextIfNotEmpty(dateElements[3], " | ")}"
}
private fun startWeatherMonitor() {
weatherJob?.cancel()
weatherJob = CoroutineScope(Dispatchers.IO).launch {
while (true) {
val currentWeather = weatherSystem.getTemp(this@MainActivity)
withContext(Dispatchers.Main) {
modifyDate(stringUtils.addEndTextIfNotEmpty(currentWeather, "°C"), 3)
}
delay(300000)
}
}
}
override fun onSharedPreferenceChanged(preferences: SharedPreferences?, key: String?) { override fun onSharedPreferenceChanged(preferences: SharedPreferences?, key: String?) {
when (key) { when (key) {
@ -190,6 +218,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
startTask() startTask()
startWeatherMonitor()
// Keyboard is sometimes open when going back to the app, so close it. // Keyboard is sometimes open when going back to the app, so close it.
closeKeyboard() closeKeyboard()
@ -392,7 +421,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private suspend fun filterItems(query: String?) { private suspend fun filterItems(query: String?) {
val cleanQuery = query?.clean() val cleanQuery = stringUtils.cleanString(query)
val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>() val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
val updatedApps = appUtils.getInstalledApps(this@MainActivity) val updatedApps = appUtils.getInstalledApps(this@MainActivity)
@ -408,9 +437,11 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
newFilteredApps.addAll(installedApps) newFilteredApps.addAll(installedApps)
} else { } else {
updatedApps.forEach { updatedApps.forEach {
val cleanItemText = sharedPreferenceManager.getAppName(this@MainActivity, it.first.applicationInfo.packageName, it.second.second, packageManager.getApplicationLabel(it.first.applicationInfo)).toString().clean() val cleanItemText = stringUtils.cleanString(sharedPreferenceManager.getAppName(this@MainActivity, it.first.applicationInfo.packageName, it.second.second, packageManager.getApplicationLabel(it.first.applicationInfo)).toString())
if (cleanItemText.contains(cleanQuery, ignoreCase = true)) { if (cleanItemText != null) {
newFilteredApps.add(it) if (cleanItemText.contains(cleanQuery, ignoreCase = true)) {
newFilteredApps.add(it)
}
} }
} }
} }
@ -425,10 +456,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
} }
private fun String.clean(): String {
return this.replace("[^a-zA-Z0-9]".toRegex(), "")
}
private fun startTask() { private fun startTask() {
job?.cancel() job?.cancel()
job = CoroutineScope(Dispatchers.Default).launch { job = CoroutineScope(Dispatchers.Default).launch {

View file

@ -1,38 +1,64 @@
package eu.ottop.yamlauncher package eu.ottop.yamlauncher
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.setFragmentResultListener
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
class SettingsFragment : PreferenceFragmentCompat() { class SettingsFragment : PreferenceFragmentCompat() {
private var manualLocationPref: Preference? = null
private val sharedPreferenceManager = SharedPreferenceManager()
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey) setPreferencesFromResource(R.xml.root_preferences, rootKey)
val weatherSystem = WeatherSystem()
val gpsLocationPref: SwitchPreference? = findPreference("gps_location") val gpsLocationPref: SwitchPreference? = findPreference("gps_location")
val manualLocationPref: Preference? = findPreference("manual_location") manualLocationPref = findPreference("manual_location")
manualLocationPref?.summary = sharedPreferenceManager.getWeatherRegion(requireContext())
if (gpsLocationPref != null && manualLocationPref != null) { if (gpsLocationPref != null && manualLocationPref != null) {
// Initial setup // Initial setup
manualLocationPref.isEnabled = !gpsLocationPref.isChecked manualLocationPref?.isEnabled = !gpsLocationPref.isChecked
// Set up a listener to update the enabled state of manualLocationPref // Set up a listener to update the enabled state of manualLocationPref
gpsLocationPref.onPreferenceChangeListener = gpsLocationPref.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, newValue -> Preference.OnPreferenceChangeListener { _, newValue ->
val isGpsEnabled = newValue as Boolean val isGpsEnabled = newValue as Boolean
manualLocationPref.isEnabled = !isGpsEnabled if (isGpsEnabled) {
weatherSystem.setGpsLocation(requireActivity())
}
manualLocationPref?.isEnabled = !isGpsEnabled
true // Returning true means the change is persisted true // Returning true means the change is persisted
} }
manualLocationPref?.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
requireActivity().supportFragmentManager
.beginTransaction()
.replace(R.id.settings_layout, LocationFragment())
.addToBackStack(null)
.commit()
true
}
} }
findPreference<Preference?>("hidden_apps")?.onPreferenceClickListener = findPreference<Preference?>("hidden_apps")?.onPreferenceClickListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceClickListener {
activity?.supportFragmentManager requireActivity().supportFragmentManager
?.beginTransaction() .beginTransaction()
?.replace(R.id.settings_layout, HiddenAppsFragment()) .replace(R.id.settings_layout, HiddenAppsFragment())
?.addToBackStack(null) .addToBackStack(null)
?.commit() .commit()
true } true }
} }
override fun onResume() {
super.onResume()
manualLocationPref?.summary = sharedPreferenceManager.getWeatherRegion(requireContext())
}
} }

View file

@ -60,17 +60,25 @@ class SharedPreferenceManager {
editor.apply() editor.apply()
} }
fun setWeatherLocation(cont: Context, location: String) { fun setWeatherLocation(cont: Context, location: String, region: String?) {
val editor = cont.getSharedPreferences("weather_location", AppCompatActivity.MODE_PRIVATE).edit() val editor = cont.getSharedPreferences("weather_location", AppCompatActivity.MODE_PRIVATE).edit()
val key = "location" val key = "location"
val regionKey = "location_region"
editor.putString(key, location) editor.putString(key, location)
editor.putString(regionKey, region)
editor.apply() editor.apply()
} }
fun getWeatherLocation(cont: Context) : String? { fun getWeatherLocation(cont: Context) : String? {
val sharedPreferences = cont.getSharedPreferences("weather_location", AppCompatActivity.MODE_PRIVATE) val sharedPreferences = cont.getSharedPreferences("weather_location", AppCompatActivity.MODE_PRIVATE)
val key = "location" val key = "location"
return sharedPreferences.getString(key, null) return sharedPreferences.getString(key, "")
}
fun getWeatherRegion(cont: Context) : String? {
val sharedPreferences = cont.getSharedPreferences("weather_location", AppCompatActivity.MODE_PRIVATE)
val key = "location_region"
return sharedPreferences.getString(key, "")
} }
fun setClockAlignment(cont: Context, alignment: Int) { fun setClockAlignment(cont: Context, alignment: Int) {

View file

@ -0,0 +1,17 @@
package eu.ottop.yamlauncher
class StringUtils {
fun addEndTextIfNotEmpty(value: String, addition: String): String {
return if (value.isNotEmpty()) "$value$addition" else value
}
fun addStartTextIfNotEmpty(value: String, addition: String): String {
return if (value.isNotEmpty()) "$addition$value" else value
}
fun cleanString(string: String?) : String? {
return string?.replace("[^a-zA-Z0-9]".toRegex(), "")
}
}

View file

@ -10,9 +10,7 @@ import android.location.LocationManager
import android.widget.Toast import android.widget.Toast
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.json.JSONObject import org.json.JSONObject
import java.net.HttpURLConnection import java.net.HttpURLConnection
@ -21,8 +19,9 @@ import java.net.URL
class WeatherSystem { class WeatherSystem {
private val sharedPreferenceManager = SharedPreferenceManager() private val sharedPreferenceManager = SharedPreferenceManager()
private val stringUtils = StringUtils()
fun getWeatherForCurrentLocation(activity: Activity) { fun setGpsLocation(activity: Activity) {
val locationManager = activity.getSystemService(Context.LOCATION_SERVICE) as LocationManager val locationManager = activity.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val locationListener = object : LocationListener { val locationListener = object : LocationListener {
@ -49,18 +48,50 @@ class WeatherSystem {
if (currentLocation != null) { if (currentLocation != null) {
sharedPreferenceManager.setWeatherLocation(activity, "latitude=${currentLocation.latitude}&longitude=${currentLocation.longitude}") sharedPreferenceManager.setWeatherLocation(activity, "latitude=${currentLocation.latitude}&longitude=${currentLocation.longitude}", sharedPreferenceManager.getWeatherRegion(activity))
} }
else { else {
Toast.makeText(activity, "Unable to get location", Toast.LENGTH_SHORT).show() Toast.makeText(activity, "Unable to get location", Toast.LENGTH_SHORT).show()
} }
} }
fun getTemp(context: Context) { // Run within Dispatchers.IO from the outside (doesn't refresh properly otherwise)
CoroutineScope(Dispatchers.IO).launch { fun getSearchedLocations(searchTerm: String?) : MutableList<Map<String, String>> {
val foundLocations = mutableListOf<Map<String, String>>()
val url = URL("https://geocoding-api.open-meteo.com/v1/search?name=$searchTerm&count=50&language=en&format=json")
with(url.openConnection() as HttpURLConnection) {
requestMethod = "GET"
try {
inputStream.bufferedReader().use {
val response = it.readText()
println("yo")
val jsonObject = JSONObject(response)
val resultArray = jsonObject.getJSONArray("results")
for (i in 0 until resultArray.length()) {
val resultObject: JSONObject = resultArray.getJSONObject(i)
foundLocations.add(mapOf(
"name" to resultObject.getString("name"),
"latitude" to resultObject.getDouble("latitude").toString(),
"longitude" to resultObject.getDouble("longitude").toString(),
"country" to resultObject.optString("country", resultObject.optString("country_code","")),
"region" to stringUtils.addEndTextIfNotEmpty(resultObject.optString("admin2", resultObject.optString("admin1",resultObject.optString("admin3",""))), ", ")
))
}
}
}catch (e: Exception){
e.printStackTrace()
}
}
return foundLocations
}
suspend fun getTemp(context: Context) : String {
val location = sharedPreferenceManager.getWeatherLocation(context) val location = sharedPreferenceManager.getWeatherLocation(context)
if (location != null) { if (location != null) {
val url = URL("https://api.open-meteo.com/v1/forecast?$location&current=temperature_2m") val url = URL("https://api.open-meteo.com/v1/forecast?$location&current=temperature_2m")
@ -73,9 +104,9 @@ class WeatherSystem {
val jsonObject = JSONObject(response) val jsonObject = JSONObject(response)
val currentData = jsonObject.getJSONObject("current") val currentData = jsonObject.getJSONObject("current")
val currentWeather = currentData.getInt("temperature_2m")
println("Field1: $currentWeather") return currentData.getInt("temperature_2m").toString()
} }
} }
} }
@ -84,7 +115,8 @@ class WeatherSystem {
Toast.makeText(context, "No weather location set", Toast.LENGTH_SHORT).show() Toast.makeText(context, "No weather location set", Toast.LENGTH_SHORT).show()
} }
} }
}
return ""
} }
} }

View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/manual_location_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="vertical"
android:visibility="visible">
<Space
android:layout_width="match_parent"
android:layout_height="60dp" />
<TextView
android:id="@+id/location_menutitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="false"
android:gravity="start"
android:paddingLeft="40dp"
android:paddingTop="20dp"
android:paddingRight="40dp"
android:paddingBottom="20dp"
android:text="Find your city"
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
android:textColor="#C1F3F3F3"
android:textSize="36sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/locationrecycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clipToPadding="false"
android:fadingEdgeLength="20dp"
android:padding="0dp"
android:requiresFadingEdge="vertical"
android:scrollbars="none"
app:layoutManager="LinearLayoutManager">
</androidx.recyclerview.widget.RecyclerView>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/locationSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"
android:layout_weight="0.1"
android:background="@android:color/transparent"
android:cursorVisible="true"
android:drawableStart="@android:drawable/ic_menu_search"
android:drawablePadding="8dp"
android:editTextColor="#f3f3f3"
android:hint="@string/search"
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
android:textSize="25sp"
tools:ignore="RtlCompat" />
</LinearLayout>

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/location_place"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/location_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:clickable="false"
android:drawablePadding="3dp"
android:gravity="start"
android:paddingLeft="35dp"
android:paddingTop="20dp"
android:paddingRight="35dp"
android:paddingBottom="00dp"
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
android:textColor="#F3F3F3"
android:textSize="28sp"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/region_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:clickable="false"
android:drawablePadding="3dp"
android:gravity="start"
android:paddingLeft="35dp"
android:paddingTop="0dp"
android:paddingRight="35dp"
android:paddingBottom="20dp"
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
android:textColor="#C3C3C3"
android:textSize="14sp"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="@+id/location_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/location_name" />
</androidx.constraintlayout.widget.ConstraintLayout>