Added single multiple clock
This commit is contained in:
@ -84,6 +84,10 @@ object Preferences : KotprefModel() {
|
||||
|
||||
var weatherIconPack by intPref(default = Constants.WeatherIconPack.DEFAULT.rawValue)
|
||||
|
||||
// Clock
|
||||
var altTimezoneLabel by stringPref(default = "")
|
||||
var altTimezoneId by stringPref(default = "")
|
||||
|
||||
// Global
|
||||
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
|
||||
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 18f)
|
||||
|
@ -0,0 +1,40 @@
|
||||
package com.tommasoberlose.anotherwidget.network
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.chibatching.kotpref.Kotpref
|
||||
import com.google.gson.internal.LinkedTreeMap
|
||||
import com.haroldadmin.cnradapter.NetworkResponse
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.global.Constants
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
||||
import com.tommasoberlose.anotherwidget.network.repository.TimeZonesRepository
|
||||
import com.tommasoberlose.anotherwidget.ui.fragments.MainFragment
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.lang.Exception
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class TimeZonesApi(val context: Context) {
|
||||
suspend fun getTimeZone(lat: String, long: String): String? {
|
||||
Kotpref.init(context)
|
||||
val repository = TimeZonesRepository()
|
||||
var id: String? = null
|
||||
|
||||
when (val response = repository.getTimeZone(lat, long)) {
|
||||
is NetworkResponse.Success -> {
|
||||
try {
|
||||
Log.d("ciao", response.body.toString())
|
||||
id = response.body["timezoneId"] as String
|
||||
|
||||
} catch(ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
}
|
@ -71,4 +71,13 @@ object ApiServices {
|
||||
@Query("lon") lon: String,
|
||||
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||
}
|
||||
|
||||
interface TimeZonesService {
|
||||
@GET("timezoneJSON")
|
||||
suspend fun getTimeZone(
|
||||
@Query("lat") lat: String,
|
||||
@Query("lng") lon: String,
|
||||
@Query("username") username: String = "tommaso.berlose",
|
||||
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.tommasoberlose.anotherwidget.network.repository
|
||||
|
||||
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
|
||||
import com.tommasoberlose.anotherwidget.network.api.ApiServices
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
||||
class TimeZonesRepository {
|
||||
|
||||
/* YR */
|
||||
private val apiService: ApiServices.TimeZonesService = getRetrofit().create(ApiServices.TimeZonesService::class.java)
|
||||
suspend fun getTimeZone(lat: String, long: String) = apiService.getTimeZone(lat, long)
|
||||
|
||||
companion object {
|
||||
private const val BASE_URL_YR = "http://api.geonames.org/"
|
||||
|
||||
private fun getRetrofit(): Retrofit {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(BASE_URL_YR)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(NetworkResponseAdapterFactory())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.activities.tabs
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.location.Address
|
||||
import android.location.Geocoder
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.chibatching.kotpref.bulk
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.tommasoberlose.anotherwidget.R
|
||||
import com.tommasoberlose.anotherwidget.databinding.ActivityTimeZoneSelectorBinding
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
import com.tommasoberlose.anotherwidget.network.TimeZonesApi
|
||||
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.tabs.TimeZoneSelectorViewModel
|
||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||
import com.tommasoberlose.anotherwidget.utils.toast
|
||||
import kotlinx.coroutines.*
|
||||
import net.idik.lib.slimadapter.SlimAdapter
|
||||
|
||||
class TimeZoneSelectorActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var adapter: SlimAdapter
|
||||
private lateinit var viewModel: TimeZoneSelectorViewModel
|
||||
private lateinit var binding: ActivityTimeZoneSelectorBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(TimeZoneSelectorViewModel::class.java)
|
||||
binding = ActivityTimeZoneSelectorBinding.inflate(layoutInflater)
|
||||
|
||||
binding.geonameCredits.movementMethod = LinkMovementMethod.getInstance()
|
||||
|
||||
binding.listView.setHasFixedSize(true)
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
binding.listView.layoutManager = mLayoutManager
|
||||
|
||||
adapter = SlimAdapter.create()
|
||||
adapter
|
||||
.register<String>(R.layout.custom_location_item) { _, injector ->
|
||||
injector
|
||||
.text(R.id.text, getString(R.string.no_time_zone_label))
|
||||
.clicked(R.id.text) {
|
||||
Preferences.bulk {
|
||||
altTimezoneId = ""
|
||||
altTimezoneLabel = ""
|
||||
}
|
||||
MainWidget.updateWidget(this@TimeZoneSelectorActivity)
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
.register<Address>(R.layout.custom_location_item) { item, injector ->
|
||||
injector.text(R.id.text, item.getAddressLine(0))
|
||||
injector.clicked(R.id.item) {
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val networkApi = TimeZonesApi(this@TimeZoneSelectorActivity)
|
||||
val id = networkApi.getTimeZone(item.latitude.toString(), item.longitude.toString())
|
||||
|
||||
if (id != null) {
|
||||
Preferences.bulk {
|
||||
altTimezoneId = id
|
||||
altTimezoneLabel = item.locality
|
||||
}
|
||||
MainWidget.updateWidget(this@TimeZoneSelectorActivity)
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
} else {
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
toast(getString(R.string.time_zone_search_error_message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.attachTo(binding.listView)
|
||||
|
||||
|
||||
viewModel.addresses.observe(this, Observer {
|
||||
adapter.updateData(listOf("Default") + it)
|
||||
})
|
||||
|
||||
setupListener()
|
||||
subscribeUi(binding, viewModel)
|
||||
|
||||
binding.location.requestFocus()
|
||||
|
||||
setContentView(binding.root)
|
||||
}
|
||||
|
||||
private var searchJob: Job? = null
|
||||
|
||||
private fun subscribeUi(binding: ActivityTimeZoneSelectorBinding, viewModel: TimeZoneSelectorViewModel) {
|
||||
binding.viewModel = viewModel
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
viewModel.addresses.observe(this, Observer {
|
||||
adapter.updateData(listOf("Default") + it)
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
})
|
||||
|
||||
viewModel.locationInput.observe(this, Observer { location ->
|
||||
binding.loader.visibility = View.VISIBLE
|
||||
searchJob?.cancel()
|
||||
searchJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(200)
|
||||
val list = if (location == null || location == "") {
|
||||
viewModel.addresses.value!!
|
||||
} else {
|
||||
val coder = Geocoder(this@TimeZoneSelectorActivity)
|
||||
try {
|
||||
coder.getFromLocationName(location, 10) as ArrayList<Address>
|
||||
} catch (ignored: Exception) {
|
||||
emptyList<Address>()
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
viewModel.addresses.value = list
|
||||
binding.loader.visibility = View.INVISIBLE
|
||||
}
|
||||
|
||||
}
|
||||
binding.clearSearch.isVisible = location.isNotBlank()
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupListener() {
|
||||
binding.actionBack.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
binding.clearSearch.setOnClickListener {
|
||||
viewModel.locationInput.value = ""
|
||||
}
|
||||
}
|
||||
}
|
@ -249,6 +249,32 @@ class MainFragment : Fragment() {
|
||||
)
|
||||
binding.widgetDetail.timeAmPm.isVisible = Preferences.showAMPMIndicator
|
||||
|
||||
// Timezones
|
||||
if (Preferences.altTimezoneId != "" && Preferences.altTimezoneLabel != "") {
|
||||
// Clock
|
||||
binding.widgetDetail.altTimezoneTime.timeZone = Preferences.altTimezoneId
|
||||
binding.widgetDetail.altTimezoneTimeAmPm.timeZone = Preferences.altTimezoneId
|
||||
binding.widgetDetail.altTimezoneLabel.text = Preferences.altTimezoneLabel
|
||||
binding.widgetDetail.altTimezoneTime.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||
binding.widgetDetail.altTimezoneTimeAmPm.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||
binding.widgetDetail.altTimezoneLabel.setTextColor(ColorHelper.getClockFontColor(requireActivity().isDarkTheme()))
|
||||
binding.widgetDetail.altTimezoneTime.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(requireContext()) / 3
|
||||
)
|
||||
binding.widgetDetail.altTimezoneTimeAmPm.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
(Preferences.clockTextSize.toPixel(requireContext()) / 3) / 5 * 2
|
||||
)
|
||||
binding.widgetDetail.altTimezoneLabel.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
(Preferences.clockTextSize.toPixel(requireContext()) / 3) / 5 * 2
|
||||
)
|
||||
binding.widgetDetail.timezonesContainer.isVisible = true
|
||||
} else {
|
||||
binding.widgetDetail.timezonesContainer.isVisible = false
|
||||
}
|
||||
|
||||
// Clock bottom margin
|
||||
binding.widgetDetail.clockBottomMarginNone.isVisible =
|
||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.rawValue
|
||||
|
@ -28,6 +28,7 @@ import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.ChooseApplicationActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.activities.tabs.TimeZoneSelectorActivity
|
||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
|
||||
import com.tommasoberlose.anotherwidget.utils.isDefaultSet
|
||||
@ -100,6 +101,17 @@ class ClockFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.altTimezoneLabel.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
if (it != "") {
|
||||
binding.altTimezoneClockLabel.text =
|
||||
String.format("%s (%s)", it, Preferences.altTimezoneId)
|
||||
} else {
|
||||
binding.altTimezoneClockLabel.text = getString(R.string.no_time_zone_label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.showAMPMIndicator.observe(viewLifecycleOwner) {
|
||||
maintainScrollPosition {
|
||||
binding.ampmIndicatorLabel.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||
@ -144,6 +156,10 @@ class ClockFragment : Fragment() {
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.actionAltTimezoneClock.setOnClickListener {
|
||||
startActivity(Intent(requireContext(), TimeZoneSelectorActivity::class.java))
|
||||
}
|
||||
|
||||
binding.actionAmpmIndicatorSize.setOnClickListener {
|
||||
binding.ampmIndicatorToggle.isChecked = !binding.ampmIndicatorToggle.isChecked
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
|
||||
// Clock Settings
|
||||
val showClock = Preferences.asLiveData(Preferences::showClock)
|
||||
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
|
||||
val altTimezoneLabel = Preferences.asLiveData(Preferences::altTimezoneLabel)
|
||||
val clockTextColor = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextColor)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextAlpha)) { value = true }
|
||||
@ -108,6 +109,7 @@ class MainViewModel(context: Application) : AndroidViewModel(context) {
|
||||
addSource(Preferences.asLiveData(Preferences::clockTextAlphaDark)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::showAMPMIndicator)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::clockBottomMargin)) { value = true }
|
||||
addSource(Preferences.asLiveData(Preferences::altTimezoneLabel)) { value = true }
|
||||
}
|
||||
val widgetPreferencesUpdate = MediatorLiveData<Boolean>().apply {
|
||||
addSource(Preferences.asLiveData(Preferences::textGlobalColor)) { value = true }
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.tommasoberlose.anotherwidget.ui.viewmodels.tabs
|
||||
|
||||
import android.app.Application
|
||||
import android.location.Address
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||
|
||||
class TimeZoneSelectorViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
val addresses: MutableLiveData<List<Address>> = MutableLiveData(emptyList())
|
||||
val locationInput: MutableLiveData<String> = MutableLiveData(Preferences.altTimezoneLabel)
|
||||
}
|
@ -64,6 +64,38 @@ class ClockWidget(val context: Context) {
|
||||
R.id.clock_bottom_margin_large,
|
||||
if (Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.rawValue) View.VISIBLE else View.GONE
|
||||
)
|
||||
|
||||
|
||||
// Timezones
|
||||
if (Preferences.altTimezoneId != "" && Preferences.altTimezoneLabel != "") {
|
||||
views.setString(R.id.alt_timezone_time, "setTimeZone", Preferences.altTimezoneId)
|
||||
views.setString(R.id.alt_timezone_time_am_pm, "setTimeZone", Preferences.altTimezoneId)
|
||||
views.setTextViewText(R.id.alt_timezone_label, Preferences.altTimezoneLabel)
|
||||
|
||||
views.setTextColor(R.id.alt_timezone_time, ColorHelper.getClockFontColor(context.isDarkTheme()))
|
||||
views.setTextColor(R.id.alt_timezone_time_am_pm, ColorHelper.getClockFontColor(context.isDarkTheme()))
|
||||
views.setTextColor(R.id.alt_timezone_label, ColorHelper.getClockFontColor(context.isDarkTheme()))
|
||||
views.setTextViewTextSize(
|
||||
R.id.alt_timezone_time,
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
Preferences.clockTextSize.toPixel(context) / 3
|
||||
)
|
||||
views.setTextViewTextSize(
|
||||
R.id.alt_timezone_time_am_pm,
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
(Preferences.clockTextSize.toPixel(context) / 3) / 5 * 2
|
||||
)
|
||||
views.setTextViewTextSize(
|
||||
R.id.alt_timezone_label,
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
(Preferences.clockTextSize.toPixel(context) / 3) / 5 * 2
|
||||
)
|
||||
|
||||
views.setOnClickPendingIntent(R.id.timezones_container, clockPIntent)
|
||||
views.setViewVisibility(R.id.timezones_container, View.VISIBLE)
|
||||
} else {
|
||||
views.setViewVisibility(R.id.timezones_container, View.GONE)
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
|
Reference in New Issue
Block a user