diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index 1e606d2..3fdeb0f 100644
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/app/build.gradle b/app/build.gradle
index 9546c4b..2b532b5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -122,4 +122,7 @@ dependencies {
// Permissions
implementation 'com.karumi:dexter:6.1.0'
+
+ // Fonts
+ implementation 'com.github.firatkarababa:downloadable-font-list-library:1.0.2'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 12c4db4..fdc05c4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,6 +32,7 @@
+
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt
index 14d6a91..dd39166 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Constants.kt
@@ -8,6 +8,9 @@ object Constants {
const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE"
const val CUSTOM_FONT_GOOGLE_SANS = 1
+ const val CUSTOM_FONT_DOWNLOADED = 2
+ const val CUSTOM_FONT_DOWNLOAD_NEW = 3
+
enum class ClockBottomMargin(val value: Int) {
NONE(0),
SMALL(1),
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt
index a9ba5a3..29ca963 100755
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/global/Preferences.kt
@@ -92,7 +92,8 @@ object Preferences : KotprefModel() {
var showOnlyBusyEvents by booleanPref(default = false)
var secondRowInformation by intPref(key = "PREF_SECOND_ROW_INFORMATION", default = 0)
var customFont by intPref(key = "PREF_CUSTOM_FONT", default = Constants.CUSTOM_FONT_GOOGLE_SANS)
- var customFontFile by stringPref(key = "PREF_CUSTOM_FONT_FILE")
+ var customFontFile by stringPref(default = "")
+ var customFontName by stringPref(default = "")
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
var showDividers by booleanPref(default = true)
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/SettingsStringHelper.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/SettingsStringHelper.kt
index e9b1148..bb51343 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/SettingsStringHelper.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/SettingsStringHelper.kt
@@ -54,11 +54,12 @@ object SettingsStringHelper {
}
}
- fun getCustomFontLabel(shadow: Int): Int {
- return when (shadow) {
- 0 -> R.string.custom_font_subtitle_0
- 1 -> R.string.custom_font_subtitle_1
- else -> R.string.custom_font_subtitle_1
+ fun getCustomFontLabel(context: Context, font: Int): String {
+ return when (font) {
+ 0 -> context.getString(R.string.custom_font_subtitle_0)
+ Constants.CUSTOM_FONT_GOOGLE_SANS -> context.getString(R.string.custom_font_subtitle_1)
+ Constants.CUSTOM_FONT_DOWNLOADED -> Preferences.customFontName
+ else -> context.getString(R.string.custom_font_subtitle_1)
}
}
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WidgetHelper.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WidgetHelper.kt
index 728b92e..d87f7cc 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WidgetHelper.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WidgetHelper.kt
@@ -3,10 +3,20 @@ package com.tommasoberlose.anotherwidget.helpers
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.res.Configuration.ORIENTATION_PORTRAIT
+import android.graphics.Typeface
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.Looper
import android.util.Log
+import androidx.core.provider.FontRequest
+import androidx.core.provider.FontsContractCompat
import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Preferences
+import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
+import com.tommasoberlose.anotherwidget.utils.toPixel
+import kotlin.math.min
object WidgetHelper {
class WidgetSizeProvider(
@@ -44,4 +54,37 @@ object WidgetHelper {
width to second * factor
}
}
+
+ fun runWithCustomTypeface(context: Context, function: (typeface: Typeface?) -> Unit) {
+ if (Preferences.customFontFile != "") {
+ val request = FontRequest(
+ "com.google.android.gms.fonts",
+ "com.google.android.gms",
+ Preferences.customFontFile,
+ R.array.com_google_android_gms_fonts_certs
+ )
+
+ val callback = object : FontsContractCompat.FontRequestCallback() {
+ override fun onTypefaceRetrieved(typeface: Typeface) {
+ function.invoke(typeface)
+ }
+
+ override fun onTypefaceRequestFailed(reason: Int) {
+ function.invoke(null)
+ }
+ }
+
+ val handlerThread = HandlerThread("generateView")
+ handlerThread.start()
+ if (Looper.myLooper() == null) {
+ Looper.prepare()
+ }
+
+ Handler(handlerThread.looper).run {
+ FontsContractCompat.requestFont(context, request, callback, this)
+ }
+ } else {
+ function.invoke(null)
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/CustomFontActivity.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/CustomFontActivity.kt
new file mode 100644
index 0000000..d8762b7
--- /dev/null
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/activities/CustomFontActivity.kt
@@ -0,0 +1,167 @@
+package com.tommasoberlose.anotherwidget.ui.activities
+
+import android.app.Activity
+import android.content.Intent
+import android.graphics.Typeface
+import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerThread
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.provider.FontRequest
+import androidx.core.provider.FontsContractCompat
+import androidx.core.view.isVisible
+import androidx.databinding.DataBindingUtil
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.chibatching.kotpref.blockingBulk
+import com.koolio.library.Font
+import com.tommasoberlose.anotherwidget.R
+import com.tommasoberlose.anotherwidget.databinding.ActivityCustomFontBinding
+import com.tommasoberlose.anotherwidget.global.Constants
+import com.tommasoberlose.anotherwidget.global.Preferences
+import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomFontViewModel
+import kotlinx.android.synthetic.main.activity_choose_application.*
+import kotlinx.coroutines.*
+import net.idik.lib.slimadapter.SlimAdapter
+import net.idik.lib.slimadapter.diff.DefaultDiffCallback
+
+
+class CustomFontActivity : AppCompatActivity() {
+
+ private lateinit var adapter: SlimAdapter
+ private lateinit var viewModel: CustomFontViewModel
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ viewModel = ViewModelProvider(this).get(CustomFontViewModel::class.java)
+ val binding = DataBindingUtil.setContentView(
+ this,
+ R.layout.activity_custom_font
+ )
+
+ list_view.setHasFixedSize(true)
+ val mLayoutManager = LinearLayoutManager(this)
+ list_view.layoutManager = mLayoutManager
+
+ adapter = SlimAdapter.create()
+ adapter.enableDiff(object: DefaultDiffCallback() {
+ override fun areItemsTheSame(oldItem: Any?, newItem: Any?): Boolean {
+ return oldItem is Font && newItem is Font && oldItem.fontFamily == newItem.fontFamily
+ }
+
+ override fun areContentsTheSame(oldItem: Any?, newItem: Any?): Boolean {
+ return oldItem is Font && newItem is Font && oldItem.fontFamily == newItem.fontFamily
+ }
+ })
+ adapter
+ .register(R.layout.list_item) { item, injector ->
+ injector
+ .text(R.id.text, item.fontFamily)
+ .with(R.id.text) {
+ val request = FontRequest(
+ "com.google.android.gms.fonts",
+ "com.google.android.gms",
+ item.queryString,
+ R.array.com_google_android_gms_fonts_certs
+ )
+
+
+ val callback = object : FontsContractCompat.FontRequestCallback() {
+ override fun onTypefaceRetrieved(typeface: Typeface) {
+ it.typeface = typeface
+ it.isVisible = true
+
+ it.measure(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ }
+
+ override fun onTypefaceRequestFailed(reason: Int) {
+ it.isVisible = false
+ it.layoutParams = it.layoutParams.apply {
+ height = 0
+ }
+ }
+ }
+
+ val handlerThread = HandlerThread(item.fontFamily)
+ handlerThread.start()
+ val mHandler = Handler(handlerThread.looper)
+ FontsContractCompat.requestFont(this, request, callback, mHandler)
+ }
+
+ injector.clicked(R.id.text) {
+ saveFont(item)
+ }
+ }
+ .attachTo(list_view)
+
+ setupListener()
+ subscribeUi(binding, viewModel)
+
+ search.requestFocus()
+ }
+
+ private var filterJob: Job? = null
+
+ private fun subscribeUi(binding: ActivityCustomFontBinding, viewModel: CustomFontViewModel) {
+ binding.viewModel = viewModel
+
+ viewModel.fontList.observe(this, Observer {
+ updateList(list = it)
+ loader.visibility = View.INVISIBLE
+ })
+
+ viewModel.searchInput.observe(this, Observer { search ->
+ updateList(search = search)
+ })
+ }
+
+ private fun updateList(
+ list: ArrayList? = viewModel.fontList.value,
+ search: String? = viewModel.searchInput.value
+ ) {
+ loader.visibility = View.VISIBLE
+ filterJob?.cancel()
+ filterJob = lifecycleScope.launch(Dispatchers.IO) {
+ if (list != null && list.isNotEmpty()) {
+ delay(200)
+ val filteredList: List = if (search == null || search == "") {
+ list
+ } else {
+ list.filter {
+ it.fontFamily.contains(search, true)
+ }
+ }.distinctBy { it.fontFamily }
+ withContext(Dispatchers.Main) {
+ adapter.updateData(filteredList)
+ loader.visibility = View.INVISIBLE
+ }
+ }
+ }
+ }
+
+ private fun setupListener() {
+ action_back.setOnClickListener {
+ onBackPressed()
+ }
+ }
+
+ private fun saveFont(font: Font) {
+ val resultIntent = Intent()
+ Preferences.blockingBulk {
+ customFont = Constants.CUSTOM_FONT_DOWNLOADED
+ customFontName = font.fontFamily
+ customFontFile = font.queryString
+ }
+ setResult(Activity.RESULT_OK, resultIntent)
+ finish()
+ }
+}
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/GeneralTabFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/GeneralTabFragment.kt
index b99d2b6..340def6 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/GeneralTabFragment.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/GeneralTabFragment.kt
@@ -3,16 +3,24 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
+import android.graphics.Typeface
import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerThread
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.Toast
+import androidx.core.provider.FontRequest
+import androidx.core.provider.FontsContractCompat
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.chibatching.kotpref.blockingBulk
+import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
@@ -25,9 +33,13 @@ import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.helpers.DateHelper
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
+import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
+import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
import com.tommasoberlose.anotherwidget.ui.activities.CustomDateActivity
+import com.tommasoberlose.anotherwidget.ui.activities.CustomFontActivity
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
+import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
import kotlinx.android.synthetic.main.fragment_clock_settings.*
import kotlinx.android.synthetic.main.fragment_general_settings.*
@@ -271,7 +283,15 @@ class GeneralTabFragment : Fragment() {
viewModel.customFont.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
- custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it))
+ custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), it)
+ MainWidget.updateWidget(requireContext())
+ }
+ })
+
+ viewModel.customFontFile.observe(viewLifecycleOwner, Observer {
+ maintainScrollPosition {
+ custom_font_label?.text = SettingsStringHelper.getCustomFontLabel(requireContext(), Preferences.customFont)
+ MainWidget.updateWidget(requireContext())
}
})
@@ -455,10 +475,25 @@ class GeneralTabFragment : Fragment() {
action_custom_font.setOnClickListener {
val dialog = BottomSheetMenu(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(Preferences.customFont)
(0..1).forEach {
- dialog.addItem(getString(SettingsStringHelper.getCustomFontLabel(it)), it)
+ dialog.addItem(SettingsStringHelper.getCustomFontLabel(requireContext(), it), it)
}
+ if (Preferences.customFontFile != "") {
+ dialog.addItem(Preferences.customFontName, Constants.CUSTOM_FONT_DOWNLOADED)
+ }
+ dialog.addItem(getString(R.string.action_custom_font_to_search), Constants.CUSTOM_FONT_DOWNLOAD_NEW)
dialog.addOnSelectItemListener { value ->
- Preferences.customFont = value
+ if (value == Constants.CUSTOM_FONT_DOWNLOAD_NEW) {
+ startActivityForResult(
+ Intent(requireContext(), CustomFontActivity::class.java),
+ RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code
+ )
+ } else if (value != Constants.CUSTOM_FONT_DOWNLOADED) {
+ Preferences.bulk {
+ customFont = value
+ customFontFile = ""
+ customFontName = ""
+ }
+ }
}.show()
/*
@@ -487,15 +522,7 @@ class GeneralTabFragment : Fragment() {
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code -> {
- /*val uri = data.data
- Log.d("AW", "File Uri: " + uri.toString())
- val path = Util.getPath(this, uri)
- Log.d("AW", "File Path: " + path)
- SP.edit()
- .putString(Constants.PREF_CUSTOM_FONT_FILE, path)
- .commit()
- sendBroadcast(Intent(Constants.ACTION_TIME_UPDATE))
- updateSettings()*/
+
}
}
}
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt
index b7168f0..27e35ec 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/fragments/MainFragment.kt
@@ -36,6 +36,7 @@ import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
+import com.tommasoberlose.anotherwidget.helpers.WidgetHelper
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
@@ -147,133 +148,136 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true)
)
)
- uiJob = lifecycleScope.launch(Dispatchers.IO) {
- val generatedView = MainWidget.generateWidgetView(requireContext())
+ WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
+ uiJob = lifecycleScope.launch(Dispatchers.IO) {
+ val generatedView = MainWidget.generateWidgetView(requireContext(), typeface)
- withContext(Dispatchers.Main) {
- generatedView.measure(0, 0)
- preview?.measure(0, 0)
- }
+ withContext(Dispatchers.Main) {
+ generatedView.measure(0, 0)
+ preview?.measure(0, 0)
+ }
- val bitmap = if (preview != null) {
- BitmapHelper.getBitmapFromView(
- generatedView,
- if (preview.width > 0) preview.width else generatedView.measuredWidth,
- generatedView.measuredHeight
- )
- } else {
- null
- }
- withContext(Dispatchers.Main) {
- // Clock
- time?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
- time_am_pm?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
- time?.setTextSize(
- TypedValue.COMPLEX_UNIT_SP,
- Preferences.clockTextSize.toPixel(requireContext())
- )
- time_am_pm?.setTextSize(
- TypedValue.COMPLEX_UNIT_SP,
- Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
- )
- time_am_pm?.isVisible = Preferences.showAMPMIndicator
+ val bitmap = if (preview != null) {
+ BitmapHelper.getBitmapFromView(
+ generatedView,
+ if (preview.width > 0) preview.width else generatedView.measuredWidth,
+ generatedView.measuredHeight
+ )
+ } else {
+ null
+ }
+ withContext(Dispatchers.Main) {
+ // Clock
+ time?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
+ time_am_pm?.setTextColor(ColorHelper.getClockFontColor(activity?.isDarkTheme() == true))
+ time?.setTextSize(
+ TypedValue.COMPLEX_UNIT_SP,
+ Preferences.clockTextSize.toPixel(requireContext())
+ )
+ time_am_pm?.setTextSize(
+ TypedValue.COMPLEX_UNIT_SP,
+ Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
+ )
+ time_am_pm?.isVisible = Preferences.showAMPMIndicator
- // Clock bottom margin
- clock_bottom_margin_none?.isVisible =
- Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
- clock_bottom_margin_small?.isVisible =
- Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
- clock_bottom_margin_medium?.isVisible =
- Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
- clock_bottom_margin_large?.isVisible =
- Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
+ // Clock bottom margin
+ clock_bottom_margin_none?.isVisible =
+ Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
+ clock_bottom_margin_small?.isVisible =
+ Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
+ clock_bottom_margin_medium?.isVisible =
+ Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
+ clock_bottom_margin_large?.isVisible =
+ Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
- if ((Preferences.showClock && (time?.alpha ?: 1f < 1f)) || (!Preferences.showClock && (time?.alpha ?: 0f > 0f))) {
- if (Preferences.showClock) {
+ if ((Preferences.showClock && (time?.alpha ?: 1f < 1f)) || (!Preferences.showClock && (time?.alpha ?: 0f > 0f))) {
+ if (Preferences.showClock) {
+ time_container?.layoutParams = time_container.layoutParams.apply {
+ height = RelativeLayout.LayoutParams.WRAP_CONTENT
+ }
+ time_container?.measure(0, 0)
+ }
+ val initialHeight = time_container?.measuredHeight ?: 0
+ ValueAnimator.ofFloat(
+ if (Preferences.showClock) 0f else 1f,
+ if (Preferences.showClock) 1f else 0f
+ ).apply {
+ duration = 500L
+ addUpdateListener {
+ val animatedValue = animatedValue as Float
+ time_container?.layoutParams =
+ time_container.layoutParams.apply {
+ height = (initialHeight * animatedValue).toInt()
+ }
+ time?.alpha = animatedValue
+ }
+ addListener(
+ onStart = {
+ if (Preferences.showClock) {
+ time_container?.isVisible = true
+ }
+ },
+ onEnd = {
+ if (!Preferences.showClock) {
+ time_container?.isVisible = false
+ }
+ }
+ )
+ }.start()
+
+ if (preview != null) {
+ ValueAnimator.ofInt(
+ preview.height,
+ PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
+ requireContext()
+ ) else 0
+ ).apply {
+ duration = 500L
+ addUpdateListener {
+ if (preview != null) {
+ val animatedValue = animatedValue as Int
+ val layoutParams = preview.layoutParams
+ layoutParams.height = animatedValue
+ preview.layoutParams = layoutParams
+ }
+ }
+ }.start()
+ }
+ } else {
time_container?.layoutParams = time_container.layoutParams.apply {
height = RelativeLayout.LayoutParams.WRAP_CONTENT
}
time_container?.measure(0, 0)
}
- val initialHeight = time_container?.measuredHeight ?: 0
- ValueAnimator.ofFloat(
- if (Preferences.showClock) 0f else 1f,
- if (Preferences.showClock) 1f else 0f
- ).apply {
- duration = 500L
- addUpdateListener {
- val animatedValue = animatedValue as Float
- time_container?.layoutParams =
- time_container.layoutParams.apply {
- height = (initialHeight * animatedValue).toInt()
- }
- time?.alpha = animatedValue
- }
- addListener(
- onStart = {
- if (Preferences.showClock) {
- time_container?.isVisible = true
- }
- },
- onEnd = {
- if (!Preferences.showClock) {
- time_container?.isVisible = false
- }
- }
- )
- }.start()
- if (preview != null) {
+ if (preview != null && preview.height == 0) {
ValueAnimator.ofInt(
preview.height,
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
requireContext()
) else 0
).apply {
- duration = 500L
+ duration = 300L
addUpdateListener {
if (preview != null) {
val animatedValue = animatedValue as Int
val layoutParams = preview.layoutParams
layoutParams.height = animatedValue
- preview.layoutParams = layoutParams
+ preview?.layoutParams = layoutParams
}
}
}.start()
}
- } else {
- time_container?.layoutParams = time_container.layoutParams.apply {
- height = RelativeLayout.LayoutParams.WRAP_CONTENT
+
+ widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)
+ ?.setDuration(200L)?.start()
+ bitmap_container?.apply {
+ setImageBitmap(bitmap)
+ scaleX = 0.9f
+ scaleY = 0.9f
}
- time_container?.measure(0, 0)
+ widget?.animate()?.alpha(1f)?.start()
}
-
- if (preview != null && preview.height == 0) {
- ValueAnimator.ofInt(
- preview.height,
- PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
- requireContext()
- ) else 0
- ).apply {
- duration = 300L
- addUpdateListener {
- if (preview != null) {
- val animatedValue = animatedValue as Int
- val layoutParams = preview.layoutParams
- layoutParams.height = animatedValue
- preview?.layoutParams = layoutParams
- }
- }
- }.start()
- }
-
- widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)?.setDuration(200L)?.start()
- bitmap_container?.apply {
- setImageBitmap(bitmap)
- scaleX = 0.9f
- scaleY = 0.9f
- }
- widget?.animate()?.alpha(1f)?.start()
}
}
} else {
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/CustomFontViewModel.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/CustomFontViewModel.kt
new file mode 100644
index 0000000..b27fa27
--- /dev/null
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/CustomFontViewModel.kt
@@ -0,0 +1,39 @@
+package com.tommasoberlose.anotherwidget.ui.viewmodels
+
+import android.app.Application
+import android.content.Intent
+import android.content.pm.ResolveInfo
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import com.koolio.library.DownloadableFontList
+import com.koolio.library.Font
+import com.koolio.library.FontList
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+class CustomFontViewModel(application: Application) : AndroidViewModel(application) {
+
+ val fontList: MutableLiveData> = MutableLiveData()
+ val searchInput: MutableLiveData = MutableLiveData("")
+
+ init {
+ viewModelScope.launch(Dispatchers.IO) {
+
+
+ val fontListCallback: DownloadableFontList.FontListCallback =
+ object : DownloadableFontList.FontListCallback {
+ override fun onFontListRetrieved(downloadedList: FontList?) {
+ fontList.postValue(downloadedList?.fontArrayList)
+ }
+
+ override fun onTypefaceRequestFailed(reason: Int) {
+
+ }
+ }
+
+ DownloadableFontList.requestDownloadableFontList(fontListCallback, "AIzaSyCT_v2Qw1zCWfmc_ywsovj_4poSXr7k5f0")
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt
index c6b7354..1944edc 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/viewmodels/MainViewModel.kt
@@ -24,6 +24,7 @@ class MainViewModel : ViewModel() {
val textShadow = Preferences.asLiveData(Preferences::textShadow)
val textShadowDark = Preferences.asLiveData(Preferences::textShadowDark)
val customFont = Preferences.asLiveData(Preferences::customFont)
+ val customFontFile = Preferences.asLiveData(Preferences::customFontFile)
val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation)
val showDividers = Preferences.asLiveData(Preferences::showDividers)
val secondRowTopMargin = Preferences.asLiveData(Preferences::secondRowTopMargin)
diff --git a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt
index a90532e..d7ca1f6 100644
--- a/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt
+++ b/app/src/main/java/com/tommasoberlose/anotherwidget/ui/widgets/MainWidget.kt
@@ -11,12 +11,18 @@ import android.content.res.Resources
import android.graphics.Color
import android.graphics.Typeface
import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.Looper
import android.text.format.DateUtils
import android.util.Log
import android.util.TypedValue
import android.view.View
+import android.view.ViewGroup
import android.widget.*
import androidx.core.content.ContextCompat
+import androidx.core.provider.FontRequest
+import androidx.core.provider.FontsContractCompat
import androidx.core.view.isVisible
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository
@@ -90,10 +96,14 @@ class MainWidget : AppWidgetProvider() {
val height = displayMetrics.heightPixels
val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId)
- generateWidgetView(context, appWidgetId, appWidgetManager, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)))
+
+ WidgetHelper.runWithCustomTypeface(context) {
+ generateWidgetView(context, appWidgetId, appWidgetManager, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it)
+ }
}
- private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int) {
+ private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int, typeface: Typeface? = null) {
+
var views = RemoteViews(context.packageName, R.layout.the_widget_sans)
try {
@@ -125,7 +135,8 @@ class MainWidget : AppWidgetProvider() {
// Setup listener
try {
- val generatedView = generateWidgetView(context)
+
+ val generatedView = generateWidgetView(context, typeface)
views.setImageViewBitmap(
R.id.bitmap_container,
BitmapHelper.getBitmapFromView(generatedView, width = w)
@@ -492,7 +503,7 @@ class MainWidget : AppWidgetProvider() {
// Generates the widget bitmap from the view
- fun generateWidgetView(context: Context): View {
+ fun generateWidgetView(context: Context, typeface: Typeface? = null): View {
val eventRepository = EventRepository(context)
val v = View.inflate(context, R.layout.the_widget, null)
@@ -514,8 +525,10 @@ class MainWidget : AppWidgetProvider() {
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null) {
// Multiple counter
- v.action_next.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1
- v.action_previous.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1
+ v.action_next.isVisible =
+ Preferences.showNextEvent && eventRepository.getEventsCount() > 1
+ v.action_previous.isVisible =
+ Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.next_event.text = nextEvent.title
@@ -528,7 +541,11 @@ class MainWidget : AppWidgetProvider() {
)
.toLowerCase(Locale.getDefault())
} else {
- SettingsStringHelper.getAllDayEventDifferenceText(context, now.timeInMillis, nextEvent.startDate).toLowerCase(Locale.getDefault())
+ SettingsStringHelper.getAllDayEventDifferenceText(
+ context,
+ now.timeInMillis,
+ nextEvent.startDate
+ ).toLowerCase(Locale.getDefault())
}
v.next_event_difference_time.visibility = View.VISIBLE
} else {
@@ -536,15 +553,30 @@ class MainWidget : AppWidgetProvider() {
}
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
- v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.round_place))
+ v.second_row_icon.setImageDrawable(
+ ContextCompat.getDrawable(
+ context,
+ R.drawable.round_place
+ )
+ )
v.next_event_date.text = nextEvent.address
} else {
- v.second_row_icon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.round_today))
+ v.second_row_icon.setImageDrawable(
+ ContextCompat.getDrawable(
+ context,
+ R.drawable.round_today
+ )
+ )
if (!nextEvent.allDay) {
- val startHour = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(nextEvent.startDate)
- val endHour = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(nextEvent.endDate)
+ val startHour =
+ DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault())
+ .format(nextEvent.startDate)
+ val endHour =
+ DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault())
+ .format(nextEvent.endDate)
- var dayDiff = TimeUnit.MILLISECONDS.toDays(nextEvent.endDate - nextEvent.startDate)
+ var dayDiff =
+ TimeUnit.MILLISECONDS.toDays(nextEvent.endDate - nextEvent.startDate)
val startCal = Calendar.getInstance()
startCal.timeInMillis = nextEvent.startDate
@@ -554,31 +586,46 @@ class MainWidget : AppWidgetProvider() {
if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) {
dayDiff++
- } else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get(Calendar.MINUTE) >= endCal.get(Calendar.MINUTE)) {
+ } else if (startCal.get(Calendar.HOUR_OF_DAY) == endCal.get(Calendar.HOUR_OF_DAY) && startCal.get(
+ Calendar.MINUTE
+ ) >= endCal.get(Calendar.MINUTE)
+ ) {
dayDiff++
}
var multipleDay = ""
if (dayDiff > 0) {
- multipleDay = String.format(" (+%s%s)", dayDiff, context.getString(R.string.day_char))
+ multipleDay = String.format(
+ " (+%s%s)",
+ dayDiff,
+ context.getString(R.string.day_char)
+ )
}
- v.next_event_date.text = String.format("%s - %s%s", startHour, endHour, multipleDay)
+ v.next_event_date.text =
+ String.format("%s - %s%s", startHour, endHour, multipleDay)
} else {
- val flags: Int = DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
- v.next_event_date.text = DateUtils.formatDateTime(context, nextEvent.startDate, flags)
+ val flags: Int =
+ DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
+ v.next_event_date.text =
+ DateUtils.formatDateTime(context, nextEvent.startDate, flags)
}
}
v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE
- v.second_row_top_margin_small.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.value) View.VISIBLE else View.GONE
- v.second_row_top_margin_medium.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE
- v.second_row_top_margin_large.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.value) View.VISIBLE else View.GONE
+ v.second_row_top_margin_small.visibility =
+ if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.value) View.VISIBLE else View.GONE
+ v.second_row_top_margin_medium.visibility =
+ if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE
+ v.second_row_top_margin_large.visibility =
+ if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.value) View.VISIBLE else View.GONE
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
v.second_row_icon.isVisible = true
var showSomething = false
- loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) {
+ loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(
+ context
+ )) {
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
if (MediaPlayerHelper.isSomeonePlaying(context)) {
@@ -613,9 +660,13 @@ class MainWidget : AppWidgetProvider() {
v.second_row_icon.isVisible = false
val batteryLevel = BatteryHelper.getBatteryLevel(context)
if (batteryLevel == 100) {
- v.next_event_date.text = "%s - %d%%".format(context.getString(R.string.charging), batteryLevel)
+ v.next_event_date.text = "%s - %d%%".format(
+ context.getString(R.string.charging),
+ batteryLevel
+ )
} else {
- v.next_event_date.text = context.getString(R.string.charging)
+ v.next_event_date.text =
+ context.getString(R.string.charging)
}
showSomething = true
break@loop
@@ -641,7 +692,9 @@ class MainWidget : AppWidgetProvider() {
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
v.second_row_icon.isVisible = false
- v.next_event_date.text = context.getString(R.string.daily_steps_counter).format(Preferences.googleFitSteps)
+ v.next_event_date.text =
+ context.getString(R.string.daily_steps_counter)
+ .format(Preferences.googleFitSteps)
showSomething = true
break@loop
}
@@ -654,9 +707,12 @@ class MainWidget : AppWidgetProvider() {
v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE
- v.second_row_top_margin_small.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.value) View.VISIBLE else View.GONE
- v.second_row_top_margin_medium.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE
- v.second_row_top_margin_large.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.value) View.VISIBLE else View.GONE
+ v.second_row_top_margin_small.visibility =
+ if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.value) View.VISIBLE else View.GONE
+ v.second_row_top_margin_medium.visibility =
+ if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE
+ v.second_row_top_margin_large.visibility =
+ if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.value) View.VISIBLE else View.GONE
} else {
v.second_row_icon.isVisible = false
}
@@ -664,17 +720,33 @@ class MainWidget : AppWidgetProvider() {
// Color
- listOf(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.divider3, v.special_temp).forEach {
+ listOf(
+ v.empty_date,
+ v.divider1,
+ v.temp,
+ v.next_event,
+ v.next_event_difference_time,
+ v.divider3,
+ v.special_temp
+ ).forEach {
it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme()))
}
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.value) {
listOf(v.action_next, v.action_previous)
} else {
- listOf(v.action_next, v.action_previous, v.empty_weather_icon, v.special_weather_icon)
+ listOf(
+ v.action_next,
+ v.action_previous,
+ v.empty_weather_icon,
+ v.special_weather_icon
+ )
}.forEach {
it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme()))
- it.alpha = (if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue().toFloat() else Preferences.textGlobalAlpha.toIntValue().toFloat()) / 100
+ it.alpha =
+ (if (context.isDarkTheme()) Preferences.textGlobalAlphaDark.toIntValue()
+ .toFloat() else Preferences.textGlobalAlpha.toIntValue()
+ .toFloat()) / 100
}
listOf(v.next_event_date, v.divider2, v.calendar_temp).forEach {
@@ -687,7 +759,10 @@ class MainWidget : AppWidgetProvider() {
listOf(v.second_row_icon, v.weather_icon)
}.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme()))
- it.alpha = (if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue().toFloat() else Preferences.textSecondaryAlpha.toIntValue().toFloat()) / 100
+ it.alpha =
+ (if (context.isDarkTheme()) Preferences.textSecondaryAlphaDark.toIntValue()
+ .toFloat() else Preferences.textSecondaryAlpha.toIntValue()
+ .toFloat()) / 100
}
// Text Size
@@ -727,35 +802,76 @@ class MainWidget : AppWidgetProvider() {
// Shadows
- val shadowRadius = when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
- 0 -> 0f
- 1 -> 5f
- 2 -> 5f
- else -> 5f
- }
- val shadowColor = when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
- 0 -> Color.TRANSPARENT
- 1 -> R.color.black_50
- 2 -> Color.BLACK
- else -> R.color.black_50
- }
- val shadowDy = when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
- 0 -> 0f
- 1 -> 0f
- 2 -> 1f
- else -> 0f
- }
+ val shadowRadius =
+ when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
+ 0 -> 0f
+ 1 -> 5f
+ 2 -> 5f
+ else -> 5f
+ }
+ val shadowColor =
+ when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
+ 0 -> Color.TRANSPARENT
+ 1 -> R.color.black_50
+ 2 -> Color.BLACK
+ else -> R.color.black_50
+ }
+ val shadowDy =
+ when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
+ 0 -> 0f
+ 1 -> 0f
+ 2 -> 1f
+ else -> 0f
+ }
- listOf(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp, v.divider3, v.special_temp).forEach {
+ listOf(
+ v.empty_date,
+ v.divider1,
+ v.temp,
+ v.next_event,
+ v.next_event_difference_time,
+ v.next_event_date,
+ v.divider2,
+ v.calendar_temp,
+ v.divider3,
+ v.special_temp
+ ).forEach {
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
}
// Custom Font
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
- val googleSans: Typeface = Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf")
- listOf(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.next_event_date, v.divider2, v.calendar_temp, v.divider3, v.special_temp).forEach {
+ val googleSans: Typeface =
+ Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf")
+ listOf(
+ v.empty_date,
+ v.divider1,
+ v.temp,
+ v.next_event,
+ v.next_event_difference_time,
+ v.next_event_date,
+ v.divider2,
+ v.calendar_temp,
+ v.divider3,
+ v.special_temp
+ ).forEach {
it.typeface = googleSans
}
+ } else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) {
+ listOf(
+ v.empty_date,
+ v.divider1,
+ v.temp,
+ v.next_event,
+ v.next_event_difference_time,
+ v.next_event_date,
+ v.divider2,
+ v.calendar_temp,
+ v.divider3,
+ v.special_temp
+ ).forEach {
+ it.typeface = typeface
+ }
}
// Weather
@@ -763,7 +879,12 @@ class MainWidget : AppWidgetProvider() {
v.weather.visibility = View.VISIBLE
v.calendar_weather.visibility = View.VISIBLE
v.special_weather.visibility = View.VISIBLE
- val currentTemp = String.format(Locale.getDefault(), "%d °%s", Preferences.weatherTemp.roundToInt(), Preferences.weatherRealTempUnit)
+ val currentTemp = String.format(
+ Locale.getDefault(),
+ "%d °%s",
+ Preferences.weatherTemp.roundToInt(),
+ Preferences.weatherRealTempUnit
+ )
val icon: String = Preferences.weatherIcon
if (icon == "") {
@@ -772,8 +893,16 @@ class MainWidget : AppWidgetProvider() {
v.special_weather_icon.visibility = View.GONE
} else {
v.weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
- v.empty_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
- v.special_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
+ v.empty_weather_icon.setImageResource(
+ WeatherHelper.getWeatherIconResource(
+ icon
+ )
+ )
+ v.special_weather_icon.setImageResource(
+ WeatherHelper.getWeatherIconResource(
+ icon
+ )
+ )
v.weather_icon.visibility = View.VISIBLE
v.empty_weather_icon.visibility = View.VISIBLE
v.special_weather_icon.visibility = View.VISIBLE
diff --git a/app/src/main/res/layout/activity_custom_font.xml b/app/src/main/res/layout/activity_custom_font.xml
new file mode 100644
index 0000000..e014111
--- /dev/null
+++ b/app/src/main/res/layout/activity_custom_font.xml
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item.xml b/app/src/main/res/layout/list_item.xml
new file mode 100644
index 0000000..d72b728
--- /dev/null
+++ b/app/src/main/res/layout/list_item.xml
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index a87af76..465ed7d 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -27,6 +27,7 @@
Formato data
Sfondo widget
Margine
+ Cerca font...
Calendario
diff --git a/app/src/main/res/values/font_certs.xml b/app/src/main/res/values/font_certs.xml
new file mode 100644
index 0000000..949ce9f
--- /dev/null
+++ b/app/src/main/res/values/font_certs.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ - @array/com_google_android_gms_fonts_certs_dev
+ - @array/com_google_android_gms_fonts_certs_prod
+
+
+ -
+ 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
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1a51a4f..f2f2b5d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -29,6 +29,7 @@
Date format
Widget background
Margin
+ Custom font...
Calendar