Add downloadable fonts

This commit is contained in:
Tommaso Berlose 2020-10-04 20:39:52 +02:00
parent b7bc93e174
commit 6ab8e40d45
18 changed files with 752 additions and 173 deletions

Binary file not shown.

View File

@ -122,4 +122,7 @@ dependencies {
// Permissions // Permissions
implementation 'com.karumi:dexter:6.1.0' implementation 'com.karumi:dexter:6.1.0'
// Fonts
implementation 'com.github.firatkarababa:downloadable-font-list-library:1.0.2'
} }

View File

@ -32,6 +32,7 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".ui.activities.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" /> <activity android:name=".ui.activities.ChooseApplicationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.CustomFontActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" /> <activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" /> <activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />
<activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" /> <activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" android:screenOrientation="portrait" />

View File

@ -8,6 +8,9 @@ object Constants {
const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE" const val RESULT_APP_PACKAGE = "RESULT_APP_PACKAGE"
const val CUSTOM_FONT_GOOGLE_SANS = 1 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) { enum class ClockBottomMargin(val value: Int) {
NONE(0), NONE(0),
SMALL(1), SMALL(1),

View File

@ -92,7 +92,8 @@ object Preferences : KotprefModel() {
var showOnlyBusyEvents by booleanPref(default = false) var showOnlyBusyEvents by booleanPref(default = false)
var secondRowInformation by intPref(key = "PREF_SECOND_ROW_INFORMATION", default = 0) 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 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 showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
var showDividers by booleanPref(default = true) var showDividers by booleanPref(default = true)

View File

@ -54,11 +54,12 @@ object SettingsStringHelper {
} }
} }
fun getCustomFontLabel(shadow: Int): Int { fun getCustomFontLabel(context: Context, font: Int): String {
return when (shadow) { return when (font) {
0 -> R.string.custom_font_subtitle_0 0 -> context.getString(R.string.custom_font_subtitle_0)
1 -> R.string.custom_font_subtitle_1 Constants.CUSTOM_FONT_GOOGLE_SANS -> context.getString(R.string.custom_font_subtitle_1)
else -> R.string.custom_font_subtitle_1 Constants.CUSTOM_FONT_DOWNLOADED -> Preferences.customFontName
else -> context.getString(R.string.custom_font_subtitle_1)
} }
} }

View File

@ -3,10 +3,20 @@ package com.tommasoberlose.anotherwidget.helpers
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.content.Context import android.content.Context
import android.content.res.Configuration.ORIENTATION_PORTRAIT 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 android.util.Log
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Preferences 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 { object WidgetHelper {
class WidgetSizeProvider( class WidgetSizeProvider(
@ -44,4 +54,37 @@ object WidgetHelper {
width to second * factor 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)
}
}
} }

View File

@ -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<ActivityCustomFontBinding>(
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<Font>(R.layout.list_item) { item, injector ->
injector
.text(R.id.text, item.fontFamily)
.with<TextView>(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<Font>? = 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<Font> = 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()
}
}

View File

@ -3,16 +3,24 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.Typeface
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.chibatching.kotpref.blockingBulk import com.chibatching.kotpref.blockingBulk
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu 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.ColorHelper.toIntValue
import com.tommasoberlose.anotherwidget.helpers.DateHelper import com.tommasoberlose.anotherwidget.helpers.DateHelper
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper 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.CustomDateActivity
import com.tommasoberlose.anotherwidget.ui.activities.CustomFontActivity
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.isDarkTheme import com.tommasoberlose.anotherwidget.utils.isDarkTheme
import kotlinx.android.synthetic.main.fragment_clock_settings.* import kotlinx.android.synthetic.main.fragment_clock_settings.*
import kotlinx.android.synthetic.main.fragment_general_settings.* import kotlinx.android.synthetic.main.fragment_general_settings.*
@ -271,7 +283,15 @@ class GeneralTabFragment : Fragment() {
viewModel.customFont.observe(viewLifecycleOwner, Observer { viewModel.customFont.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { 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 { action_custom_font.setOnClickListener {
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(Preferences.customFont) val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_custom_font_title)).setSelectedValue(Preferences.customFont)
(0..1).forEach { (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 -> 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() }.show()
/* /*
@ -487,15 +522,7 @@ class GeneralTabFragment : Fragment() {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
when (requestCode) { when (requestCode) {
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code -> { 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()*/
} }
} }
} }

View File

@ -36,6 +36,7 @@ import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark 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.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter import com.tommasoberlose.anotherwidget.ui.adapters.ViewPagerAdapter
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
@ -147,8 +148,9 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true) ColorHelper.getBackgroundColor(activity?.isDarkTheme() == true)
) )
) )
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
uiJob = lifecycleScope.launch(Dispatchers.IO) { uiJob = lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.generateWidgetView(requireContext()) val generatedView = MainWidget.generateWidgetView(requireContext(), typeface)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
generatedView.measure(0, 0) generatedView.measure(0, 0)
@ -267,7 +269,8 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
}.start() }.start()
} }
widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)?.setDuration(200L)?.start() widget_loader?.animate()?.scaleX(0f)?.scaleY(0f)?.alpha(0f)
?.setDuration(200L)?.start()
bitmap_container?.apply { bitmap_container?.apply {
setImageBitmap(bitmap) setImageBitmap(bitmap)
scaleX = 0.9f scaleX = 0.9f
@ -276,6 +279,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
widget?.animate()?.alpha(1f)?.start() widget?.animate()?.alpha(1f)?.start()
} }
} }
}
} else { } else {
if (preview != null) { if (preview != null) {
ValueAnimator.ofInt( ValueAnimator.ofInt(

View File

@ -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<ArrayList<Font>> = MutableLiveData()
val searchInput: MutableLiveData<String> = 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")
}
}
}

View File

@ -24,6 +24,7 @@ class MainViewModel : ViewModel() {
val textShadow = Preferences.asLiveData(Preferences::textShadow) val textShadow = Preferences.asLiveData(Preferences::textShadow)
val textShadowDark = Preferences.asLiveData(Preferences::textShadowDark) val textShadowDark = Preferences.asLiveData(Preferences::textShadowDark)
val customFont = Preferences.asLiveData(Preferences::customFont) val customFont = Preferences.asLiveData(Preferences::customFont)
val customFontFile = Preferences.asLiveData(Preferences::customFontFile)
val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation) val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation)
val showDividers = Preferences.asLiveData(Preferences::showDividers) val showDividers = Preferences.asLiveData(Preferences::showDividers)
val secondRowTopMargin = Preferences.asLiveData(Preferences::secondRowTopMargin) val secondRowTopMargin = Preferences.asLiveData(Preferences::secondRowTopMargin)

View File

@ -11,12 +11,18 @@ import android.content.res.Resources
import android.graphics.Color import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.text.format.DateUtils import android.text.format.DateUtils
import android.util.Log import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.view.ViewGroup
import android.widget.* import android.widget.*
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository import com.tommasoberlose.anotherwidget.db.EventRepository
@ -90,10 +96,14 @@ class MainWidget : AppWidgetProvider() {
val height = displayMetrics.heightPixels val height = displayMetrics.heightPixels
val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId) 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) var views = RemoteViews(context.packageName, R.layout.the_widget_sans)
try { try {
@ -125,7 +135,8 @@ class MainWidget : AppWidgetProvider() {
// Setup listener // Setup listener
try { try {
val generatedView = generateWidgetView(context)
val generatedView = generateWidgetView(context, typeface)
views.setImageViewBitmap( views.setImageViewBitmap(
R.id.bitmap_container, R.id.bitmap_container,
BitmapHelper.getBitmapFromView(generatedView, width = w) BitmapHelper.getBitmapFromView(generatedView, width = w)
@ -492,7 +503,7 @@ class MainWidget : AppWidgetProvider() {
// Generates the widget bitmap from the view // 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 eventRepository = EventRepository(context)
val v = View.inflate(context, R.layout.the_widget, null) 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) { if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null) {
// Multiple counter // Multiple counter
v.action_next.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1 v.action_next.isVisible =
v.action_previous.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1 Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.action_previous.isVisible =
Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.next_event.text = nextEvent.title v.next_event.text = nextEvent.title
@ -528,7 +541,11 @@ class MainWidget : AppWidgetProvider() {
) )
.toLowerCase(Locale.getDefault()) .toLowerCase(Locale.getDefault())
} else { } 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 v.next_event_difference_time.visibility = View.VISIBLE
} else { } else {
@ -536,15 +553,30 @@ class MainWidget : AppWidgetProvider() {
} }
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { 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 v.next_event_date.text = nextEvent.address
} else { } 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) { if (!nextEvent.allDay) {
val startHour = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(nextEvent.startDate) val startHour =
val endHour = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(nextEvent.endDate) 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() val startCal = Calendar.getInstance()
startCal.timeInMillis = nextEvent.startDate startCal.timeInMillis = nextEvent.startDate
@ -554,31 +586,46 @@ class MainWidget : AppWidgetProvider() {
if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) { if (startCal.get(Calendar.HOUR_OF_DAY) > endCal.get(Calendar.HOUR_OF_DAY)) {
dayDiff++ 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++ dayDiff++
} }
var multipleDay = "" var multipleDay = ""
if (dayDiff > 0) { 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 { } else {
val flags: Int = DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH val flags: Int =
v.next_event_date.text = DateUtils.formatDateTime(context, nextEvent.startDate, flags) 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.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE 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_small.visibility =
v.second_row_top_margin_medium.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.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_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)) { } else if (GlanceProviderHelper.showGlanceProviders(context)) {
v.second_row_icon.isVisible = true v.second_row_icon.isVisible = true
var showSomething = false var showSomething = false
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(context)) { loop@ for (provider: Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders(
context
)) {
when (provider) { when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> { Constants.GlanceProviderId.PLAYING_SONG -> {
if (MediaPlayerHelper.isSomeonePlaying(context)) { if (MediaPlayerHelper.isSomeonePlaying(context)) {
@ -613,9 +660,13 @@ class MainWidget : AppWidgetProvider() {
v.second_row_icon.isVisible = false v.second_row_icon.isVisible = false
val batteryLevel = BatteryHelper.getBatteryLevel(context) val batteryLevel = BatteryHelper.getBatteryLevel(context)
if (batteryLevel == 100) { 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 { } else {
v.next_event_date.text = context.getString(R.string.charging) v.next_event_date.text =
context.getString(R.string.charging)
} }
showSomething = true showSomething = true
break@loop break@loop
@ -641,7 +692,9 @@ class MainWidget : AppWidgetProvider() {
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> { Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) { if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
v.second_row_icon.isVisible = false 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 showSomething = true
break@loop break@loop
} }
@ -654,9 +707,12 @@ class MainWidget : AppWidgetProvider() {
v.empty_layout.visibility = View.GONE v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE 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_small.visibility =
v.second_row_top_margin_medium.visibility = if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.value) View.VISIBLE else View.GONE if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.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_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 { } else {
v.second_row_icon.isVisible = false v.second_row_icon.isVisible = false
} }
@ -664,17 +720,33 @@ class MainWidget : AppWidgetProvider() {
// Color // Color
listOf<TextView>(v.empty_date, v.divider1, v.temp, v.next_event, v.next_event_difference_time, v.divider3, v.special_temp).forEach { listOf<TextView>(
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())) it.setTextColor(ColorHelper.getFontColor(context.applicationContext.isDarkTheme()))
} }
if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.value) { if (Preferences.weatherIconPack != Constants.WeatherIconPack.MINIMAL.value) {
listOf<ImageView>(v.action_next, v.action_previous) listOf<ImageView>(v.action_next, v.action_previous)
} else { } else {
listOf<ImageView>(v.action_next, v.action_previous, v.empty_weather_icon, v.special_weather_icon) listOf<ImageView>(
v.action_next,
v.action_previous,
v.empty_weather_icon,
v.special_weather_icon
)
}.forEach { }.forEach {
it.setColorFilter(ColorHelper.getFontColorRgb(context.applicationContext.isDarkTheme())) 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<TextView>(v.next_event_date, v.divider2, v.calendar_temp).forEach { listOf<TextView>(v.next_event_date, v.divider2, v.calendar_temp).forEach {
@ -687,7 +759,10 @@ class MainWidget : AppWidgetProvider() {
listOf<ImageView>(v.second_row_icon, v.weather_icon) listOf<ImageView>(v.second_row_icon, v.weather_icon)
}.forEach { }.forEach {
it.setColorFilter(ColorHelper.getSecondaryFontColorRgb(context.applicationContext.isDarkTheme())) 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 // Text Size
@ -727,35 +802,76 @@ class MainWidget : AppWidgetProvider() {
// Shadows // Shadows
val shadowRadius = when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { val shadowRadius =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> 0f 0 -> 0f
1 -> 5f 1 -> 5f
2 -> 5f 2 -> 5f
else -> 5f else -> 5f
} }
val shadowColor = when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { val shadowColor =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> Color.TRANSPARENT 0 -> Color.TRANSPARENT
1 -> R.color.black_50 1 -> R.color.black_50
2 -> Color.BLACK 2 -> Color.BLACK
else -> R.color.black_50 else -> R.color.black_50
} }
val shadowDy = when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) { val shadowDy =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> 0f 0 -> 0f
1 -> 0f 1 -> 0f
2 -> 1f 2 -> 1f
else -> 0f else -> 0f
} }
listOf<TextView>(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<TextView>(
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) it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
} }
// Custom Font // Custom Font
if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) { if (Preferences.customFont == Constants.CUSTOM_FONT_GOOGLE_SANS) {
val googleSans: Typeface = Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf") val googleSans: Typeface =
listOf<TextView>(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 { Typeface.createFromAsset(context.assets, "fonts/google_sans_regular.ttf")
listOf<TextView>(
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 it.typeface = googleSans
} }
} else if (Preferences.customFont == Constants.CUSTOM_FONT_DOWNLOADED && typeface != null) {
listOf<TextView>(
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 // Weather
@ -763,7 +879,12 @@ class MainWidget : AppWidgetProvider() {
v.weather.visibility = View.VISIBLE v.weather.visibility = View.VISIBLE
v.calendar_weather.visibility = View.VISIBLE v.calendar_weather.visibility = View.VISIBLE
v.special_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 val icon: String = Preferences.weatherIcon
if (icon == "") { if (icon == "") {
@ -772,8 +893,16 @@ class MainWidget : AppWidgetProvider() {
v.special_weather_icon.visibility = View.GONE v.special_weather_icon.visibility = View.GONE
} else { } else {
v.weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon)) v.weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
v.empty_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon)) v.empty_weather_icon.setImageResource(
v.special_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon)) WeatherHelper.getWeatherIconResource(
icon
)
)
v.special_weather_icon.setImageResource(
WeatherHelper.getWeatherIconResource(
icon
)
)
v.weather_icon.visibility = View.VISIBLE v.weather_icon.visibility = View.VISIBLE
v.empty_weather_icon.visibility = View.VISIBLE v.empty_weather_icon.visibility = View.VISIBLE
v.special_weather_icon.visibility = View.VISIBLE v.special_weather_icon.visibility = View.VISIBLE

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="viewModel"
type="com.tommasoberlose.anotherwidget.ui.viewmodels.CustomFontViewModel" />
</data>
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorPrimaryDark"
tools:context="com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="2dp"
app:cardCornerRadius="0dp"
android:id="@+id/toolbar"
app:cardBackgroundColor="@color/colorPrimary">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="10dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:layout_centerVertical="true"
android:id="@+id/action_back"
android:layout_alignParentLeft="true"
app:tint="@color/colorPrimaryText"
android:src="@drawable/round_arrow_back" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:text="@string/action_choose_application"
android:gravity="center"
style="@style/AnotherWidget.Main.Title"/>
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="10dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:layout_centerVertical="true"
android:id="@+id/action_filter"
android:layout_alignParentRight="true"
android:visibility="gone"
app:tint="@color/colorPrimaryText"
android:src="@drawable/round_filter_list" />
</RelativeLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardElevation="2dp"
app:cardCornerRadius="0dp"
app:cardBackgroundColor="@color/colorPrimary">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/colorPrimaryDark"
app:cardCornerRadius="9dp"
app:cardElevation="0dp"
android:layout_marginTop="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp">
<EditText
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/colorPrimaryDark"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:inputType="textCapWords"
android:textColor="@color/colorPrimaryText"
android:textColorHint="@color/colorSecondaryText"
android:textAlignment="viewStart"
android:id="@+id/search"
android:fontFamily="@font/google_sans"
android:gravity="center_vertical|start"
android:hint="@string/search"
android:text="@={viewModel.searchInput}"
android:autofillHints="" />
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.card.MaterialCardView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<androidx.core.widget.ContentLoadingProgressBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:indeterminateTint="@color/colorAccent"
android:layout_marginTop="-7dp"
android:id="@+id/loader"
style="@style/Widget.AppCompat.ProgressBar.Horizontal" />
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/list_view" />
</RelativeLayout>
</LinearLayout>
</layout>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical|start"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingEnd="32dp"
android:paddingStart="32dp"
android:focusable="true"
android:clickable="true"
android:textAlignment="viewStart"
android:background="?attr/selectableItemBackground"
android:textColor="@color/colorPrimaryText"
style="@style/AnotherWidget.Settings.Title"/>

View File

@ -27,6 +27,7 @@
<string name="settings_date_format_title">Formato data</string> <string name="settings_date_format_title">Formato data</string>
<string name="header_widget_background">Sfondo widget</string> <string name="header_widget_background">Sfondo widget</string>
<string name="settings_secondary_row_top_margin_title">Margine</string> <string name="settings_secondary_row_top_margin_title">Margine</string>
<string name="action_custom_font_to_search">Cerca font...</string>
<!-- Calendar --> <!-- Calendar -->
<string name="settings_calendar_title">Calendario</string> <string name="settings_calendar_title">Calendario</string>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<array name="com_google_android_gms_fonts_certs">
<item>@array/com_google_android_gms_fonts_certs_dev</item>
<item>@array/com_google_android_gms_fonts_certs_prod</item>
</array>
<string-array name="com_google_android_gms_fonts_certs_dev">
<item>
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
</item>
</string-array>
<string-array name="com_google_android_gms_fonts_certs_prod">
<item>
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
</item>
</string-array>
</resources>

View File

@ -29,6 +29,7 @@
<string name="settings_date_format_title">Date format</string> <string name="settings_date_format_title">Date format</string>
<string name="header_widget_background">Widget background</string> <string name="header_widget_background">Widget background</string>
<string name="settings_secondary_row_top_margin_title">Margin</string> <string name="settings_secondary_row_top_margin_title">Margin</string>
<string name="action_custom_font_to_search">Custom font...</string>
<!-- Calendar --> <!-- Calendar -->
<string name="settings_calendar_title">Calendar</string> <string name="settings_calendar_title">Calendar</string>