Compare commits

...

10 Commits

Author SHA1 Message Date
77864cbef4 Suppress unused parameter warnings. 2021-09-27 00:02:50 +08:00
32c580bac7 Merge branch 'patch-1' into patch-develop 2021-09-26 22:29:09 +08:00
85fa0cae11 Add weather providers HERE.com and AccuWeather.com; fix Weather.gov. 2021-09-26 22:28:06 +08:00
05f2a745c2 Merge branch 'patch-1' into patch-develop
# Conflicts:
#	app/src/main/java/com/tommasoberlose/anotherwidget/helpers/WeatherHelper.kt
2021-09-25 11:34:02 +08:00
ef2e89b6ff Correct weather info for weatherbit.io, weather.gov and yr.no. 2021-09-25 11:31:53 +08:00
a306d92282 Make text shadows more visible. 2021-09-25 11:08:10 +08:00
da9fc362af Merge branch 'patch-3' into patch-develop 2021-09-24 10:45:07 +08:00
ff83cfd953 Update translation. 2021-09-24 10:44:05 +08:00
5d9dcd9701 Replace Realm with Room. 2021-09-23 00:23:42 +08:00
183901534c Correct the widget layout.
Adjust the layout carefully, so that remote grid views perfectly overlap the bitmap generated from the binding view, whether left-aligned, right-aligned or centered, and regardless of the size of the widget, text, margins or spacing.

Display the clock in the correct text size.
2021-09-17 12:01:41 +08:00
37 changed files with 842 additions and 536 deletions

View File

@ -7,8 +7,6 @@ apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
def apikeyPropertiesFile = rootProject.file("apikey.properties")
def apikeyProperties = new Properties()
apikeyProperties.load(new FileInputStream(apikeyPropertiesFile))
@ -88,6 +86,10 @@ dependencies {
// EventBus
implementation 'org.greenrobot:eventbus:3.2.0'
// Room
implementation "androidx.room:room-runtime:2.3.0"
kapt "androidx.room:room-compiler:2.3.0"
// Navigation
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'

View File

@ -7,10 +7,6 @@ import androidx.appcompat.app.AppCompatDelegate
import com.chibatching.kotpref.Kotpref
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import io.realm.Realm
import io.realm.RealmConfiguration
import net.danlew.android.joda.JodaTimeAndroid
class AWApplication : Application() {
override fun onCreate() {
@ -24,12 +20,5 @@ class AWApplication : Application() {
// Dark theme
AppCompatDelegate.setDefaultNightMode(Preferences.darkThemePreference)
// Realm
Realm.init(this)
val config = RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.build()
Realm.setDefaultConfiguration(config)
}
}

View File

@ -18,7 +18,7 @@ class FixedFocusScrollView @JvmOverloads constructor(
var isScrollable = true
override fun scrollTo(x: Int, y: Int) {
if (isScrollable) {
if (isScrollable || !isLaidOut) {
super.scrollTo(x, y)
}
}

View File

@ -3,32 +3,37 @@ package com.tommasoberlose.anotherwidget.db
import android.content.Context
import android.provider.CalendarContract
import android.util.Log
import androidx.room.Dao
import androidx.room.Database
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Room
import androidx.room.RoomDatabase
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.applyFilters
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper.sortEvents
import com.tommasoberlose.anotherwidget.models.Event
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import io.realm.Realm
import io.realm.RealmResults
import java.util.*
import kotlin.Comparator
import kotlin.collections.ArrayList
class EventRepository(val context: Context) {
private val realm by lazy { Realm.getDefaultInstance() }
private val db by lazy { EventDatabase.getDatabase(context) }
fun saveEvents(eventList: List<Event>) {
realm.executeTransaction { realm ->
realm.where(Event::class.java).findAll().deleteAllFromRealm()
realm.copyToRealm(eventList)
db.runInTransaction{
db.dao().run {
deleteAll()
insertAll(eventList)
}
}
}
fun clearEvents() {
realm.executeTransaction { realm ->
realm.where(Event::class.java).findAll().deleteAllFromRealm()
}
db.dao().deleteAll()
}
fun resetNextEventData() {
@ -44,11 +49,11 @@ class EventRepository(val context: Context) {
}
fun saveNextEventData(event: Event) {
Preferences.nextEventId = event.eventID
Preferences.nextEventId = event.id
}
fun getNextEvent(): Event? {
val nextEvent = getEventByEventId(Preferences.nextEventId)
val nextEvent = getEventById(Preferences.nextEventId)
val now = Calendar.getInstance().timeInMillis
val limit = Calendar.getInstance().apply {
timeInMillis = now
@ -64,73 +69,63 @@ class EventRepository(val context: Context) {
else -> add(Calendar.HOUR, 6)
}
}
val event = if (nextEvent != null && nextEvent.endDate > now && nextEvent.startDate <= limit.timeInMillis) {
return if (nextEvent != null && nextEvent.endDate > now && nextEvent.startDate <= limit.timeInMillis) {
nextEvent
} else {
val events = getEvents()
if (events.isNotEmpty()) {
val newNextEvent = events.first()
Preferences.nextEventId = newNextEvent.eventID
Preferences.nextEventId = newNextEvent.id
newNextEvent
} else {
resetNextEventData()
null
}
}
return try {
realm.copyFromRealm(event!!)
} catch (ex: Exception) {
event
}
}
fun getEventByEventId(id: Long): Event? {
val event = realm.where(Event::class.java).equalTo("eventID", id).findFirst()
return try {
realm.copyFromRealm(event!!)
} catch (ex: Exception) {
event
}
fun getEventById(id: Long): Event? {
return db.dao().findById(id)
}
fun goToNextEvent() {
val eventList = getEvents()
if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
if (index > -1 && index < eventList.size - 1) {
Preferences.nextEventId = eventList[index + 1].eventID
Preferences.nextEventId = eventList[index + 1].id
} else {
Preferences.nextEventId = eventList.first().eventID
Preferences.nextEventId = eventList.first().id
}
} else {
resetNextEventData()
}
MainWidget.updateWidget(context)
org.greenrobot.eventbus.EventBus.getDefault().post(
com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent()
)
}
fun goToPreviousEvent() {
val eventList = getEvents()
if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
if (index > 0) {
Preferences.nextEventId = eventList[index - 1].eventID
Preferences.nextEventId = eventList[index - 1].id
} else {
Preferences.nextEventId = eventList.last().eventID
Preferences.nextEventId = eventList.last().id
}
} else {
resetNextEventData()
}
MainWidget.updateWidget(context)
org.greenrobot.eventbus.EventBus.getDefault().post(
com.tommasoberlose.anotherwidget.ui.fragments.MainFragment.UpdateUiMessageEvent()
)
}
fun getFutureEvents(): List<Event> {
val now = Calendar.getInstance().timeInMillis
realm.refresh()
return realm
.where(Event::class.java)
.greaterThan("endDate", now)
.findAll()
.applyFilters()
return db.dao().findFuture(Calendar.getInstance().timeInMillis).applyFilters().sortEvents()
}
private fun getEvents(): List<Event> {
@ -149,18 +144,54 @@ class EventRepository(val context: Context) {
else -> add(Calendar.HOUR, 6)
}
}
realm.refresh()
return realm
.where(Event::class.java)
.greaterThan("endDate", now)
.lessThanOrEqualTo("startDate", limit.timeInMillis)
.findAll()
.applyFilters()
return db.dao().find(now, limit.timeInMillis).applyFilters().sortEvents()
}
fun getEventsCount(): Int = getEvents().size
fun close() {
realm.close()
// db.close()
}
@Dao
interface EventDao {
@Query("SELECT * FROM events WHERE id = :id LIMIT 1")
fun findById(id: Long) : Event?
@Query("SELECT * FROM events WHERE end_date > :from")
fun findFuture(from: Long) : List<Event>
@Query("SELECT * FROM events WHERE end_date > :from and start_date <= :to")
fun find(from: Long, to: Long) : List<Event>
@Insert
fun insertAll(events: List<Event>)
@Query("DELETE FROM events")
fun deleteAll()
}
@Database(entities = arrayOf(Event::class), version = 1, exportSchema = false)
abstract class EventDatabase : RoomDatabase() {
abstract fun dao(): EventDao
companion object {
private var INSTANCE: EventDatabase? = null
fun getDatabase(context: Context): EventDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
EventDatabase::class.java,
"events"
).allowMainThreadQueries().build()
INSTANCE = instance
// return instance
instance
}
}
}
}
}

View File

@ -93,11 +93,11 @@ object Preferences : KotprefModel() {
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)
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 26f)
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 24f)
var textSecondSize by floatPref(key = "PREF_TEXT_SECOND_SIZE", default = 16f)
var clockTextSize by floatPref(key = "PREF_TEXT_CLOCK_SIZE", default = 72f)
var clockBottomMargin by intPref(default = Constants.ClockBottomMargin.MEDIUM.rawValue)
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.NONE.rawValue)
var secondRowTopMargin by intPref(default = Constants.SecondRowTopMargin.SMALL.rawValue)
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")

View File

@ -44,8 +44,8 @@ object BitmapHelper {
FirebaseCrashlytics.getInstance().setCustomKey("HEIGHT SPEC", measuredHeight)
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredWidth", view.measuredWidth)
FirebaseCrashlytics.getInstance().setCustomKey("VIEW measuredHeight", view.measuredHeight)
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final width", measuredWidth)
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final height", view.measuredHeight)
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final width", widgetWidth)
FirebaseCrashlytics.getInstance().setCustomKey("WIDGET final height", widgetHeight)
}
return try {
@ -58,7 +58,7 @@ object BitmapHelper {
//Bind a canvas to it
val canvas = Canvas(btm)
// draw the view on the canvas
view.layout(0, 0, measuredWidth, measuredHeight)
view.layout(0, 0, widgetWidth, widgetHeight)
view.draw(canvas)
//return the bitmap
}

View File

@ -17,7 +17,7 @@ object ImageHelper {
0 -> 0f * factor
1 -> 8f * factor
2 -> 16f * factor
else -> 0f * factor
else -> 8f * factor
}, resources.displayMetrics)
if (originalView.drawable != null && originalView.drawable.intrinsicWidth > 0 && originalView.drawable.intrinsicHeight > 0) {
@ -58,7 +58,7 @@ object ImageHelper {
0 -> 0f * factor
1 -> 0.8f * factor
2 -> 1f * factor
else -> 0f
else -> 0.8f * factor
}))
colorMatrixScript.setColorMatrix(matrix)

View File

@ -339,92 +339,92 @@ object WeatherHelper {
}
}
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when {
iconString.contains("skc") -> "01"
iconString.contains("few") -> "02"
iconString.contains("sct") -> "03"
iconString.contains("bkn") -> "04"
iconString.contains("ovc") -> "04"
iconString.contains("wind_skc") -> "01"
iconString.contains("wind_few") -> "02"
iconString.contains("wind_sct") -> "03"
iconString.contains("wind_bkn") -> "04"
iconString.contains("wind_ovc") -> "04"
iconString.contains("snow") -> "13"
iconString.contains("rain_snow") -> "81"
iconString.contains("rain_sleet") -> "81"
iconString.contains("snow_sleet") -> "81"
iconString.contains("fzra") -> "81"
iconString.contains("rain_fzra") -> "81"
iconString.contains("snow_fzra") -> "81"
iconString.contains("sleet") -> "81"
iconString.contains("rain") -> "10"
iconString.contains("rain_showers") -> "10"
iconString.contains("rain_showers_hi") -> "10"
iconString.contains("tsra") -> "82"
iconString.contains("tsra_sct") -> "82"
iconString.contains("tsra_hi") -> "82"
iconString.contains("tornado") -> "80"
iconString.contains("hurricane") -> "80"
iconString.contains("tropical_storm") -> "09"
iconString.contains("dust") -> "Dust"
iconString.contains("smoke") -> "Smoke"
iconString.contains("haze") -> "50"
iconString.contains("hot") -> "01"
iconString.contains("cold") -> "13"
iconString.contains("blizzard") -> "80"
iconString.contains("fog") -> "82"
fun getWeatherGovIcon(iconString: String, isDaytime: Boolean): String = when (iconString.substringBefore('?').substringAfterLast('/')) {
"skc" -> "01"
"few" -> "02"
"sct" -> "02"
"bkn" -> "03"
"ovc" -> "04"
"wind_skc" -> "01"
"wind_few" -> "02"
"wind_sct" -> "02"
"wind_bkn" -> "03"
"wind_ovc" -> "04"
"snow" -> "13"
"rain_snow" -> "81"
"rain_sleet" -> "81"
"snow_sleet" -> "81"
"fzra" -> "81"
"rain_fzra" -> "81"
"snow_fzra" -> "81"
"sleet" -> "81"
"rain" -> "10"
"rain_showers" -> "10"
"rain_showers_hi" -> "10"
"tsra" -> "09"
"tsra_sct" -> "11"
"tsra_hi" -> "11"
"tornado" -> "80"
"hurricane" -> "80"
"tropical_storm" -> "09"
"dust" -> "50"
"smoke" -> "50"
"haze" -> "50"
"hot" -> "01"
"cold" -> "13"
"blizzard" -> "13"
"fog" -> "82"
else -> ""
} + if (isDaytime) "d" else "n"
fun getWeatherBitIcon(iconString: String): String = when {
iconString.contains("t01") -> "11"
iconString.contains("t02") -> "09"
iconString.contains("t03") -> "09"
iconString.contains("t04") -> "09"
iconString.contains("t05") -> "09"
iconString.contains("d01") -> "10"
iconString.contains("d02") -> "10"
iconString.contains("d03") -> "10"
iconString.contains("r01") -> "10"
iconString.contains("r02") -> "10"
iconString.contains("r03") -> "10"
iconString.contains("f01") -> "10"
iconString.contains("r04") -> "10"
iconString.contains("r05") -> "10"
iconString.contains("r06") -> "10"
iconString.contains("s01") -> "13"
iconString.contains("s02") -> "13"
iconString.contains("s03") -> "13"
iconString.contains("s04") -> "81"
iconString.contains("s05") -> "90"
iconString.contains("s06") -> "13"
iconString.contains("a01") -> "82"
iconString.contains("a02") -> "82"
iconString.contains("a03") -> "82"
iconString.contains("a04") -> "82"
iconString.contains("a05") -> "82"
iconString.contains("a06") -> "82"
iconString.contains("c01") -> "01"
iconString.contains("c02") -> "02"
iconString.contains("c03") -> "04"
iconString.contains("c04") -> "04"
fun getWeatherBitIcon(iconString: String): String = when (iconString.substring(0, 3)) {
"t01" -> "11"
"t02" -> "11"
"t03" -> "09"
"t04" -> "11"
"t05" -> "11"
"d01" -> "10"
"d02" -> "10"
"d03" -> "10"
"r01" -> "10"
"r02" -> "10"
"r03" -> "10"
"f01" -> "10"
"r04" -> "10"
"r05" -> "10"
"r06" -> "10"
"s01" -> "13"
"s02" -> "13"
"s03" -> "13"
"s04" -> "81"
"s05" -> "81"
"s06" -> "13"
"a01" -> "50"
"a02" -> "50"
"a03" -> "50"
"a04" -> "50"
"a05" -> "82"
"a06" -> "82"
"c01" -> "01"
"c02" -> "02"
"c03" -> "03"
"c04" -> "04"
else -> ""
} + if (iconString.contains("d")) "d" else "n"
} + iconString.substring(3)
fun getWeatherApiIcon(icon: Int, isDaytime: Boolean): String = when(icon) {
1000 -> "01"
1003 -> "02"
1006 -> "03"
1009 -> "04"
1030 -> "82"
1030 -> "50"
1063 -> "10"
1066 -> "10"
1069 -> "10"
1066 -> "13"
1069 -> "81"
1072 -> "81"
1087 -> "11"
1114 -> "13"
1117 -> "09"
1117 -> "13"
1135 -> "82"
1147 -> "82"
1150 -> "10"
@ -439,8 +439,8 @@ object WeatherHelper {
1195 -> "10"
1198 -> "81"
1201 -> "81"
1204 -> "13"
1207 -> "13"
1204 -> "81"
1207 -> "81"
1210 -> "13"
1213 -> "13"
1216 -> "13"
@ -451,62 +451,62 @@ object WeatherHelper {
1240 -> "10"
1243 -> "10"
1246 -> "10"
1249 -> "13"
1252 -> "13"
1249 -> "81"
1252 -> "81"
1255 -> "13"
1258 -> "13"
1261 -> "13"
1264 -> "13"
1273 -> "09"
1273 -> "11"
1276 -> "09"
1279 -> "13"
1282 -> "13"
else -> ""
} + if (isDaytime) "d" else "n"
fun getYRIcon(iconCode: String, isDaytime: Boolean): String = when {
iconCode.contains("clearsky") -> "01"
iconCode.contains("cloudy") -> "04"
iconCode.contains("fair") -> "02"
iconCode.contains("fog") -> "82"
iconCode.contains("heavyrain") -> "10"
iconCode.contains("heavyrainandthunder") -> "11"
iconCode.contains("heavyrainshowers") -> "10"
iconCode.contains("heavyrainshowersandthunder") -> "11"
iconCode.contains("heavysleet") -> "10"
iconCode.contains("heavysleetandthunder") -> "11"
iconCode.contains("heavysleetshowers") -> "10"
iconCode.contains("heavysleetshowersandthunder") -> "11"
iconCode.contains("heavysnow") -> "13"
iconCode.contains("heavysnowandthunder") -> "13"
iconCode.contains("heavysnowshowers") -> "13"
iconCode.contains("heavysnowshowersandthunder") -> "13"
iconCode.contains("lightrain") -> "10"
iconCode.contains("lightrainandthunder") -> "11"
iconCode.contains("lightrainshowers") -> "10"
iconCode.contains("lightrainshowersandthunder") -> "11"
iconCode.contains("lightsleet") -> "10"
iconCode.contains("lightsleetandthunder") -> "11"
iconCode.contains("lightsleetshowers") -> "10"
iconCode.contains("lightsnow") -> "13"
iconCode.contains("lightsnowandthunder") -> "13"
iconCode.contains("lightsnowshowers") -> "13"
iconCode.contains("lightssleetshowersandthunder") -> "81"
iconCode.contains("lightssnowshowersandthunder") -> "81"
iconCode.contains("partlycloudy") -> "03"
iconCode.contains("rain") -> "10"
iconCode.contains("rainandthunder") -> "11"
iconCode.contains("rainshowers") -> "10"
iconCode.contains("rainshowersandthunder") -> "11"
iconCode.contains("sleet") -> "10"
iconCode.contains("sleetandthunder") -> "11"
iconCode.contains("sleetshowers") -> "10"
iconCode.contains("sleetshowersandthunder") -> "11"
iconCode.contains("snow") -> "13"
iconCode.contains("snowandthunder") -> "13"
iconCode.contains("snowshowers") -> "13"
iconCode.contains("snowshowersandthunder") -> "13"
fun getYRIcon(iconCode: String): String = when (iconCode.substringBefore('_')) {
"clearsky" -> "01"
"cloudy" -> "04"
"fair" -> "02"
"fog" -> "82"
"heavyrain" -> "10"
"heavyrainandthunder" -> "09"
"heavyrainshowers" -> "10"
"heavyrainshowersandthunder" -> "09"
"heavysleet" -> "81"
"heavysleetandthunder" -> "81"
"heavysleetshowers" -> "81"
"heavysleetshowersandthunder" -> "81"
"heavysnow" -> "13"
"heavysnowandthunder" -> "13"
"heavysnowshowers" -> "13"
"heavysnowshowersandthunder" -> "13"
"lightrain" -> "10"
"lightrainandthunder" -> "11"
"lightrainshowers" -> "10"
"lightrainshowersandthunder" -> "11"
"lightsleet" -> "81"
"lightsleetandthunder" -> "81"
"lightsleetshowers" -> "81"
"lightsnow" -> "13"
"lightsnowandthunder" -> "13"
"lightsnowshowers" -> "13"
"lightssleetshowersandthunder" -> "81"
"lightssnowshowersandthunder" -> "81"
"partlycloudy" -> "03"
"rain" -> "10"
"rainandthunder" -> "11"
"rainshowers" -> "10"
"rainshowersandthunder" -> "11"
"sleet" -> "81"
"sleetandthunder" -> "81"
"sleetshowers" -> "81"
"sleetshowersandthunder" -> "81"
"snow" -> "13"
"snowandthunder" -> "13"
"snowshowers" -> "13"
"snowshowersandthunder" -> "13"
else -> ""
} + if (isDaytime) "d" else "n"
} + if (iconCode.substringAfter('_', "day") == "day") "d" else "n"
}

View File

@ -25,8 +25,15 @@ object WidgetHelper {
) {
fun getWidgetsSize(widgetId: Int): Pair<Int, Int> {
val width = getWidgetWidth(widgetId)
val height = getWidgetHeight(widgetId)
val portrait = context.resources.configuration.orientation == ORIENTATION_PORTRAIT
val width = getWidgetSizeInDp(
widgetId,
if (portrait) AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH else AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH
)
val height = getWidgetSizeInDp(
widgetId,
if (portrait) AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT else AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT
)
val widthInPx = context.dip(width)
val heightInPx = context.dip(height)
FirebaseCrashlytics.getInstance().setCustomKey("widthInPx", widthInPx)

View File

@ -1,26 +1,35 @@
package com.tommasoberlose.anotherwidget.models
import android.provider.CalendarContract
import io.realm.RealmObject
import java.util.Date
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
/**
* Created by tommaso on 05/10/17.
*/
open class Event(
var id: Long = 0,
var eventID: Long = 0,
var title: String = "",
var startDate: Long = 0,
var endDate: Long = 0,
var calendarID: Int = 0,
var allDay: Boolean = false,
var address: String = "",
var selfAttendeeStatus: Int = CalendarContract.Attendees.ATTENDEE_STATUS_NONE,
var availability: Int = CalendarContract.EventsEntity.AVAILABILITY_BUSY
) : RealmObject() {
@Entity(tableName = "events")
data class Event(
@PrimaryKey
val id: Long = 0,
@ColumnInfo(name = "event_id")
val eventID: Long = 0,
val title: String = "",
@ColumnInfo(name = "start_date")
val startDate: Long = 0,
@ColumnInfo(name = "end_date")
val endDate: Long = 0,
@ColumnInfo(name = "calendar_id")
val calendarID: Long = 0,
@ColumnInfo(name = "all_day")
val allDay: Boolean = false,
val address: String = "",
@ColumnInfo(name = "self_attendee_status")
val selfAttendeeStatus: Int = CalendarContract.Attendees.ATTENDEE_STATUS_NONE,
val availability: Int = CalendarContract.EventsEntity.AVAILABILITY_BUSY
)/* {
override fun toString(): String {
return "Event:\nEVENT ID: " + eventID + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate) + "\nCAL ID: " + calendarID + "\nADDRESS: " + address
}
}
}*/

View File

@ -26,9 +26,7 @@ class TimeZonesApi(val context: Context) {
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()
}

View File

@ -121,25 +121,34 @@ class WeatherNetworkApi(val context: Context) {
val props =
weatherResponse.body["properties"] as LinkedTreeMap<*, *>
val periods = props["periods"] as List<*>
val now = periods[0] as LinkedTreeMap<*, *>
@android.annotation.SuppressLint("SimpleDateFormat")
val format = SimpleDateFormat(
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N)
"yyyy-MM-dd'T'HH:mm:ssXXX"
else
"yyyy-MM-dd'T'HH:mm:ssZ"
)
for (period in periods) {
val now = period as LinkedTreeMap<*, *>
val endTime = format.parse(now["endTime"] as String)!!
if (endTime.time > System.currentTimeMillis()) {
val temp = now["temperature"] as Double
val fullIcon = now["icon"] as String
val isDaytime = now["isDaytime"] as Boolean
val temp = now["temperature"] as Double
val fullIcon = now["icon"] as String
val isDaytime = now["isDaytime"] as Boolean
Preferences.weatherTemp = temp.toFloat()
Preferences.weatherIcon = WeatherHelper.getWeatherGovIcon(fullIcon, isDaytime)
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
MainWidget.updateWidget(context)
Preferences.weatherTemp = temp.toFloat()
Preferences.weatherIcon = WeatherHelper.getWeatherGovIcon(fullIcon, isDaytime)
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
MainWidget.updateWidget(context)
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
break
}
}
} catch (ex: Exception) {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
Preferences.weatherProviderLocationError = ""
} finally {
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
}
}
else -> {
@ -155,14 +164,16 @@ class WeatherNetworkApi(val context: Context) {
}
}
is NetworkResponse.ServerError -> {
if (pointsResponse.body?.containsKey("status") == true && (pointsResponse.body?.get("status") as Double).toInt() == 404) {
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_wrong_location)
} else {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
Preferences.weatherProviderLocationError = ""
when (pointsResponse.code) {
404 -> {
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = context.getString(R.string.weather_provider_error_wrong_location)
}
else -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
Preferences.weatherProviderLocationError = ""
}
}
WeatherHelper.removeWeather(
context
)
@ -183,7 +194,18 @@ class WeatherNetworkApi(val context: Context) {
when (val response = repository.getWeather()) {
is NetworkResponse.Success -> {
try {
Log.d("ciao - here", response.body.toString())
val observations = response.body["observations"] as LinkedTreeMap<*, *>
val location = (observations["location"] as List<*>).first() as LinkedTreeMap<*, *>
val observation = (location["observation"] as List<*>).first() as LinkedTreeMap<*, *>
val iconName = observation["iconName"] as String
val daylight = observation["daylight"] as String
val temperature = observation["temperature"] as String
Preferences.weatherTemp = temperature.toFloat()
Preferences.weatherIcon = repository.getWeatherIcon(iconName, daylight != "N")
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
MainWidget.updateWidget(context)
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
} catch(ex: Exception) {
@ -194,8 +216,16 @@ class WeatherNetworkApi(val context: Context) {
}
}
is NetworkResponse.ServerError -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
Preferences.weatherProviderLocationError = ""
when (response.code) {
401 -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_invalid_key)
Preferences.weatherProviderLocationError = ""
}
else -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
Preferences.weatherProviderLocationError = ""
}
}
WeatherHelper.removeWeather(
context
)
@ -225,10 +255,10 @@ class WeatherNetworkApi(val context: Context) {
when (val response = repository.getWeather()) {
is NetworkResponse.Success -> {
try {
val data = response.body["data"] as List<LinkedTreeMap<String, Any>>?
data?.first()?.let {
val data = response.body["data"] as List<*>?
data?.first()?.let { it as LinkedTreeMap<*, *>
val temp = it["temp"] as Double
val weatherInfo = it["weather"] as LinkedTreeMap<String, Any>
val weatherInfo = it["weather"] as LinkedTreeMap<*, *>
val iconCode = weatherInfo["icon"] as String
Preferences.weatherTemp = temp.toFloat()
@ -238,8 +268,6 @@ class WeatherNetworkApi(val context: Context) {
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
}
} catch(ex: Exception) {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
@ -288,12 +316,12 @@ class WeatherNetworkApi(val context: Context) {
when (val response = repository.getWeather()) {
is NetworkResponse.Success -> {
try {
val current = response.body["current"] as LinkedTreeMap<String, Any>?
val current = response.body["current"] as LinkedTreeMap<*, *>?
current?.let {
val tempC = current["temp_c"] as Double
val tempF = current["temp_f"] as Double
val isDay = current["is_day"] as Double
val condition = current["condition"] as LinkedTreeMap<String, Any>
val condition = current["condition"] as LinkedTreeMap<*, *>
val iconCode = condition["code"] as Double
Preferences.weatherTemp = if (Preferences.weatherTempUnit == "F") tempF.toFloat() else tempC.toFloat()
@ -303,8 +331,6 @@ class WeatherNetworkApi(val context: Context) {
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
}
} catch(ex: Exception) {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
@ -353,28 +379,74 @@ class WeatherNetworkApi(val context: Context) {
private suspend fun useAccuweatherProvider(context: Context) {
if (Preferences.weatherProviderApiAccuweather != "") {
// val repository = AccuweatherRepository()
val repository = AccuweatherRepository()
// when (val response = repository.getWeather()) {
// is NetworkResponse.Success -> {
// try {
// Log.d("ciao", response.body.toString())
// } catch(ex: Exception) {
//
// Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
// Preferences.weatherProviderLocationError = ""
// }
// }
// is NetworkResponse.ServerError -> {
// WeatherHelper.removeWeather(
// context
// )
// }
// Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
// Preferences.weatherProviderLocationError = ""
// EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
// }
when (val locationResponse = repository.getLocation()) {
is NetworkResponse.Success -> {
try {
val key = locationResponse.body["Key"] as String
when (val weatherResponse = repository.getWeather(key)) {
is NetworkResponse.Success -> {
try {
weatherResponse.body.first().let {
val temp = it["Temperature"] as LinkedTreeMap<*, *>
val tempC = (temp["Metric"] as LinkedTreeMap<*, *>)["Value"] as Double
val tempF = (temp["Imperial"] as LinkedTreeMap<*, *>)["Value"] as Double
val isDay = it["IsDayTime"] as Boolean
val icon = it["WeatherIcon"] as Double
Preferences.weatherTemp = if (Preferences.weatherTempUnit == "F") tempF.toFloat() else tempC.toFloat()
Preferences.weatherIcon = repository.getWeatherIcon(icon.toInt(), isDay)
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
MainWidget.updateWidget(context)
}
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
} catch (ex: Exception) {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
Preferences.weatherProviderLocationError = ""
}
}
else -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_connection)
Preferences.weatherProviderLocationError = ""
}
}
} catch(ex: Exception) {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
Preferences.weatherProviderLocationError = ""
} finally {
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
}
}
is NetworkResponse.ServerError -> {
when (locationResponse.code) {
401 -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_invalid_key)
Preferences.weatherProviderLocationError = ""
}
503 -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_expired_key)
Preferences.weatherProviderLocationError = ""
}
else -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)
Preferences.weatherProviderLocationError = ""
}
}
WeatherHelper.removeWeather(
context
)
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
}
else -> {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_connection)
Preferences.weatherProviderLocationError = ""
EventBus.getDefault().post(MainFragment.UpdateUiMessageEvent())
}
}
} else {
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_missing_key)
Preferences.weatherProviderLocationError = ""
@ -393,38 +465,27 @@ class WeatherNetworkApi(val context: Context) {
is NetworkResponse.Success -> {
try {
val pp = response.body["properties"] as LinkedTreeMap<*, *>
val data = pp["timeseries"] as List<LinkedTreeMap<String, Any>>?
data?.let {
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
for (item in data) {
val time = Calendar.getInstance().apply { time = format.parse(item["time"] as String)!! }
val now = Calendar.getInstance()
if (time.timeInMillis >= now.timeInMillis) {
val dd = item["data"] as LinkedTreeMap<*, *>
val instant = dd["instant"] as LinkedTreeMap<*, *>
val next = dd["next_1_hours"] as LinkedTreeMap<*, *>
val data = pp["timeseries"] as List<*>?
data?.first()?.let { it as LinkedTreeMap<*, *>
val dd = it["data"] as LinkedTreeMap<*, *>
val instant = dd["instant"] as LinkedTreeMap<*, *>
val next = dd["next_1_hours"] as LinkedTreeMap<*, *>
val details = instant["details"] as LinkedTreeMap<*, *>
val temp = details["air_temperature"] as Double
val details = instant["details"] as LinkedTreeMap<*, *>
val temp = details["air_temperature"] as Double
val summary = next["summary"] as LinkedTreeMap<*, *>
val iconCode = summary["symbol_code"] as String
val summary = next["summary"] as LinkedTreeMap<*, *>
val iconCode = summary["symbol_code"] as String
Preferences.weatherTemp = temp.toFloat()
Preferences.weatherIcon = WeatherHelper.getYRIcon(iconCode, now.get(Calendar.HOUR_OF_DAY) >= 22 || now.get(Calendar.HOUR_OF_DAY) <= 8)
Preferences.weatherTempUnit = "C"
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
MainWidget.updateWidget(context)
Preferences.weatherTemp = temp.toFloat()
Preferences.weatherIcon = WeatherHelper.getYRIcon(iconCode)
Preferences.weatherTempUnit = "C"
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
MainWidget.updateWidget(context)
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
break
}
}
Preferences.weatherProviderError = ""
Preferences.weatherProviderLocationError = ""
}
} catch(ex: Exception) {
ex.printStackTrace()
Preferences.weatherProviderError = context.getString(R.string.weather_provider_error_generic)

View File

@ -13,7 +13,7 @@ object ApiServices {
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
@Headers("User-Agent: (Another Widget, tommaso.berlose@gmail.com)")
@GET("gridpoints/{gridId}/{gridX},{gridY}/forecast")
@GET("gridpoints/{gridId}/{gridX},{gridY}/forecast/hourly")
suspend fun getWeather(
@Path("gridId") gridId: String,
@Path("gridX") gridX: Int,
@ -54,13 +54,17 @@ object ApiServices {
}
interface AccuweatherService {
@GET("")
suspend fun getWeather(
@Path("gridId") gridId: String,
@Path("gridX") gridX: Int,
@Path("gridY") gridY: Int,
@Query("units") unit: String
@GET("locations/v1/cities/geoposition/search")
suspend fun getLocation(
@Query("apikey") apikey: String,
@Query("q") location: String
): NetworkResponse<HashMap<String, Any>, HashMap<String, Any>>
@GET("currentconditions/v1/{locationKey}")
suspend fun getWeather(
@Path("locationKey") locationKey: String,
@Query("apikey") apikey: String
): NetworkResponse<List<HashMap<String, Any>>, HashMap<String, Any>>
}
interface YrService {

View File

@ -1,6 +1,7 @@
package com.tommasoberlose.anotherwidget.network.repository
import com.haroldadmin.cnradapter.NetworkResponseAdapterFactory
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.network.api.ApiServices
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
@ -9,10 +10,11 @@ class AccuweatherRepository {
/* ACCUWEATHER */
private val apiServiceAccu: ApiServices.AccuweatherService = getRetrofit().create(ApiServices.AccuweatherService::class.java)
suspend fun getWeather(): Nothing = TODO()
suspend fun getLocation() = apiServiceAccu.getLocation(Preferences.weatherProviderApiAccuweather, "${Preferences.customLocationLat},${Preferences.customLocationLon}")
suspend fun getWeather(locationKey: String) = apiServiceAccu.getWeather(locationKey, Preferences.weatherProviderApiAccuweather)
companion object {
private const val BASE_URL_ACCU = ""
private const val BASE_URL_ACCU = "https://dataservice.accuweather.com/"
private fun getRetrofit(): Retrofit {
return Retrofit.Builder()
@ -22,4 +24,20 @@ class AccuweatherRepository {
.build()
}
}
fun getWeatherIcon(icon: Int, isDaytime: Boolean): String = when(icon) {
1, 2, 30, 33, 34 -> "01"
3, 4, 35, 36 -> "02"
5, 37 -> "50"
6, 38 -> "03"
7, 8 -> "04"
11 -> "82"
12, 13, 14, 18, 39, 40 -> "10"
15 -> "09"
16, 17, 41, 42 -> "11"
32 -> "80"
19, 20, 21, 22, 23, 24, 31, 43, 44 -> "13"
25, 26, 29 -> "81"
else -> ""
} + if (isDaytime) "d" else "n"
}

View File

@ -23,4 +23,157 @@ class HereRepository {
.build()
}
}
fun getWeatherIcon(iconName: String, isDaytime: Boolean): String = when(iconName.substringAfter("night_")) {
"sunny" -> "01"
"clear" -> "01"
"mostly_sunny" -> "01"
"mostly_clear" -> "01"
"passing_clounds" -> "02"
"more_sun_than_clouds" -> "02"
"scattered_clouds" -> "02"
"partly_cloudy" -> "02"
"a_mixture_of_sun_and_clouds" -> "03"
"increasing_cloudiness" -> "03"
"breaks_of_sun_late" -> "03"
"afternoon_clouds" -> "03"
"morning_clouds" -> "03"
"partly_sunny" -> "03"
"high_level_clouds" -> "03"
"decreasing_cloudiness" -> "03"
"clearing_skies" -> "01"
"high_clouds" -> "03"
"rain_early" -> "10"
"heavy_rain_early" -> "10"
"strong_thunderstorms" -> "09"
"severe_thunderstorms" -> "09"
"thundershowers" -> "11"
"thunderstorms" -> "11"
"tstorms_early" -> "11"
"isolated_tstorms_late" -> "11"
"scattered_tstorms_late" -> "11"
"tstorms_late" -> "11"
"tstorms" -> "11"
"ice_fog" -> "82"
"more_clouds_than_sun" -> "03"
"broken_clouds" -> "03"
"scattered_showers" -> "10"
"a_few_showers" -> "10"
"light_showers" -> "10"
"passing_showers" -> "10"
"rain_showers" -> "10"
"showers" -> "10"
"widely_scattered_tstorms" -> "11"
"isolated_tstorms" -> "11"
"a_few_tstorms" -> "11"
"scattered_tstorms" -> "11"
"hazy_sunshine" -> "50"
"haze" -> "50"
"smoke" -> "50"
"low_level_haze" -> "50"
"early_fog_followed_by_sunny_skies" -> "50"
"early_fog" -> "82"
"light_fog" -> "82"
"fog" -> "82"
"dense_fog" -> "82"
//"night_haze"
//"night_smoke"
//"night_low_level_haze"
//"night_widely_scattered_tstorms"
//"night_isolated_tstorms"
//"night_a_few_tstorms"
//"night_scattered_tstorms"
//"night_tstorms"
//"night_clear"
"mostly_cloudy" -> "03"
"cloudy" -> "04"
"overcast" -> "04"
"low_clouds" -> "03"
"hail" -> "10"
"sleet" -> "81"
"light_mixture_of_precip" -> "81"
"icy_mix" -> "81"
"mixture_of_precip" -> "81"
"heavy_mixture_of_precip" -> "81"
"snow_changing_to_rain" -> "81"
"snow_changing_to_an_icy_mix" -> "81"
"an_icy_mix_changing_to_snow" -> "81"
"an_icy_mix_changing_to_rain" -> "81"
"rain_changing_to_snow" -> "81"
"rain_changing_to_an_icy_mix" -> "81"
"light_icy_mix_early" -> "81"
"icy_mix_early" -> "81"
"light_icy_mix_late" -> "81"
"icy_mix_late" -> "81"
"snow_rain_mix" -> "81"
"scattered_flurries" -> "13"
"snow_flurries" -> "13"
"light_snow_showers" -> "13"
"snow_showers" -> "13"
"light_snow" -> "13"
"flurries_early" -> "13"
"snow_showers_early" -> "13"
"light_snow_early" -> "13"
"flurries_late" -> "13"
"snow_showers_late" -> "13"
"light_snow_late" -> "13"
//"night_decreasing_cloudiness"
//"night_clearing_skies"
//"night_high_level_clouds"
//"night_high_clouds"
//"night_scattered_showers"
//"night_a_few_showers"
//"night_light_showers"
//"night_passing_showers"
//"night_rain_showers"
//"night_sprinkles"
//"night_showers"
//"night_mostly_clear"
//"night_passing_clouds"
//"night_scattered_clouds"
//"night_partly_cloudy"
//"increasing_cloudiness"
//"night_afternoon_clouds"
//"night_morning_clouds"
//"night_broken_clouds"
//"night_mostly_cloudy"
"light_freezing_rain" -> "81"
"freezing_rain" -> "81"
"heavy_rain" -> "10"
"lots_of_rain" -> "10"
"tons_of_rain" -> "10"
//"heavy_rain_early" -> "10"
"heavy_rain_late" -> "10"
"flash_floods" -> "10"
"flood" -> "10"
"drizzle" -> "10"
"sprinkles" -> "10"
"light_rain" -> "10"
"sprinkles_early" -> "10"
"light_rain_early" -> "10"
"sprinkles_late" -> "10"
"light_rain_late" -> "10"
"rain" -> "10"
"numerous_showers" -> "10"
"showery" -> "10"
"showers_early" -> "10"
//"rain_early" -> "10"
"showers_late" -> "10"
"rain_late" -> "10"
"snow" -> "13"
"moderate_snow" -> "13"
"snow_early" -> "13"
"snow_late" -> "13"
"heavy_snow" -> "13"
"heavy_snow_early" -> "13"
"heavy_snow_late" -> "13"
"tornado" -> "80"
"tropical_storm" -> "09"
"hurricane" -> "80"
"sandstorm" -> "50"
"duststorm" -> "50"
"snowstorm" -> "13"
"blizzard" -> "13"
else -> ""
} + if (isDaytime) "d" else "n"
}

View File

@ -95,7 +95,7 @@ class UpdatesReceiver : BroadcastReceiver() {
setEventUpdate(context, event)
}
} else {
val event = eventRepository.getEventByEventId(eventId)
val event = eventRepository.getEventById(eventId)
if (event != null) {
setEventUpdate(context, event)
}
@ -166,11 +166,11 @@ class UpdatesReceiver : BroadcastReceiver() {
fireTime.coerceAtLeast(now.timeInMillis + 1000 * 60),
PendingIntent.getBroadcast(
context,
event.eventID.toInt(),
event.id.toInt(),
Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
if (event.startDate > now.timeInMillis)
putExtra(EVENT_ID, event.eventID)
putExtra(EVENT_ID, event.id)
},
PendingIntent.FLAG_UPDATE_CURRENT
)
@ -185,7 +185,7 @@ class UpdatesReceiver : BroadcastReceiver() {
}, 0))
val eventRepository = EventRepository(context)
eventRepository.getFutureEvents().forEach {
cancel(PendingIntent.getBroadcast(context, it.eventID.toInt(), Intent(context, UpdatesReceiver::class.java).apply {
cancel(PendingIntent.getBroadcast(context, it.id.toInt(), Intent(context, UpdatesReceiver::class.java).apply {
action = Actions.ACTION_TIME_UPDATE
}, 0))
}

View File

@ -143,7 +143,7 @@ class UpdateCalendarService : Service() {
title = e.title ?: "",
startDate = instance.begin,
endDate = instance.end,
calendarID = e.calendarId.toInt(),
calendarID = e.calendarId,
allDay = e.allDay,
address = e.eventLocation ?: "",
selfAttendeeStatus = e.selfAttendeeStatus.toInt(),

View File

@ -115,8 +115,6 @@ class WeatherProviderActivity : AppCompatActivity() {
adapter.updateData(
Constants.WeatherProvider.values().asList()
.filter { it != Constants.WeatherProvider.HERE }
.filter { it != Constants.WeatherProvider.ACCUWEATHER }
)
setupListener()
@ -165,7 +163,7 @@ class WeatherProviderActivity : AppCompatActivity() {
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(ignore: MainFragment.UpdateUiMessageEvent?) {
fun onMessageEvent(@Suppress("UNUSED_PARAMETER") ignore: MainFragment.UpdateUiMessageEvent?) {
binding.loader.isVisible = Preferences.weatherProviderError == "-"
if (Preferences.weatherProviderError == "" && Preferences.weatherProviderLocationError == "") {
Snackbar.make(binding.listView, getString(R.string.settings_weather_provider_api_key_subtitle_all_set), Snackbar.LENGTH_LONG).show()

View File

@ -86,6 +86,7 @@ class MainFragment : Fragment() {
binding.actionSettings.isClickable = !show
binding.actionSettings.isFocusable = !show
binding.fragmentTitle.text = if (show) destination.label.toString() else getString(R.string.app_name)
binding.toolbar.cardElevation = 0f
}
binding.actionSettings.setOnSingleClickListener {
@ -98,6 +99,10 @@ class MainFragment : Fragment() {
}
private fun subscribeUi(viewModel: MainViewModel) {
viewModel.showPreview.observe(viewLifecycleOwner) {
binding.preview.visibility = if (it) View.VISIBLE else View.GONE
}
viewModel.showWallpaper.observe(viewLifecycleOwner) {
if (it) {
val wallpaper = requireActivity().getCurrentWallpaper()
@ -138,7 +143,7 @@ class MainFragment : Fragment() {
}
viewModel.fragmentScrollY.observe(viewLifecycleOwner) {
binding.toolbar.cardElevation = if (it > 0) 24f else 0f
binding.toolbar.cardElevation = if (it > 0) 32f else 0f
}
viewModel.widgetPreferencesUpdate.observe(viewLifecycleOwner) {
@ -153,7 +158,11 @@ class MainFragment : Fragment() {
WidgetHelper.runWithCustomTypeface(requireContext()) { typeface ->
uiJob?.cancel()
uiJob = lifecycleScope.launch(Dispatchers.IO) {
val generatedView = MainWidget.getWidgetView(requireContext(), binding.widget.width, typeface)
val generatedView = MainWidget.getWidgetView(
requireContext(),
binding.widget.width - binding.widget.paddingStart - binding.widget.paddingEnd,
typeface
)
if (generatedView != null) {
withContext(Dispatchers.Main) {
@ -214,7 +223,7 @@ class MainFragment : Fragment() {
class ChangeTabEvent(val page: Int)
@Subscribe(threadMode = ThreadMode.MAIN)
fun onUpdateUiEvent(ignore: UpdateUiMessageEvent?) {
fun onUpdateUiEvent(@Suppress("UNUSED_PARAMETER") ignore: UpdateUiMessageEvent?) {
delayJob?.cancel()
delayJob = lifecycleScope.launch(Dispatchers.IO) {
delay(300)
@ -225,7 +234,7 @@ class MainFragment : Fragment() {
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onChangeTabEvent(ignore: ChangeTabEvent) {
fun onChangeTabEvent(@Suppress("UNUSED_PARAMETER") ignore: ChangeTabEvent) {
val navHost = childFragmentManager.findFragmentById(R.id.settings_fragment) as? NavHostFragment?
navHost?.navController?.navigateUp()
}

View File

@ -236,6 +236,7 @@ class CalendarFragment : Fragment() {
binding.showDiffTimeToggle.setOnCheckedChangeListener { _, isChecked ->
Preferences.showDiffTime = isChecked
updateCalendar()
}
binding.actionShowNextEventOnMultipleLines.setOnClickListener {

View File

@ -146,7 +146,7 @@ class ClockFragment : Fragment() {
binding.actionClockTextSize.setOnClickListener {
BottomSheetPicker(
requireContext(),
items = (46 downTo 12).map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
items = (120 downTo 30).filter { it % 2 == 0 }.map { BottomSheetPicker.MenuItem("${it}sp", it.toFloat()) },
getSelected = { Preferences.clockTextSize },
header = getString(R.string.settings_clock_text_size_title),
onItemSelected = {value ->

View File

@ -317,6 +317,17 @@ class TypographyFragment : Fragment() {
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == android.app.Activity.RESULT_OK) {
when (requestCode) {
RequestCode.CUSTOM_FONT_CHOOSER_REQUEST_CODE.code -> {
com.tommasoberlose.anotherwidget.ui.widgets.MainWidget.updateWidget(requireContext())
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun maintainScrollPosition(callback: () -> Unit) {
binding.scrollView.isScrollable = false
callback.invoke()

View File

@ -32,6 +32,7 @@ import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.convertDpToPixel
import com.tommasoberlose.anotherwidget.utils.isDarkTheme
import com.tommasoberlose.anotherwidget.utils.toPixel
import java.text.DateFormat
import java.util.*
import java.util.concurrent.TimeUnit
@ -79,9 +80,10 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
try {
val generatedBinding = generateWidgetView(typeface) ?: return null
val width = w - (Preferences.widgetPadding.convertDpToPixel(context) + Preferences.widgetMargin.convertDpToPixel(context)).toInt() * 2
views.setImageViewBitmap(
R.id.bitmap_container,
BitmapHelper.getBitmapFromView(generatedBinding.root, width = w)
BitmapHelper.getBitmapFromView(generatedBinding.root, width)
)
views = updateGridView(generatedBinding, views, appWidgetId)
} catch (ex: Exception) {
@ -241,10 +243,6 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
views.setViewVisibility(R.id.sub_line_rect, View.VISIBLE)
views.setViewVisibility(R.id.weather_sub_line_rect, if (Preferences.showWeather && Preferences.weatherIcon != "") View.VISIBLE else View.GONE)
views.setViewVisibility(R.id.first_line_rect, View.GONE)
views.setViewVisibility(R.id.sub_line_top_margin_small_sans, View.GONE)
views.setViewVisibility(R.id.sub_line_top_margin_medium_sans, View.GONE)
views.setViewVisibility(R.id.sub_line_top_margin_large_sans, View.GONE)
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
var showSomething = false
var isWeatherShown = false
@ -297,6 +295,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
if (Preferences.customNotes.isNotEmpty()) {
showSomething = true
break@loop
}
}
@ -601,9 +600,12 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
bindingView.subLine.isVisible = true
bindingView.weatherSubLine.isVisible = Preferences.showWeather && Preferences.weatherIcon != ""
bindingView.subLineTopMarginSmall.visibility = View.GONE
bindingView.subLineTopMarginMedium.visibility = View.GONE
bindingView.subLineTopMarginLarge.visibility = View.GONE
bindingView.subLineTopMarginSmall.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.SMALL.rawValue) View.VISIBLE else View.GONE
bindingView.subLineTopMarginMedium.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.MEDIUM.rawValue) View.VISIBLE else View.GONE
bindingView.subLineTopMarginLarge.visibility =
if (Preferences.secondRowTopMargin == Constants.SecondRowTopMargin.LARGE.rawValue) View.VISIBLE else View.GONE
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
bindingView.subLineIcon.isVisible = true
var showSomething = false
@ -844,48 +846,54 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
bindingView.nextEvent to Preferences.textMainSize,
bindingView.nextEventDifferenceTime to Preferences.textMainSize,
bindingView.subLineText to Preferences.textSecondSize,
bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2),
bindingView.weatherSubLineDivider to (Preferences.textSecondSize * 0.9f),
bindingView.weatherSubLineTemperature to Preferences.textSecondSize,
).forEach {
it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second)
if (!it.first.includeFontPadding && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
it.first.isFallbackLineSpacing = false
}
// Icons scale
bindingView.subLineIcon.scaleX = Preferences.textSecondSize / 18f
bindingView.subLineIcon.scaleY = Preferences.textSecondSize / 18f
bindingView.weatherSubLineWeatherIcon.scaleX = Preferences.textSecondSize / 18f
bindingView.weatherSubLineWeatherIcon.scaleY = Preferences.textSecondSize / 18f
bindingView.weatherDateLineWeatherIcon.scaleX = ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 20f
bindingView.weatherDateLineWeatherIcon.scaleY = ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 20f
bindingView.actionNext.scaleX = Preferences.textMainSize / 28f
bindingView.actionNext.scaleY = Preferences.textMainSize / 28f
listOf(
bindingView.subLineIcon to Preferences.textSecondSize / 16f,
bindingView.subLineIconShadow to Preferences.textSecondSize / 16f,
bindingView.weatherSubLineWeatherIcon to Preferences.textSecondSize / 16f,
bindingView.weatherDateLineWeatherIcon to ((Preferences.textMainSize + Preferences.textSecondSize) / 2) / 24f,
bindingView.actionNext to Preferences.textMainSize / 24f,
bindingView.actionNextShadow to Preferences.textMainSize / 24f
).forEach {
if (it.first.tag == null)
it.first.tag = it.first.layoutParams.height
it.first.layoutParams = it.first.layoutParams.apply {
height = ((it.first.tag as Int) * it.second).roundToInt()
width = height
}
}
// Shadows
val shadowRadius =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> 0f
1 -> 5f
2 -> 5f
else -> 5f
}
1 -> 2f
2 -> 3f
else -> 2f
}.toPixel(context)
val shadowColor =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> Color.TRANSPARENT
1 -> R.color.black_50
1 -> Color.DKGRAY
2 -> Color.BLACK
else -> R.color.black_50
else -> Color.DKGRAY
}
val shadowDy =
val shadowOffset =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> 0f
1 -> 0f
2 -> 1f
2 -> 0.5f
else -> 0f
}
}.toPixel(context)
listOf<TextView>(
bindingView.date,
@ -896,7 +904,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
bindingView.weatherSubLineDivider,
bindingView.weatherSubLineTemperature,
).forEach {
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
it.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, shadowColor)
}
// Icons shadow
@ -910,7 +918,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
it.second.isVisible = it.first.isVisible
it.second.scaleX = it.first.scaleX
it.second.scaleY = it.first.scaleY
it.second.applyShadow(it.first)
it.second.applyShadow(it.first, 0.8f)
}
}
@ -968,10 +976,7 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
// Dividers
arrayOf(bindingView.weatherSubLineDivider).forEach {
it.visibility = if (Preferences.showDividers) View.VISIBLE else View.INVISIBLE
it.layoutParams = (it.layoutParams as ViewGroup.MarginLayoutParams).apply {
this.marginEnd = if (Preferences.showDividers) 8f.convertDpToPixel(context).toInt() else 0
}
it.visibility = if (Preferences.showDividers) View.VISIBLE else View.GONE
}
// Right Aligned
@ -981,8 +986,11 @@ class AlignedWidget(val context: Context, val rightAligned: Boolean = false) {
}
bindingView.mainContent.gravity = Gravity.END
bindingView.dateLayout.gravity = Gravity.END
bindingView.date.gravity = Gravity.END
bindingView.calendarLayout.gravity = Gravity.END or Gravity.CENTER_VERTICAL
bindingView.nextEvent.gravity = Gravity.END
bindingView.subLineContainer.gravity = Gravity.END or Gravity.CENTER_VERTICAL
bindingView.subLineText.gravity = Gravity.END
}
return bindingView

View File

@ -32,12 +32,12 @@ class ClockWidget(val context: Context) {
views.setTextViewTextSize(
R.id.time,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context)
Preferences.clockTextSize
)
views.setTextViewTextSize(
R.id.time_am_pm,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context) / 5 * 2
Preferences.clockTextSize / 5 * 2
)
val clockPIntent = IntentHelper.getPendingIntent(
context,
@ -80,19 +80,29 @@ class ClockWidget(val context: Context) {
views.setTextViewTextSize(
R.id.alt_timezone_time,
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize.toPixel(context) / 3
Preferences.clockTextSize / 3
)
views.setTextViewTextSize(
R.id.alt_timezone_time_am_pm,
TypedValue.COMPLEX_UNIT_SP,
(Preferences.clockTextSize.toPixel(context) / 3) / 5 * 2
(Preferences.clockTextSize / 3) / 5 * 2
)
views.setTextViewTextSize(
R.id.alt_timezone_label,
TypedValue.COMPLEX_UNIT_SP,
(Preferences.clockTextSize.toPixel(context) / 3) / 5 * 2
(Preferences.clockTextSize / 3) / 5 * 2
)
val padding = (TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
Preferences.clockTextSize,
context.resources.displayMetrics
) * 0.2).toInt()
if (Preferences.widgetAlign == Constants.WidgetAlign.RIGHT.rawValue)
views.setViewPadding(R.id.timezones_container, 0, padding, padding, 0)
else
views.setViewPadding(R.id.timezones_container, padding, padding, 0,0)
views.setOnClickPendingIntent(R.id.timezones_container, clockPIntent)
views.setViewVisibility(R.id.timezones_container, View.VISIBLE)
} else {

View File

@ -63,17 +63,13 @@ class MainWidget : AppWidgetProvider() {
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager,
appWidgetId: Int) {
val displayMetrics = Resources.getSystem().displayMetrics
val width = displayMetrics.widthPixels
val height = displayMetrics.heightPixels
val dimensions = WidgetHelper.WidgetSizeProvider(context, appWidgetManager).getWidgetsSize(appWidgetId)
WidgetHelper.runWithCustomTypeface(context) {
val views = when (Preferences.widgetAlign) {
Constants.WidgetAlign.LEFT.rawValue -> AlignedWidget(context).generateWidget(appWidgetId, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it)
Constants.WidgetAlign.RIGHT.rawValue -> AlignedWidget(context, rightAligned = true).generateWidget(appWidgetId, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it)
else -> StandardWidget(context).generateWidget(appWidgetId, min(dimensions.first - 8.toPixel(context), min(width, height) - 16.toPixel(context)), it)
Constants.WidgetAlign.LEFT.rawValue -> AlignedWidget(context).generateWidget(appWidgetId, dimensions.first, it)
Constants.WidgetAlign.RIGHT.rawValue -> AlignedWidget(context, rightAligned = true).generateWidget(appWidgetId, dimensions.first, it)
else -> StandardWidget(context).generateWidget(appWidgetId, dimensions.first, it)
}
try {
if (views != null) appWidgetManager.updateAppWidget(appWidgetId, views)

View File

@ -82,9 +82,10 @@ class StandardWidget(val context: Context) {
try {
val generatedBinding = generateWidgetView(typeface) ?: return null
val width = w - (Preferences.widgetPadding.convertDpToPixel(context) + Preferences.widgetMargin.convertDpToPixel(context)).toInt() * 2
views.setImageViewBitmap(
R.id.bitmap_container,
BitmapHelper.getBitmapFromView(generatedBinding.root, width = w)
BitmapHelper.getBitmapFromView(generatedBinding.root, width)
)
views = updateGridView(generatedBinding, views, appWidgetId)
} catch (ex: Exception) {
@ -325,6 +326,7 @@ class StandardWidget(val context: Context) {
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
if (Preferences.customNotes.isNotEmpty()) {
showSomething = true
break@loop
}
}
@ -874,56 +876,60 @@ class StandardWidget(val context: Context) {
// Text Size
listOf<Pair<TextView, Float>>(
bindingView.date to Preferences.textMainSize,
bindingView.weatherDateLineDivider to (Preferences.textMainSize - 2),
bindingView.weatherDateLineDivider to (Preferences.textMainSize * 0.9f),
bindingView.weatherDateLineTemperature to Preferences.textMainSize,
bindingView.nextEvent to Preferences.textMainSize,
bindingView.nextEventDifferenceTime to Preferences.textMainSize,
bindingView.subLineText to Preferences.textSecondSize,
bindingView.weatherSubLineDivider to (Preferences.textSecondSize - 2),
bindingView.weatherSubLineDivider to (Preferences.textSecondSize * 0.9f),
bindingView.weatherSubLineTemperature to Preferences.textSecondSize,
).forEach {
it.first.setTextSize(TypedValue.COMPLEX_UNIT_SP, it.second)
if (!it.first.includeFontPadding && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
it.first.isFallbackLineSpacing = false
}
// Icons scale
bindingView.subLineIcon.scaleX = Preferences.textSecondSize / 18f
bindingView.subLineIcon.scaleY = Preferences.textSecondSize / 18f
bindingView.weatherSubLineWeatherIcon.scaleX = Preferences.textSecondSize / 18f
bindingView.weatherSubLineWeatherIcon.scaleY = Preferences.textSecondSize / 18f
bindingView.weatherDateLineWeatherIcon.scaleX = Preferences.textMainSize / 18f
bindingView.weatherDateLineWeatherIcon.scaleY = Preferences.textMainSize / 18f
bindingView.actionNext.scaleX = Preferences.textMainSize / 28f
bindingView.actionNext.scaleY = Preferences.textMainSize / 28f
bindingView.actionPrevious.scaleX = Preferences.textMainSize / 28f
bindingView.actionPrevious.scaleY = Preferences.textMainSize / 28f
listOf(
bindingView.subLineIcon to Preferences.textSecondSize / 16f,
bindingView.subLineIconShadow to Preferences.textSecondSize / 16f,
bindingView.weatherSubLineWeatherIcon to Preferences.textSecondSize / 16f,
bindingView.weatherDateLineWeatherIcon to Preferences.textMainSize / 24f,
bindingView.actionNext to Preferences.textMainSize / 24f,
bindingView.actionNextShadow to Preferences.textMainSize / 24f,
bindingView.actionPrevious to Preferences.textMainSize / 24f,
bindingView.actionPreviousShadow to Preferences.textMainSize / 24f
).forEach {
if (it.first.tag == null)
it.first.tag = it.first.layoutParams.height
it.first.layoutParams = it.first.layoutParams.apply {
height = ((it.first.tag as Int) * it.second).roundToInt()
width = height
}
}
// Shadows
val shadowRadius =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> 0f
1 -> 5f
2 -> 5f
else -> 5f
}
1 -> 2f
2 -> 3f
else -> 2f
}.toPixel(context)
val shadowColor =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> Color.TRANSPARENT
1 -> R.color.black_50
1 -> Color.DKGRAY
2 -> Color.BLACK
else -> R.color.black_50
else -> Color.DKGRAY
}
val shadowDy =
val shadowOffset =
when (if (context.isDarkTheme()) Preferences.textShadowDark else Preferences.textShadow) {
0 -> 0f
1 -> 0f
2 -> 1f
2 -> 0.5f
else -> 0f
}
}.toPixel(context)
listOf<TextView>(
bindingView.date,
@ -935,7 +941,7 @@ class StandardWidget(val context: Context) {
bindingView.weatherSubLineDivider,
bindingView.weatherSubLineTemperature,
).forEach {
it.setShadowLayer(shadowRadius, 0f, shadowDy, shadowColor)
it.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, shadowColor)
}
// Icons shadow
@ -949,7 +955,7 @@ class StandardWidget(val context: Context) {
it.second.isVisible = it.first.isVisible
it.second.scaleX = it.first.scaleX
it.second.scaleY = it.first.scaleY
it.second.applyShadow(it.first)
it.second.applyShadow(it.first, 0.8f)
}
}
@ -1013,10 +1019,7 @@ class StandardWidget(val context: Context) {
// Dividers
arrayOf(bindingView.weatherDateLineDivider, bindingView.weatherSubLineDivider).forEach {
it.visibility = if (Preferences.showDividers) View.VISIBLE else View.INVISIBLE
it.layoutParams = (it.layoutParams as ViewGroup.MarginLayoutParams).apply {
this.marginEnd = if (Preferences.showDividers) 8f.convertDpToPixel(context).toInt() else 0
}
it.visibility = if (Preferences.showDividers) View.VISIBLE else View.GONE
}

View File

@ -94,8 +94,7 @@
android:layout_centerInParent="true"
android:layout_gravity="center"
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:padding="8dp"
android:id="@+id/widget"
android:alpha="0"
android:animateLayoutChanges="true"

View File

@ -511,7 +511,7 @@
android:layout_height="wrap_content"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingBottom="32dp"
android:paddingBottom="12dp"
android:duplicateParentState="true"
android:textSize="14sp"
android:textColor="@color/colorSecondaryText"

View File

@ -16,7 +16,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="32dp"
android:paddingBottom="48dp"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"

View File

@ -76,7 +76,6 @@
android:id="@+id/footer"
android:padding="8dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"

View File

@ -22,7 +22,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:paddingBottom="8dp"
android:orientation="vertical"
android:layoutDirection="locale"
android:id="@+id/date_layout">
@ -30,6 +29,7 @@
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start"
android:lines="1"
android:textColor="@color/colorPrimary"
android:maxLines="1"
@ -44,15 +44,14 @@
android:visibility="gone"
android:id="@+id/weather_date_line">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_width="28dp"
android:layout_height="28dp"
android:id="@+id/weather_date_line_weather_icon"
android:layout_marginStart="8dp"
android:layout_marginEnd="4dp"/>
android:layout_marginStart="4dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Widget.Date.Big"
style="@style/AnotherWidget.Widget.Title"
android:maxLines="1"
android:includeFontPadding="false"
android:id="@+id/weather_date_line_temperature"/>
@ -85,6 +84,7 @@
android:id="@+id/next_event_difference_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:includeFontPadding="false"
style="@style/AnotherWidget.Widget.Title" />
</LinearLayout>
@ -138,28 +138,31 @@
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:gravity="center_vertical"
android:id="@+id/sub_line"
android:visibility="gone"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:cropToPadding="false"
android:clipChildren="false"
android:layout_marginTop="2dp"
android:layout_marginEnd="4dp">
android:clipToPadding="false"
android:clipChildren="false">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:cropToPadding="false"
android:clipToPadding="false"
android:clipChildren="false"
android:layout_marginEnd="6dp"
android:id="@+id/sub_line_icon_shadow"
android:src="@drawable/round_today_24"/>
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:cropToPadding="false"
android:clipToPadding="false"
android:clipChildren="false"
android:layout_marginEnd="6dp"
android:id="@+id/sub_line_icon"
android:src="@drawable/round_today_24"/>
</RelativeLayout>
@ -167,7 +170,9 @@
android:id="@+id/sub_line_text"
android:layout_width="wrap_content"
android:gravity="start"
android:maxLines="2"
android:ellipsize="end"
android:lines="1"
android:maxLines="1"
android:includeFontPadding="false"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Widget.Subtitle" />
@ -176,14 +181,15 @@
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:gravity="center"
android:visibility="gone"
android:layout_marginStart="4dp"
android:layout_marginStart="2dp"
android:id="@+id/weather_sub_line">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="4dp"
android:id="@+id/weather_sub_line_divider"
android:text="@string/divider"
@ -193,12 +199,12 @@
android:layout_width="20dp"
android:layout_height="20dp"
android:id="@+id/weather_sub_line_weather_icon"
android:layout_marginStart="4dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="4dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Widget.Date.Big"
style="@style/AnotherWidget.Widget.Subtitle"
android:maxLines="1"
android:includeFontPadding="false"
android:id="@+id/weather_sub_line_temperature"/>

View File

@ -15,7 +15,7 @@
android:id="@+id/main_layout"
android:animateLayoutChanges="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="10000dp"
android:layout_height="wrap_content"
android:id="@+id/time_container"
android:layoutDirection="locale"
@ -48,9 +48,6 @@
android:layout_height="wrap_content"
android:id="@+id/timezones_container"
android:visibility="gone"
android:layout_marginStart="16dp"
android:layout_marginEnd="0dp"
android:layout_marginTop="18dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
@ -117,16 +114,16 @@
android:orientation="horizontal"
android:id="@+id/clock_bottom_margin_large" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_width="10000dp"
android:layout_height="wrap_content"
android:id="@+id/content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitStart"
android:scaleType="matrix"
android:id="@+id/bitmap_container"/>
</RelativeLayout>
<LinearLayout
@ -141,7 +138,6 @@
android:background="@color/errorColorText"
android:layoutDirection="locale"
android:visibility="gone"
android:layout_marginBottom="4dp"
android:id="@+id/first_line_rect">
<ImageView
android:layout_width="wrap_content"
@ -163,9 +159,8 @@
android:id="@+id/calendar_layout_rect"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:background="@color/colorAccent"
android:id="@+id/next_event_rect" />
<ImageView
@ -204,24 +199,26 @@
android:layout_height="wrap_content"
android:background="@color/colorNightDark"
android:orientation="horizontal"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:layoutDirection="locale"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:background="@color/colorAccent"
android:id="@+id/sub_line_rect" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<ImageView
android:layout_width="wrap_content"

View File

@ -15,10 +15,10 @@
android:id="@+id/main_layout"
android:animateLayoutChanges="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="10000dp"
android:layout_height="wrap_content"
android:id="@+id/time_container"
android:layout_gravity="end"
android:gravity="end"
android:layoutDirection="locale"
android:orientation="horizontal">
<LinearLayout
@ -26,9 +26,7 @@
android:layout_height="wrap_content"
android:id="@+id/timezones_container"
android:visibility="gone"
android:layout_marginStart="0dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="18dp"
android:gravity="end"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
@ -61,7 +59,7 @@
<TextView
android:id="@+id/alt_timezone_label"
android:layout_width="wrap_content"
android:gravity="start"
android:gravity="end"
android:maxLines="1"
android:textStyle="bold"
android:includeFontPadding="false"
@ -118,14 +116,14 @@
android:orientation="horizontal"
android:id="@+id/clock_bottom_margin_large" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_width="10000dp"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:id="@+id/content">
<ImageView
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitEnd"
android:scaleType="matrix"
android:layout_alignParentEnd="true"
android:id="@+id/bitmap_container"/>
<LinearLayout
@ -143,7 +141,6 @@
android:layoutDirection="locale"
android:visibility="gone"
android:gravity="end"
android:layout_marginBottom="4dp"
android:id="@+id/first_line_rect">
<ImageView
android:layout_width="wrap_content"
@ -165,9 +162,8 @@
android:id="@+id/calendar_layout_rect"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:background="@color/colorAccent"
android:id="@+id/next_event_rect" />
<ImageView
@ -206,24 +202,26 @@
android:layout_height="wrap_content"
android:background="@color/colorNightDark"
android:orientation="horizontal"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:layoutDirection="locale"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:background="@color/colorAccent"
android:id="@+id/sub_line_rect" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<ImageView
android:layout_width="wrap_content"

View File

@ -45,26 +45,25 @@
android:layout_height="wrap_content"
android:gravity="center"
android:visibility="gone"
android:layout_marginStart="4dp"
android:layout_marginStart="2dp"
android:id="@+id/weather_date_line">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginEnd="4dp"
android:id="@+id/weather_date_line_divider"
android:text="@string/divider"
android:includeFontPadding="false"
style="@style/AnotherWidget.Widget.Subtitle"/>
style="@style/AnotherWidget.Widget.Title"/>
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_width="28dp"
android:layout_height="28dp"
android:id="@+id/weather_date_line_weather_icon"
android:layout_marginStart="4dp"
android:layout_marginEnd="8dp"/>
android:layout_marginStart="2dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Widget.Date.Big"
style="@style/AnotherWidget.Widget.Title"
android:maxLines="1"
android:includeFontPadding="false"
android:id="@+id/weather_date_line_temperature"/>
@ -100,7 +99,6 @@
android:layout_weight="1"
android:maxLines="1"
android:lines="1"
android:gravity="end"
android:ellipsize="end"
android:includeFontPadding="false"
android:layout_height="wrap_content"
@ -113,7 +111,7 @@
android:id="@+id/next_event_difference_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:maxLines="1"
android:includeFontPadding="false"
style="@style/AnotherWidget.Widget.Title" />
</LinearLayout>
@ -159,12 +157,16 @@
android:layout_gravity="center"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:layoutDirection="locale"
android:gravity="center">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:gravity="center_vertical"
android:id="@+id/sub_line"
android:visibility="gone"
@ -172,21 +174,22 @@
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:cropToPadding="false"
android:clipChildren="false"
android:layout_marginEnd="4dp">
android:clipToPadding="false"
android:clipChildren="false">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:cropToPadding="false"
android:clipToPadding="false"
android:clipChildren="false"
android:layout_marginEnd="6dp"
android:id="@+id/sub_line_icon_shadow"
android:src="@drawable/round_today_24"/>
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:cropToPadding="false"
android:clipToPadding="false"
android:clipChildren="false"
android:layout_marginEnd="6dp"
android:id="@+id/sub_line_icon"
android:src="@drawable/round_today_24"/>
</RelativeLayout>
@ -204,14 +207,16 @@
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false"
android:gravity="center"
android:visibility="gone"
android:layout_marginStart="4dp"
android:layout_marginStart="2dp"
android:id="@+id/weather_sub_line">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="4dp"
android:id="@+id/weather_sub_line_divider"
android:text="@string/divider"
android:includeFontPadding="false"
@ -220,12 +225,12 @@
android:layout_width="20dp"
android:layout_height="20dp"
android:id="@+id/weather_sub_line_weather_icon"
android:layout_marginStart="4dp"
android:layout_marginEnd="8dp"/>
android:layout_marginStart="6dp"
android:layout_marginEnd="4dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Widget.Date.Big"
style="@style/AnotherWidget.Widget.Subtitle"
android:maxLines="1"
android:includeFontPadding="false"
android:id="@+id/weather_sub_line_temperature"/>

View File

@ -15,7 +15,7 @@
android:id="@+id/main_layout"
android:animateLayoutChanges="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="10000dp"
android:layout_height="wrap_content"
android:id="@+id/time_container"
android:gravity="center_horizontal"
@ -49,9 +49,6 @@
android:layout_height="wrap_content"
android:id="@+id/timezones_container"
android:visibility="gone"
android:layout_marginStart="16dp"
android:layout_marginEnd="0dp"
android:layout_marginTop="20dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
@ -118,23 +115,22 @@
android:orientation="horizontal"
android:id="@+id/clock_bottom_margin_large" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_width="10000dp"
android:layout_height="wrap_content"
android:id="@+id/content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:paddingTop="4dp">
android:layout_centerInParent="true">
<ImageView
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:scaleType="matrix"
android:layout_centerInParent="true"
android:id="@+id/bitmap_container"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:alpha="0"
@ -148,11 +144,11 @@
android:background="@color/colorNightDark"
android:orientation="horizontal"
android:layoutDirection="locale"
android:layout_marginBottom="4dp"
android:id="@+id/first_line_rect">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:id="@+id/date_rect"/>
<ImageView
android:layout_width="wrap_content"
@ -175,9 +171,9 @@
android:layout_gravity="center_vertical"
android:id="@+id/action_previous_rect" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:background="@color/colorAccent"
android:id="@+id/next_event_rect" />
<ImageView
android:layout_width="wrap_content"
@ -213,11 +209,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:layoutDirection="locale"
android:gravity="center">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
@ -225,12 +222,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorNightDark"
android:visibility="gone"
android:id="@+id/sub_line_rect" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<ImageView
android:layout_width="wrap_content"

View File

@ -66,12 +66,12 @@
<!-- Calendar -->
<string name="settings_calendar_title">日历</string>
<string name="title_permission_calendar">显示你的活动</string>
<string name="description_permission_calendar">授予应用查看日历的权限以在微件查看你的活动。</string>
<string name="description_permission_calendar">授予访问日历的权限\n以在您的微件查看活动。</string>
<string name="settings_filter_calendar_title">过滤活动</string>
<string name="settings_filter_calendar_subtitle">改变日历可见性</string>
<string name="settings_all_day_title">全天活动</string>
<string name="main_calendar">日历账户</string>
<string name="calendar_settings_list_error">加载日历列表出现错误</string>
<string name="main_calendar">日历</string>
<string name="calendar_settings_list_error">加载日历列表出</string>
<string name="all_day">全天活动</string>
<string name="show_events_visible">活动可见</string>
<string name="show_events_not_visible">活动不可见</string>
@ -100,7 +100,7 @@
<string name="settings_show_multiple_events_title">多活动切换器</string>
<string name="soon">即将</string>
<string name="now">即刻</string>
<string name="settings_widget_update_frequency_title">更新剩余时间频率</string>
<string name="settings_widget_update_frequency_title">剩余时间更新频率</string>
<string name="settings_widget_update_frequency_subtitle">更新频率越高耗电量越大。</string>
<string name="settings_widget_update_frequency_low"></string>
<string name="settings_widget_update_frequency_default">默认</string>
@ -123,8 +123,8 @@
<!-- Weather -->
<string name="settings_weather_title">天气</string>
<string name="title_permission_location">显示天气信息</string>
<string name="description_permission_location">授予位权限\n以在您的微件上查看天气。</string>
<string name="title_permission_location">显示天气</string>
<string name="description_permission_location">授予位权限\n以在您的微件上查看天气。</string>
<string name="settings_unit_title">单位</string>
<string name="fahrenheit" translatable="false">°F - 华氏度</string>
<string name="celsius" translatable="false">°C - 摄氏度</string>
@ -141,15 +141,15 @@
<string name="show_weather_not_visible">天气信息不可见</string>
<string name="settings_weather_app_title">天气</string>
<string name="settings_weather_provider_api_key_title">天气API密钥</string>
<string name="settings_weather_provider_api_key_subtitle_all_set">已正确配置天气信息来源。</string>
<string name="settings_weather_provider_api_key_subtitle_not_set">必须配置天气信息来源。</string>
<string name="settings_weather_provider_api_key_subtitle_all_set">已正确配置天气数据源。</string>
<string name="settings_weather_provider_api_key_subtitle_not_set">必须配置天气数据源。</string>
<string name="api_key_hint">OpenWeatherMap API密钥</string>
<string name="default_weather_app">Google Weather</string>
<string name="weather_warning">Google Awareness API已被弃用。要在微件上显示天气您需要从第三方源获取API密钥。</string>
<string name="settings_weather_icon_pack_title">天气图标</string>
<string name="default_weather_app">Google天气</string>
<string name="weather_warning">Google Awareness API已被弃用。要在微件上显示天气您需要从第三方数据源获取API密钥。</string>
<string name="settings_weather_icon_pack_title">图标</string>
<string name="settings_weather_icon_pack_default">图标包%d</string>
<string name="background_location_warning">选择地理定位后,即便应用未启动或在后台,我们也会收集您的定位数据来更新天气信息。\n这些数据不会用在其他地方。</string>
<string name="settings_weather_provider_api">天气信息来</string>
<string name="settings_weather_provider_api">天气数据</string>
<string name="settings_weather_provider_open_weather" translatable="false">OpenWeatherMap.org</string>
<string name="settings_weather_provider_weatherbit" translatable="false">Weatherbit.io</string>
@ -159,35 +159,35 @@
<string name="settings_weather_provider_weather_gov" translatable="false">Weather.gov (USA)\nby National Weather Services</string>
<string name="settings_weather_provider_yr" translatable="false">YR.no/Met.no\nby Meteorologisk Institutt</string>
<string name="weather_provider_info_open_weather_title">该天气信息来源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_weatherbit_title">该天气信息来源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_weatherapi_title">该天气信息来源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_here_title">该天气信息来源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_accuweather_title">该天气信息来源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_weather_gov_title">该天气信息来源仅美国境内有效。</string>
<string name="weather_provider_info_yr_title">该天气信息来源仅支持摄氏度单位。</string>
<string name="weather_provider_info_open_weather_title">该天气数据源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_weatherbit_title">该天气数据源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_weatherapi_title">该天气数据源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_here_title">该天气数据源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_accuweather_title">该天气数据源需要API密钥才能正常工作。</string>
<string name="weather_provider_info_weather_gov_title">该天气数据源仅美国境内有效。</string>
<string name="weather_provider_info_yr_title">该天气数据源仅支持摄氏度单位。</string>
<string name="weather_provider_info_open_weather_subtitle">前往天气信息来源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_weatherbit_subtitle">前往天气信息来源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_weatherapi_subtitle">前往天气信息来源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_here_subtitle">前往天气信息来源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_accuweather_subtitle">前往天气信息来源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_open_weather_subtitle">前往天气数据源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_weatherbit_subtitle">前往天气数据源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_weatherapi_subtitle">前往天气数据源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_here_subtitle">前往天气数据源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_accuweather_subtitle">前往天气数据源网站、创建个人账户并将默认密钥复制粘贴到此处。</string>
<string name="weather_provider_info_weather_gov_subtitle">\n</string>
<string name="weather_provider_info_yr_subtitle">\n</string>
<string name="weather_provider_error_missing_key">您选择的天气信息来源需要API密钥。</string>
<string name="weather_provider_error_missing_key">您选择的天气数据源需要API密钥。</string>
<string name="weather_provider_error_wrong_location">不支持当前位置。</string>
<string name="weather_provider_error_missing_location">请选择一个有效的地址</string>
<string name="weather_provider_error_missing_location">请选择一个有效的位置</string>
<string name="weather_provider_error_expired_key">您的API密钥似乎已经过期了。</string>
<string name="weather_provider_error_invalid_key">API密钥无效或尚未激活。</string>
<string name="weather_provider_error_misconfigured">天气信息来源配置错误。</string>
<string name="weather_provider_error_misconfigured">天气数据源配置错误。</string>
<string name="weather_provider_error_connection">网络连接错误。</string>
<string name="weather_provider_error_generic">出错了,请检查天气信息来源设置。</string>
<string name="weather_provider_error_generic">出错了,请检查天气数据源设置。</string>
<string name="api_key_required_message">需要账户</string>
<string name="us_only_message">仅限美国</string>
<string name="celsius_only_message">仅公制单位</string>
<string name="weather_select_a_provider">选择信息来</string>
<string name="weather_provider_activity_subtitle">从列表中选择天气信息来源。\n部分源需要注册免费个人账户,\n但它们通常也更精准。</string>
<string name="weather_select_a_provider">选择数据</string>
<string name="weather_provider_activity_subtitle">从列表中选择天气数据源。\n部分数据源需要注册免费个人账户,\n但它们通常也更精准。</string>
<string name="location_access_notification_channel_id" translatable="false">location-access</string>
<string name="location_access_notification_channel_name">天气更新服务</string>
@ -241,8 +241,8 @@
<string name="title_show_glance">显示速览信息</string>
<string name="description_show_glance_visible">服务已启用</string>
<string name="description_show_glance_not_visible">服务已禁用</string>
<string name="settings_sort_glance_providers_title">源优先级</string>
<string name="settings_sort_glance_providers_subtitle">您可以通过拖放图标来调整下方列表的项目顺序,以此更改数据源优先级。</string>
<string name="settings_sort_glance_providers_title">数据源优先级</string>
<string name="settings_sort_glance_providers_subtitle">您可以通过拖放图标来调整下方列表的项目顺序,以此更改数据源优先级。</string>
<string name="settings_custom_notes_title">自定义提示</string>
<string name="settings_daily_steps_title">运动健康</string>
<string name="daily_steps_counter">目前走了%d步</string>
@ -250,7 +250,7 @@
<string name="battery_low_warning">电量低</string>
<string name="charging">正在充电</string>
<string name="charged">完全充满</string>
<string name="providers"></string>
<string name="providers">数据</string>
<string name="glance_info">仅在当前没有活动且满足特定条件时才会显示速览。</string>
<string name="settings_music_players_filter_title">音乐播放器</string>
<string name="settings_music_players_filter_subtitle">选择您常用的音乐播放器</string>
@ -304,7 +304,7 @@
</string-array>
<string name="settings_show_events_as_glance_provider_title">活动</string>
<string name="settings_show_events_as_glance_provider_subtitle">查看您的日历活动的速览,并始终显示当前日期。</string>
<string name="settings_show_events_as_glance_provider_error">在日历标签中启用活动显示,并授予所需的权限。</string>
<string name="settings_show_events_as_glance_provider_error">启用日历显示,并授予所需的权限。</string>
<string name="events_glance_provider_format">%1$s %2$s</string>
<string name="settings_show_weather_as_glance_provider_title">天气</string>
<string name="settings_show_weather_as_glance_provider_subtitle">查看有关天气的更多信息,并始终显示当前日期。</string>
@ -318,9 +318,9 @@
<string name="action_about">关于</string>
<string name="action_refresh_widget">刷新微件</string>
<string name="toolbar_transition_name" translatable="false">toolbar</string>
<string name="error_opening_uri">打开URL时遭遇出错:链接已复制到剪贴板。</string>
<string name="error_opening_uri">打开URL出错链接已复制到剪贴板。</string>
<string name="loading_text">正在加载数据……</string>
<string name="error_opening_app">打开应用出错。</string>
<string name="error_opening_app">打开应用出错。</string>
<string name="default_name">默认应用</string>
<string name="action_save">保存</string>
<string name="settings_visible">可见</string>
@ -344,17 +344,17 @@
<string name="settings_feedback_subtitle">欢迎为该项目贡献您的力量!</string>
<string name="settings_feedback_title">反馈和功能请求</string>
<string name="xiaomi_manufacturer" translatable="false">xiaomi</string>
<string name="xiaomi_warning_title">检测到小米设备</string>
<string name="xiaomi_warning_message">请在应用设置的其他权限」中授予允许程序在后台运行时显示弹出窗口的权限,否则您将无法通过点击微件打开任何应用。</string>
<string name="xiaomi_warning_title">小米设备</string>
<string name="xiaomi_warning_message">请在应用设置的其他权限部分授予后台弹出界面的权限,否则您将无法通过点击微件打开任何应用。</string>
<string name="action_ignore">忽略</string>
<string name="action_grant_permission">授予权限</string>
<string name="settings_title">设置</string>
<string name="style_header">风格</string>
<string name="actions_header">动作</string>
<string name="provider_header"></string>
<string name="provider_header">数据</string>
<string name="appearance_header">外观</string>
<string name="preferences_header">偏好</string>
<string name="settings_privacy_policy_title"><![CDATA[法务与隐私]]></string>
<string name="settings_privacy_policy_title">法务与隐私</string>
<string name="settings_privacy_policy_subtitle">查看应用的隐私策略</string>
<string name="project_header">开源项目</string>
<string name="information_header">信息</string>
@ -369,8 +369,8 @@
<string name="donation_breakfast">一顿英式早餐</string>
<string name="donation_lunch">一顿快餐</string>
<string name="action_show_widget_preview">显示微件预览</string>
<string name="support_dev_subtitle">这是一个独立开发者的项目,谢谢您的支持!</string>
<string name="settings_title_integrations">整合</string>
<string name="support_dev_subtitle">这是一个独立开发者的项目,\n谢谢您的支持!</string>
<string name="settings_title_integrations">集成</string>
<string name="label_count_installed_integrations">已安装%d个集成插件</string>
<string name="nothing"></string>
<string name="action_dismiss">拒绝</string>
@ -380,13 +380,13 @@
<string name="song_info_format_activity_subtitle">更改曲目的可见信息</string>
<!-- More -->
<string name="look_and_feel_header"><![CDATA[外观与视觉]]></string>
<string name="look_and_feel_header">界面外观</string>
<string name="typography_settings_title">文本</string>
<string name="typography_settings_subtitle">设置文本字体、大小和颜色</string>
<string name="layout_settings_title">布局</string>
<string name="gestures_settings_subtitle">动作、行为与快捷方式</string>
<string name="gestures_settings_title">交互</string>
<string name="gestures_amp_input_header"><![CDATA[操作与交互]]></string>
<string name="gestures_settings_title">手势</string>
<string name="gestures_amp_input_header">手势与输入</string>
<string name="clock_settings_subtitle">设置大小、颜色与时区</string>
<string name="layout_settings_subtitle">微件间距及其它微调</string>
<string name="smart_content_header">智能内容</string>

View File

@ -7,7 +7,6 @@ buildscript {
jcenter()
maven { url 'https://jitpack.io' }
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.0'
@ -17,8 +16,6 @@ buildscript {
// Add the Crashlytics Gradle plugin.
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2'
classpath 'io.realm:realm-gradle-plugin:10.4.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@ -30,7 +27,6 @@ allprojects {
jcenter()
maven { url 'https://jitpack.io' }
mavenCentral()
}
}