Release v2.0.1

This commit is contained in:
Tommaso Berlose 2020-05-03 17:54:35 +02:00
parent 3aecf9851a
commit 9a978ac8d3
135 changed files with 2368 additions and 1221 deletions

1
.idea/.name generated Normal file
View File

@ -0,0 +1 @@
Another Widget

129
.idea/assetWizardSettings.xml generated Normal file
View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WizardSettings">
<option name="children">
<map>
<entry key="imageWizard">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="imageAssetPanel">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="actionbar">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="clipArt">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="color" value="000000" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
<option name="values">
<map>
<entry key="theme" value="HOLO_DARK" />
<entry key="themeColor" value="ffffff" />
</map>
</option>
</PersistentState>
</value>
</entry>
<entry key="launcher">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="foregroundImage">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="color" value="000000" />
<entry key="scalingPercent" value="70" />
<entry key="trimmed" value="true" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
<option name="values">
<map>
<entry key="backgroundAssetType" value="COLOR" />
<entry key="backgroundColor" value="ffffff" />
<entry key="foregroundImage" value="$USER_HOME$/Desktop/Artboard Copy 3.png" />
<entry key="legacyIconShape" value="CIRCLE" />
</map>
</option>
</PersistentState>
</value>
</entry>
<entry key="launcherLegacy">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="clipArt">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="color" value="000000" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
<entry key="notification">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="clipArt">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="color" value="000000" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</component>
</project>

Binary file not shown.

1
.idea/gradle.xml generated
View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>

View File

@ -18,8 +18,8 @@ android {
applicationId "com.tommasoberlose.anotherwidget" applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 29 targetSdkVersion 29
versionCode 40 versionCode 48
versionName "2.0" versionName "2.0.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -36,6 +36,10 @@ android {
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
kotlinOptions {
jvmTarget = "1.8"
}
kotlinOptions { kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString() jvmTarget = JavaVersion.VERSION_1_8.toString()
} }
@ -65,6 +69,7 @@ dependencies {
implementation 'com.google.android.material:material:1.2.0-alpha06' implementation 'com.google.android.material:material:1.2.0-alpha06'
implementation 'androidx.browser:browser:1.2.0' implementation 'androidx.browser:browser:1.2.0'
implementation 'net.idik:slimadapter:2.1.2' implementation 'net.idik:slimadapter:2.1.2'
implementation 'com.google.android:flexbox:2.0.1'
// Lifecycle // Lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
@ -81,9 +86,9 @@ dependencies {
// Other // Other
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'joda-time:joda-time:2.9.9' implementation 'joda-time:joda-time:2.9.9'
implementation "dev.sasikanth:colorsheet:1.0.1"
implementation 'com.andkulikov:transitionseverywhere:1.7.6'
implementation 'me.everything:providers-android:1.0.1' implementation 'me.everything:providers-android:1.0.1'
implementation 'com.github.bumptech.glide:glide:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
//Weather //Weather
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2' implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
@ -96,6 +101,7 @@ dependencies {
// KTX // KTX
implementation "androidx.core:core-ktx:1.2.0" implementation "androidx.core:core-ktx:1.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.palette:palette-ktx:1.0.0"
// Recommended: Add the Firebase SDK for Google Analytics. // Recommended: Add the Firebase SDK for Google Analytics.
implementation 'com.google.firebase:firebase-analytics:17.4.0' implementation 'com.google.firebase:firebase-analytics:17.4.0'

BIN
app/release/app-release.aab Normal file

Binary file not shown.

View File

@ -13,7 +13,7 @@
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:name=".components.AWApplication" android:name=".AWApplication"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
@ -28,9 +28,10 @@
<activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" /> <activity android:name=".ui.activities.CustomLocationActivity" android:launchMode="singleInstance" />
<activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" /> <activity android:name=".ui.activities.WeatherProviderActivity" android:launchMode="singleInstance" />
<activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" /> <activity android:name=".ui.activities.SupportDevActivity" android:launchMode="singleInstance" />
<activity android:name=".ui.activities.CustomDateActivity" android:launchMode="singleInstance" />
<receiver android:name=".ui.widgets.TheWidget"> <receiver android:name=".ui.widgets.MainWidget">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
@ -65,6 +66,7 @@
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" /> <action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
<action android:name="android.intent.action.DATE_CHANGED" /> <action android:name="android.intent.action.DATE_CHANGED" />
<action android:name="android.intent.action.TIME_SET" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver <receiver
@ -76,6 +78,7 @@
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" /> <action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.TIME_SET" />
</intent-filter> </intent-filter>
</receiver> </receiver>
@ -88,6 +91,8 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<service android:name=".services.EventListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
</application> </application>
</manifest> </manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,4 +1,4 @@
package com.tommasoberlose.anotherwidget.components package com.tommasoberlose.anotherwidget
import android.app.Application import android.app.Application
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
@ -23,5 +23,22 @@ class AWApplication : Application() {
.deleteRealmIfMigrationNeeded() .deleteRealmIfMigrationNeeded()
.build() .build()
Realm.setDefaultConfiguration(config) Realm.setDefaultConfiguration(config)
calibrateVersions()
}
private fun calibrateVersions() {
// 2.0 Tolerance
if (Preferences.clockTextSize > 50f) {
Preferences.clockTextSize = 46f
}
if (Preferences.textMainSize > 36f) {
Preferences.textMainSize = 32f
}
if (Preferences.textSecondSize > 28f) {
Preferences.textSecondSize = 24f
}
} }
} }

View File

@ -0,0 +1,55 @@
package com.tommasoberlose.anotherwidget.components
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.view.View
import android.widget.GridLayout
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import kotlinx.android.synthetic.main.bottom_sheet_menu_hor.view.*
import kotlinx.android.synthetic.main.color_picker_menu_item.view.*
class BottomSheetColorPicker(
context: Context,
private val colors: IntArray = intArrayOf(),
private val selected: Int? = null,
private val header: String? = null,
private val onColorSelected: ((selectedValue: Int) -> Unit)? = null
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
override fun show() {
val view = View.inflate(context, R.layout.bottom_sheet_menu_hor, null)
// Header
view.header.isVisible = header != null
view.header_text.text = header ?: ""
// Menu
for (@ColorInt color: Int in colors) {
val itemView = View.inflate(context, R.layout.color_picker_menu_item, null)
itemView.color.setCardBackgroundColor(ColorStateList.valueOf(color))
itemView.check.setColorFilter(ContextCompat.getColor(context,
if (color.isColorDark()) android.R.color.white else android.R.color.black
), android.graphics.PorterDuff.Mode.MULTIPLY)
itemView.check.isVisible = selected == color
itemView.color.setOnClickListener {
onColorSelected?.invoke(color)
this.dismiss()
}
view.menu.addView(itemView, GridLayout.LayoutParams(
GridLayout.spec(GridLayout.UNDEFINED, 1f),
GridLayout.spec(GridLayout.UNDEFINED, 1f)
)
)
}
setContentView(view)
super.show()
}
}

View File

@ -4,11 +4,14 @@ import android.app.Dialog
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.annotation.MenuRes import androidx.annotation.MenuRes
import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.card.MaterialCardView
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import kotlinx.android.synthetic.main.bottom_sheet_menu.view.* import kotlinx.android.synthetic.main.bottom_sheet_menu.view.*
import kotlinx.android.synthetic.main.bottom_sheet_menu_item.view.* import kotlinx.android.synthetic.main.bottom_sheet_menu_item.view.*
@ -18,18 +21,24 @@ import kotlinx.android.synthetic.main.bottom_sheet_menu_item.view.*
* theme which sets a rounded background to the dialog * theme which sets a rounded background to the dialog
* and doesn't dim the navigation bar * and doesn't dim the navigation bar
*/ */
open class BottomSheetMenu<T>(context: Context, private val header: String? = null) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) { open class BottomSheetMenu<T>(context: Context, private val header: String? = null, private val isMultiSelection: Boolean = false) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
private val items: ArrayList<MenuItem<T>> = ArrayList() private val items: ArrayList<MenuItem<T>> = ArrayList()
private var selectedRes: T? = null private var selectedRes: ArrayList<T> = ArrayList()
private var callback: ((selectedValue: T) -> Unit)? = null private var callback: ((selectedValue: T) -> Unit)? = null
private var multipleSelectionCallback: ((selectedValues: ArrayList<T>) -> Unit)? = null
fun selectResource(res: T): BottomSheetMenu<T> { fun setSelectedValue(res: T): BottomSheetMenu<T> {
selectedRes = res selectedRes = ArrayList(listOf(res))
return this return this
} }
fun addItem(title: String, value: T): BottomSheetMenu<T> { fun setSelectedValues(res: List<T>): BottomSheetMenu<T> {
selectedRes = ArrayList(res)
return this
}
fun addItem(title: String, value: T? = null): BottomSheetMenu<T> {
items.add(MenuItem(title, value)) items.add(MenuItem(title, value))
return this return this
} }
@ -39,6 +48,11 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
return this return this
} }
fun addOnMultipleSelectItemListener(multipleSelectionCallback: (selectedValues: ArrayList<T>) -> Unit): BottomSheetMenu<T> {
this.multipleSelectionCallback = multipleSelectionCallback
return this
}
override fun show() { override fun show() {
val view = View.inflate(context, R.layout.bottom_sheet_menu, null) val view = View.inflate(context, R.layout.bottom_sheet_menu, null)
@ -48,19 +62,52 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
// Menu // Menu
for (item in items) { for (item in items) {
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_item, null) if (item.value != null) {
itemView.label.text = item.title val itemView = View.inflate(context, R.layout.bottom_sheet_menu_item, null)
itemView.isSelected = item.value == selectedRes itemView.label.text = item.title
itemView.setOnClickListener { if (isMultiSelection) {
callback?.invoke(item.value) itemView.icon_check.isVisible = selectedRes.contains(item.value)
this.dismiss() itemView.label.setTextColor(
if (selectedRes.contains(item.value)) ContextCompat.getColor(
context,
R.color.colorPrimaryText
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
)
} else {
itemView.isSelected = selectedRes.contains(item.value)
}
itemView.setOnClickListener {
if (!isMultiSelection) {
callback?.invoke(item.value)
this.dismiss()
} else {
if (selectedRes.contains(item.value)) {
selectedRes.remove(item.value)
} else {
selectedRes.add(item.value)
}
multipleSelectionCallback?.invoke(selectedRes)
itemView.icon_check.isVisible = selectedRes.contains(item.value)
itemView.label.setTextColor(
if (selectedRes.contains(item.value)) ContextCompat.getColor(
context,
R.color.colorPrimaryText
) else ContextCompat.getColor(context, R.color.colorSecondaryText)
)
}
}
view.menu.addView(itemView)
} else {
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_divider, null)
itemView.label.text = item.title
view.menu.addView(itemView)
} }
view.menu.addView(itemView)
} }
setContentView(view) setContentView(view)
super.show() super.show()
} }
class MenuItem<T>(val title: String, val value: T) class MenuItem<T>(val title: String, val value: T? = null)
} }

View File

@ -1,16 +0,0 @@
package com.tommasoberlose.anotherwidget.components
/**
* Created by tommaso on 08/10/17.
*/
class CalendarSelector(id: Int, name: String?, account_name: String?) {
var id: Int = 0
var name: String = ""
var account_name: String = ""
init {
this.id = id
this.name = name?: ""
this.account_name = account_name?: ""
}
}

View File

@ -1,9 +0,0 @@
package com.tommasoberlose.anotherwidget.components.events
import android.content.pm.ApplicationInfo
/**
* Created by tommaso on 15/10/17.
*/
class AppInfoSavedEvent(val app: ApplicationInfo) {
}

View File

@ -1,16 +0,0 @@
package com.tommasoberlose.anotherwidget.components.events
import android.content.pm.ApplicationInfo
/**
* Created by tommaso on 15/10/17.
*/
class ApplicationListEvent(apps: List<ApplicationInfo>, filtered: Boolean) {
var apps: List<ApplicationInfo> = ArrayList()
var filtered: Boolean = false
init {
this.apps = apps
this.filtered = filtered
}
}

View File

@ -1,14 +0,0 @@
package com.tommasoberlose.anotherwidget.components.events
import android.location.Address
/**
* Created by tommaso on 14/10/17.
*/
class CustomLocationEvent(addresses: ArrayList<Address>) {
var addresses: ArrayList<Address> = ArrayList()
init {
this.addresses = addresses
}
}

View File

@ -0,0 +1,84 @@
package com.tommasoberlose.anotherwidget.db
import android.content.Context
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.global.Preferences
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
class EventRepository(val context: Context) {
private val realm by lazy { Realm.getDefaultInstance() }
fun saveEvents(eventList: ArrayList<Event>) {
realm.executeTransactionAsync { realm ->
realm.where(Event::class.java).findAll().deleteAllFromRealm()
realm.copyToRealm(eventList)
}
}
fun resetNextEventData() {
realm.executeTransactionAsync {
it.where(Event::class.java).findAll().deleteAllFromRealm()
}
Preferences.bulk {
remove(Preferences::nextEventId)
remove(Preferences::nextEventName)
remove(Preferences::nextEventStartDate)
remove(Preferences::nextEventAllDay)
remove(Preferences::nextEventLocation)
remove(Preferences::nextEventEndDate)
remove(Preferences::nextEventCalendarId)
}
MainWidget.updateWidget(context)
}
fun saveNextEventData(event: Event) {
Preferences.nextEventId = event.id
MainWidget.updateWidget(context)
}
fun getNextEvent(): Event? = realm.where(Event::class.java).equalTo("id", Preferences.nextEventId).findFirst() ?: realm.where(Event::class.java).findFirst()
fun goToNextEvent() {
val eventList = realm.where(Event::class.java).findAll()
if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
if (index > -1 && index < eventList.size - 1) {
Preferences.nextEventId = eventList[index + 1]!!.id
} else {
Preferences.nextEventId = eventList.first()!!.id
}
} else {
resetNextEventData()
}
UpdatesReceiver.setUpdates(context)
MainWidget.updateWidget(context)
}
fun goToPreviousEvent() {
val eventList = realm.where(Event::class.java).findAll()
if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
if (index > 0) {
Preferences.nextEventId = eventList[index - 1]!!.id
} else {
Preferences.nextEventId = eventList.last()!!.id
}
} else {
resetNextEventData()
}
UpdatesReceiver.setUpdates(context)
MainWidget.updateWidget(context)
}
fun getEvents(): RealmResults<Event> = realm.where(Event::class.java).findAll()
fun getEventsCount(): Int = realm.where(Event::class.java).findAll().size
}

View File

@ -30,7 +30,7 @@ object Preferences : KotprefModel() {
var customLocationLon by stringPref(key = "PREF_CUSTOM_LOCATION_LON", default = "") var customLocationLon by stringPref(key = "PREF_CUSTOM_LOCATION_LON", default = "")
var customLocationAdd by stringPref(key = "PREF_CUSTOM_LOCATION_ADD", default = "") var customLocationAdd by stringPref(key = "PREF_CUSTOM_LOCATION_ADD", default = "")
var hourFormat by stringPref(key = "PREF_HOUR_FORMAT", default = "12") var hourFormat by stringPref(key = "PREF_HOUR_FORMAT", default = "12")
var dateFormat by booleanPref(key = "PREF_ITA_FORMAT_DATE", default = false) var dateFormat by stringPref(default = "")
var weatherRefreshPeriod by intPref(key = "PREF_WEATHER_REFRESH_PERIOD", default = 1) var weatherRefreshPeriod by intPref(key = "PREF_WEATHER_REFRESH_PERIOD", default = 1)
var showUntil by intPref(key = "PREF_SHOW_UNTIL", default = 1) var showUntil by intPref(key = "PREF_SHOW_UNTIL", default = 1)
var calendarAppName by stringPref(key = "PREF_CALENDAR_APP_NAME", default = "") var calendarAppName by stringPref(key = "PREF_CALENDAR_APP_NAME", default = "")
@ -62,4 +62,6 @@ object Preferences : KotprefModel() {
var showGpsInformation by booleanPref(key = "PREF_SHOW_GPS_NOTIFICATION", default = true) var showGpsInformation by booleanPref(key = "PREF_SHOW_GPS_NOTIFICATION", default = true)
var showWallpaper by booleanPref(default = false) var showWallpaper by booleanPref(default = false)
var showBigClockWarning by booleanPref(default = true)
var showWeatherWarning by booleanPref(default = true)
} }

View File

@ -0,0 +1,20 @@
package com.tommasoberlose.anotherwidget.helpers
import android.app.AlarmManager
import android.content.Context
import android.text.format.DateFormat
import java.util.*
object AlarmHelper {
fun getNextAlarm(context: Context): String = with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
return if (
nextAlarmClock != null
&& nextAlarmClock.triggerTime - Calendar.getInstance().timeInMillis > 2 * 60 * 1000
&& nextAlarmClock.triggerTime - Calendar.getInstance().timeInMillis < 24 * 60 * 60 * 1000
) {
DateFormat.getTimeFormat(context).format(Date(nextAlarmClock.triggerTime))
} else {
""
}
}
}

View File

@ -0,0 +1,76 @@
package com.tommasoberlose.anotherwidget.helpers
import android.content.Context
import android.graphics.*
import android.graphics.drawable.Drawable
import android.view.View
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
object BitmapHelper {
fun getBitmapFromView(view: View): Bitmap {
//Define a bitmap with the same size as the view
val measuredWidth = View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.UNSPECIFIED)
val measuredHeight = View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.UNSPECIFIED)
view.measure(measuredWidth, measuredHeight)
view.layout(0,0, measuredWidth, measuredHeight)
val returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
//Bind a canvas to it
val canvas = Canvas(returnedBitmap)
// draw the view on the canvas
view.draw(canvas)
//return the bitmap
return returnedBitmap
}
fun getBitmapFromView(view: View, w: Int, h: Int): Bitmap {
//Define a bitmap with the same size as the view
val measuredWidth = View.MeasureSpec.makeMeasureSpec(w, View.MeasureSpec.EXACTLY)
val measuredHeight = View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.EXACTLY)
view.measure(measuredWidth, measuredHeight)
view.layout(0,0, measuredWidth, measuredHeight)
val returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
//Bind a canvas to it
val canvas = Canvas(returnedBitmap)
// draw the view on the canvas
view.draw(canvas)
//return the bitmap
return returnedBitmap
}
fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap {
var width = image.width
var height = image.height
val bitmapRatio = width.toFloat() / height.toFloat()
if (bitmapRatio > 1) {
width = maxSize
height = (width / bitmapRatio).toInt()
} else {
height = maxSize
width = (height * bitmapRatio).toInt()
}
return Bitmap.createScaledBitmap(image, width, height, true)
}
fun getTintedDrawable(context: Context, inputDrawable: Int, color: Int): Drawable? = ContextCompat.getDrawable(context, inputDrawable)?.apply {
DrawableCompat.setTint(this, color)
DrawableCompat.setTintMode(this, PorterDuff.Mode.SRC_IN)
}
fun changeBitmapColor(sourceBitmap: Bitmap, color: Int): Bitmap {
val resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0,
sourceBitmap.width - 1, sourceBitmap.height - 1)
val p = Paint()
val filter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)
p.colorFilter = filter
val canvas = Canvas(resultBitmap)
canvas.drawBitmap(resultBitmap, 0f, 0f, p)
return resultBitmap
}
}

View File

@ -0,0 +1,157 @@
package com.tommasoberlose.anotherwidget.helpers
import android.Manifest
import android.content.ContentUris
import android.content.Context
import android.provider.CalendarContract
import android.util.Log
import com.tommasoberlose.anotherwidget.services.EventListenerJob
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.models.Event
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import me.everything.providers.android.calendar.CalendarProvider
import org.greenrobot.eventbus.EventBus
import java.util.*
import kotlin.Comparator
import kotlin.collections.ArrayList
/**
* Created by tommaso on 08/10/17.
*/
object CalendarHelper {
fun updateEventList(context: Context) {
val eventRepository = EventRepository(context)
if (Preferences.showEvents) {
val eventList = ArrayList<Event>()
val now = Calendar.getInstance()
val limit = Calendar.getInstance()
when (Preferences.showUntil) {
0 -> limit.add(Calendar.HOUR, 3)
1 -> limit.add(Calendar.HOUR, 6)
2 -> limit.add(Calendar.HOUR, 12)
3 -> limit.add(Calendar.DAY_OF_MONTH, 1)
4 -> limit.add(Calendar.DAY_OF_MONTH, 3)
5 -> limit.add(Calendar.DAY_OF_MONTH, 7)
6 -> limit.add(Calendar.MINUTE, 30)
7 -> limit.add(Calendar.HOUR, 1)
else -> limit.add(Calendar.HOUR, 6)
}
val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
ContentUris.appendId(builder, now.timeInMillis)
ContentUris.appendId(builder, limit.timeInMillis)
if (!context.checkGrantedPermission(
Manifest.permission.READ_CALENDAR
)
) {
eventRepository.resetNextEventData()
} else {
val provider = CalendarProvider(context)
val data = provider.getInstances(now.timeInMillis, limit.timeInMillis)
if (data != null) {
val instances = data.list
for (instance in instances) {
try {
val e = provider.getEvent(instance.eventId)
if (e != null && !e.deleted && instance.begin <= limit.timeInMillis && (Preferences.calendarAllDay || !e.allDay) && !getFilteredCalendarIdList().contains(e.calendarId) && (Preferences.showDeclinedEvents || e.selfAttendeeStatus.toInt() != CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)) {
if (e.allDay) {
val start = Calendar.getInstance()
start.timeInMillis = instance.begin
val end = Calendar.getInstance()
end.timeInMillis = instance.end
instance.begin = start.timeInMillis - start.timeZone.getOffset(start.timeInMillis)
instance.end = end.timeInMillis - end.timeZone.getOffset(end.timeInMillis)
}
eventList.add(
Event(
instance.id,
e.id,
e.title ?: "",
instance.begin,
instance.end,
e.calendarId.toInt(),
e.allDay,
e.eventLocation ?: ""
)
)
}
} catch (ignored: Exception) {}
}
}
if (eventList.isEmpty()) {
eventRepository.resetNextEventData()
} else {
eventList.sortWith(Comparator { event: Event, event1: Event ->
if (event.allDay && event1.allDay) {
event.startDate.compareTo(event1.startDate)
} else if (event.allDay) {
1
} else if (event1.allDay) {
-1
} else {
event1.startDate.compareTo(event.startDate)
}
})
eventList.reverse()
Log.d("ciao", "list: $eventList")
eventRepository.saveEvents(
eventList
)
eventRepository.saveNextEventData(
eventList[0]
)
}
}
} else {
eventRepository.resetNextEventData()
}
UpdatesReceiver.setUpdates(context)
MainWidget.updateWidget(context)
EventBus.getDefault().post(MainActivity.UpdateUiMessageEvent())
}
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
val calendarList = ArrayList<me.everything.providers.android.calendar.Calendar>()
if (!context.checkGrantedPermission(
Manifest.permission.READ_CALENDAR
)
) {
return calendarList
}
val provider = CalendarProvider(context)
val data = provider.calendars
return if (data != null) {
data.list
} else {
calendarList
}
}
fun getFilteredCalendarIdList(): List<Long> {
return Preferences.calendarFilter.split(",").map { it.replace(" ", "") }.filter { it != "" }.map { it.toLong() }
}
fun filterCalendar(list: List<Long>) {
Preferences.calendarFilter = list.joinToString(separator = ",", prefix = " ")
}
fun setEventUpdatesAndroidN(context: Context) {
EventListenerJob.schedule(context)
}
fun removeEventUpdatesAndroidN(context: Context) {
EventListenerJob.remove(context)
}
}

View File

@ -0,0 +1,23 @@
package com.tommasoberlose.anotherwidget.helpers
import android.graphics.Color
import com.tommasoberlose.anotherwidget.global.Preferences
object ColorHelper {
fun getFontColor(): Int {
return try {
Color.parseColor(Preferences.textGlobalColor)
} catch (e: Exception) {
Color.parseColor("#FFFFFF")
}
}
fun Int.isColorDark(threshold: Double = 0.5): Boolean {
if (this == Color.TRANSPARENT) {
return false
}
val darkness =
1 - (0.299 * Color.red(this) + 0.587 * Color.green(this) + 0.114 * Color.blue(this)) / 255
return darkness >= threshold
}
}

View File

@ -0,0 +1,38 @@
package com.tommasoberlose.anotherwidget.helpers
import android.content.Context
import android.text.format.DateUtils
import android.util.Log
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.utils.getCapWordString
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
object DateHelper {
fun getDateText(context: Context, date: Calendar): String {
return if (Preferences.dateFormat != "") {
try {
SimpleDateFormat(Preferences.dateFormat, Locale.getDefault()).format(date.time)
} catch (e: Exception) {
getDefaultDateText(context, date)
}
} else {
val flags: Int =
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
"%s, %s".format(
SimpleDateFormat("EEEE", Locale.getDefault()).format(date.time),
DateUtils.formatDateTime(context, date.timeInMillis, flags)
).getCapWordString()
}
}
fun getDefaultDateText(context: Context, date: Calendar): String {
val flags: Int =
DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
return "%s, %s".format(
SimpleDateFormat("EEEE", Locale.getDefault()).format(date.time),
DateUtils.formatDateTime(context, date.timeInMillis, flags)
).getCapWordString()
}
}

View File

@ -0,0 +1,156 @@
package com.tommasoberlose.anotherwidget.helpers
import android.content.ComponentName
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.provider.AlarmClock
import android.provider.CalendarContract
import android.provider.CalendarContract.Events
import android.util.Log
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.models.Event
object IntentHelper {
fun getGoogleMapsIntentFromAddress(context: Context, address:String): Intent {
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=$address")
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
mapIntent.`package` = "com.google.android.apps.maps"
return if (mapIntent.resolveActivity(context.packageManager) != null) {
mapIntent
} else {
val map = "http://maps.google.co.in/maps?q=$address"
val i = Intent(Intent.ACTION_VIEW, Uri.parse(map));
i
}
}
fun getCalendarIntent(context: Context): Intent {
return when (Preferences.calendarAppPackage) {
"" -> {
Intent(Intent.ACTION_MAIN).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addCategory(Intent.CATEGORY_APP_CALENDAR)
}
}
"_" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
} catch (e: Exception) {
e.printStackTrace()
Intent(Intent.ACTION_MAIN).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addCategory(Intent.CATEGORY_APP_CALENDAR)
}
}
}
}
}
fun getWeatherIntent(context: Context): Intent {
return when (Preferences.weatherAppPackage) {
"" -> {
Intent(Intent.ACTION_VIEW).apply {
addCategory(Intent.CATEGORY_DEFAULT)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
data = Uri.parse("dynact://velour/weather/ProxyActivity")
component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
}
}
"_" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.weatherAppPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
} catch (e: Exception) {
Intent(Intent.ACTION_VIEW).apply {
addCategory(Intent.CATEGORY_DEFAULT)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
data = Uri.parse("dynact://velour/weather/ProxyActivity")
component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
}
}
}
}
}
fun getEventIntent(context: Context, e: Event): Intent {
return when (Preferences.eventAppPackage) {
"" -> {
val uri = ContentUris.withAppendedId(Events.CONTENT_URI, e.eventID)
Intent(Intent.ACTION_VIEW).apply {
data = uri
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
}
}
"_" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
val uri = ContentUris.withAppendedId(Events.CONTENT_URI, e.eventID)
try {
pm.getLaunchIntentForPackage(Preferences.eventAppPackage)!!.apply {
action = Intent.ACTION_VIEW
data = uri
addCategory(Intent.CATEGORY_LAUNCHER)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
}
} catch (ex: Exception) {
Intent(Intent.ACTION_VIEW).apply {
data = uri
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, e.startDate)
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, e.endDate)
}
}
}
}
}
fun getClockIntent(context: Context): Intent {
return when (Preferences.clockAppPackage) {
"" -> {
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
}
"_" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.clockAppPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
}
} catch (e: Exception) {
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
}
}
}
}
}

View File

@ -0,0 +1,115 @@
package com.tommasoberlose.anotherwidget.helpers
import android.content.Context
import android.text.format.DateUtils
import com.tommasoberlose.anotherwidget.R
import org.joda.time.DateTime
import java.util.concurrent.TimeUnit
object SettingsStringHelper {
fun getRefreshPeriodString(period: Int): Int {
return when (period) {
0 -> R.string.settings_weather_refresh_period_subtitle_0
1 -> R.string.settings_weather_refresh_period_subtitle_1
2 -> R.string.settings_weather_refresh_period_subtitle_2
3 -> R.string.settings_weather_refresh_period_subtitle_3
4 -> R.string.settings_weather_refresh_period_subtitle_4
5 -> R.string.settings_weather_refresh_period_subtitle_5
else -> R.string.settings_weather_refresh_period_subtitle_0
}
}
fun getShowUntilString(period: Int): Int {
return when (period) {
0 -> R.string.settings_show_until_subtitle_0
1 -> R.string.settings_show_until_subtitle_1
2 -> R.string.settings_show_until_subtitle_2
3 -> R.string.settings_show_until_subtitle_3
4 -> R.string.settings_show_until_subtitle_4
5 -> R.string.settings_show_until_subtitle_5
6 -> R.string.settings_show_until_subtitle_6
7 -> R.string.settings_show_until_subtitle_7
else -> R.string.settings_show_until_subtitle_1
}
}
fun getSecondRowInfoString(info: Int): Int {
return when (info) {
0 -> R.string.settings_second_row_info_subtitle_0
1 -> R.string.settings_second_row_info_subtitle_1
2 -> R.string.settings_second_row_info_subtitle_2
else -> R.string.settings_second_row_info_subtitle_0
}
}
fun getTextShadowString(shadow: Int): Int {
return when (shadow) {
0 -> R.string.settings_text_shadow_subtitle_none
1 -> R.string.settings_text_shadow_subtitle_low
2 -> R.string.settings_text_shadow_subtitle_high
else -> R.string.settings_text_shadow_subtitle_low
}
}
fun getCustomFontLabel(shadow: Int): Int {
return when (shadow) {
0 -> R.string.custom_font_subtitle_0
1 -> R.string.custom_font_subtitle_1
else -> R.string.custom_font_subtitle_1
}
}
fun getDifferenceText(context: Context, now: Long, start: Long): String {
val nowDate = DateTime(now)
val eventDate = DateTime(start)
var difference = start - now
difference += 60 * 1000 - (difference % (60 * 1000))
when {
difference <= 0 || TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
return ""
}
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.HOUR_IN_MILLIS).toString()
}
eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear -> {
return String.format("%s", context.getString(R.string.tomorrow))
}
eventDate.dayOfYear == nowDate.dayOfYear -> {
return String.format("%s", context.getString(R.string.today))
}
else -> {
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.DAY_IN_MILLIS).toString()
}
}
}
fun getAllDayEventDifferenceText(context: Context, now: Long, start: Long): String {
val nowDate = DateTime(now)
val eventDate = DateTime(start)
var difference = start - now
difference += 60 * 1000 - (difference % (60 * 1000))
return when (eventDate.dayOfYear) {
nowDate.dayOfYear -> {
""
}
nowDate.plusDays(1).dayOfYear -> {
String.format("%s", context.getString(R.string.tomorrow))
}
else -> {
DateUtils.getRelativeTimeSpanString(start, now, DateUtils.DAY_IN_MILLIS).toString()
}
}
}
fun getEmojiByUnicode(unicode: Int): String {
return String(Character.toChars(unicode))
}
}

View File

@ -1,4 +1,4 @@
package com.tommasoberlose.anotherwidget.utils package com.tommasoberlose.anotherwidget.helpers
import android.content.Context import android.content.Context
import com.google.android.gms.location.LocationServices import com.google.android.gms.location.LocationServices
@ -8,56 +8,34 @@ import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeathe
import com.kwabenaberko.openweathermaplib.models.currentweather.CurrentWeather import com.kwabenaberko.openweathermaplib.models.currentweather.CurrentWeather
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.network.WeatherNetworkApi
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
/** /**
* Created by tommaso on 08/10/17. * Created by tommaso on 08/10/17.
*/ */
object WeatherUtil { object WeatherHelper {
fun updateWeather(context: Context) { fun updateWeather(context: Context) {
val networkApi = WeatherNetworkApi(context)
if (Preferences.customLocationAdd != "") { if (Preferences.customLocationAdd != "") {
weatherNetworkRequest( networkApi.updateWeather()
context
)
} else { } else {
LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnSuccessListener { LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnSuccessListener {
Preferences.customLocationLat = it.latitude.toString() Preferences.customLocationLat = it.latitude.toString()
Preferences.customLocationLon = it.longitude.toString() Preferences.customLocationLon = it.longitude.toString()
weatherNetworkRequest(context) networkApi.updateWeather()
} }
} }
} }
private fun weatherNetworkRequest(context: Context) { fun removeWeather(context: Context) {
if (Preferences.showWeather && Preferences.weatherProviderApi != "" && Preferences.customLocationLat != "" && Preferences.customLocationLon != "") {
val helper = OpenWeatherMapHelper(Preferences.weatherProviderApi)
helper.setUnits(if (Preferences.weatherTempUnit == "F") Units.IMPERIAL else Units.METRIC)
helper.getCurrentWeatherByGeoCoordinates(Preferences.customLocationLat.toDouble(), Preferences.customLocationLon.toDouble(), object : CurrentWeatherCallback {
override fun onSuccess(currentWeather: CurrentWeather?) {
currentWeather?.let {
Preferences.weatherTemp = currentWeather.main.temp.toFloat()
Preferences.weatherIcon = currentWeather.weather[0].icon
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
Util.updateWidget(context)
}
}
override fun onFailure(throwable: Throwable?) {
}
})
} else {
removeWeather(context)
}
}
private fun removeWeather(context: Context) {
Preferences.remove(Preferences::weatherTemp) Preferences.remove(Preferences::weatherTemp)
Preferences.remove(Preferences::weatherTempUnit) Preferences.remove(Preferences::weatherTempUnit)
Util.updateWidget(context) MainWidget.updateWidget(context)
} }
fun getWeatherIconResource(icon: String): Int { fun getWeatherIconResource(icon: String): Int {

View File

@ -0,0 +1,16 @@
package com.tommasoberlose.anotherwidget.models
/**
* Created by tommaso on 08/10/17.
*/
class CalendarSelector(id: Long, name: String?, accountName: String?) {
var id: Long = 0
var name: String = ""
var accountName: String = ""
init {
this.id = id
this.name = name ?: ""
this.accountName = accountName ?: ""
}
}

View File

@ -1,4 +1,4 @@
package com.tommasoberlose.anotherwidget.components.events package com.tommasoberlose.anotherwidget.models
import io.realm.RealmObject import io.realm.RealmObject
import java.util.Date import java.util.Date

View File

@ -0,0 +1,44 @@
package com.tommasoberlose.anotherwidget.network
import android.content.Context
import com.kwabenaberko.openweathermaplib.constants.Units
import com.kwabenaberko.openweathermaplib.implementation.OpenWeatherMapHelper
import com.kwabenaberko.openweathermaplib.implementation.callbacks.CurrentWeatherCallback
import com.kwabenaberko.openweathermaplib.models.currentweather.CurrentWeather
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import org.greenrobot.eventbus.EventBus
class WeatherNetworkApi(val context: Context) {
fun updateWeather() {
if (Preferences.showWeather && Preferences.weatherProviderApi != "" && Preferences.customLocationLat != "" && Preferences.customLocationLon != "") {
val helper = OpenWeatherMapHelper(Preferences.weatherProviderApi)
helper.setUnits(if (Preferences.weatherTempUnit == "F") Units.IMPERIAL else Units.METRIC)
helper.getCurrentWeatherByGeoCoordinates(Preferences.customLocationLat.toDouble(), Preferences.customLocationLon.toDouble(), object :
CurrentWeatherCallback {
override fun onSuccess(currentWeather: CurrentWeather?) {
currentWeather?.let {
Preferences.weatherTemp = currentWeather.main.temp.toFloat()
Preferences.weatherIcon = currentWeather.weather[0].icon
Preferences.weatherRealTempUnit = Preferences.weatherTempUnit
MainWidget.updateWidget(
context
)
EventBus.getDefault().post(MainActivity.UpdateUiMessageEvent())
}
}
override fun onFailure(throwable: Throwable?) {
}
})
} else {
WeatherHelper.removeWeather(
context
)
}
}
}

View File

@ -4,22 +4,25 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log import android.util.Log
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
class NewCalendarEventReceiver : BroadcastReceiver() { class NewCalendarEventReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
when { val eventRepository = EventRepository(context)
intent.action.equals(Intent.ACTION_PROVIDER_CHANGED) -> { Log.d("ciao", "nuovo evento")
CalendarUtil.updateEventList(context) when (intent.action) {
Intent.ACTION_PROVIDER_CHANGED,
Intent.ACTION_TIME_CHANGED -> {
CalendarHelper.updateEventList(context)
} }
intent.action == Actions.ACTION_GO_TO_NEXT_EVENT -> { Actions.ACTION_GO_TO_NEXT_EVENT -> {
CalendarUtil.goToNextEvent(context) eventRepository.goToNextEvent()
} }
intent.action == Actions.ACTION_GO_TO_PREVIOUS_EVENT -> { Actions.ACTION_GO_TO_PREVIOUS_EVENT -> {
CalendarUtil.goToPreviousEvent(context) eventRepository.goToPreviousEvent()
} }
} }
} }

View File

@ -5,12 +5,13 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.app.AlarmManager import android.app.AlarmManager
import android.app.PendingIntent import android.app.PendingIntent
import com.tommasoberlose.anotherwidget.components.events.Event import android.util.Log
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.utils.CalendarUtil import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.Util
import org.joda.time.Period import org.joda.time.Period
import java.text.DateFormat
import java.util.* import java.util.*
@ -20,11 +21,11 @@ class UpdatesReceiver : BroadcastReceiver() {
when (intent.action) { when (intent.action) {
Intent.ACTION_BOOT_COMPLETED, Intent.ACTION_BOOT_COMPLETED,
Intent.ACTION_MY_PACKAGE_REPLACED, Intent.ACTION_MY_PACKAGE_REPLACED,
Actions.ACTION_CALENDAR_UPDATE -> CalendarUtil.updateEventList(context) Actions.ACTION_CALENDAR_UPDATE -> CalendarHelper.updateEventList(context)
"com.sec.android.widgetapp.APPWIDGET_RESIZE", "com.sec.android.widgetapp.APPWIDGET_RESIZE",
Intent.ACTION_DATE_CHANGED, Intent.ACTION_DATE_CHANGED,
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED -> Util.updateWidget(context) AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED -> MainWidget.updateWidget(context)
} }
} }
@ -32,8 +33,9 @@ class UpdatesReceiver : BroadcastReceiver() {
fun setUpdates(context: Context) { fun setUpdates(context: Context) {
removeUpdates(context) removeUpdates(context)
val eventRepository = EventRepository(context)
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) { with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
CalendarUtil.getEvents().forEach { event -> eventRepository.getEvents().forEach { event ->
val hoursDiff = Period(Calendar.getInstance().timeInMillis, event.startDate).hours val hoursDiff = Period(Calendar.getInstance().timeInMillis, event.startDate).hours
// Update the widget every hour till the event // Update the widget every hour till the event

View File

@ -7,18 +7,19 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.utils.Util import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
import com.tommasoberlose.anotherwidget.utils.WeatherUtil
import java.util.* import java.util.*
class WeatherReceiver : BroadcastReceiver() { class WeatherReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED || intent.action == Intent.ACTION_MY_PACKAGE_REPLACED) { when (intent.action) {
setUpdates(context) Intent.ACTION_BOOT_COMPLETED,
} else if (intent.action == Actions.ACTION_WEATHER_UPDATE) { Intent.ACTION_MY_PACKAGE_REPLACED,
WeatherUtil.updateWeather(context) Intent.ACTION_TIME_CHANGED -> setUpdates(context)
Actions.ACTION_WEATHER_UPDATE -> WeatherHelper.updateWeather(context)
} }
} }
@ -27,7 +28,7 @@ class WeatherReceiver : BroadcastReceiver() {
removeUpdates(context) removeUpdates(context)
if (Preferences.showWeather && Preferences.weatherProviderApi != "") { if (Preferences.showWeather && Preferences.weatherProviderApi != "") {
WeatherUtil.updateWeather(context) WeatherHelper.updateWeather(context)
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) { with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val pi = PendingIntent.getBroadcast( val pi = PendingIntent.getBroadcast(

View File

@ -5,8 +5,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.utils.Util import com.tommasoberlose.anotherwidget.helpers.IntentHelper
import com.tommasoberlose.anotherwidget.global.Constants
class WidgetClickListenerReceiver : BroadcastReceiver() { class WidgetClickListenerReceiver : BroadcastReceiver() {
@ -15,10 +14,10 @@ class WidgetClickListenerReceiver : BroadcastReceiver() {
if (intent.action == Actions.ACTION_OPEN_WEATHER_INTENT) { if (intent.action == Actions.ACTION_OPEN_WEATHER_INTENT) {
context.sendBroadcast(Intent(Actions.ACTION_WEATHER_UPDATE)) context.sendBroadcast(Intent(Actions.ACTION_WEATHER_UPDATE))
try { try {
context.startActivity(Util.getWeatherIntent(context)) context.startActivity(IntentHelper.getWeatherIntent(context))
} catch (e: Exception) { } catch (e: Exception) {
try { try {
context.applicationContext.startActivity(Util.getWeatherIntent(context.applicationContext)) context.applicationContext.startActivity(IntentHelper.getWeatherIntent(context.applicationContext))
} catch (e: Exception) { } catch (e: Exception) {
val uri = Uri.parse("http://www.google.com/#q=weather") val uri = Uri.parse("http://www.google.com/#q=weather")
val i = Intent(Intent.ACTION_VIEW, uri) val i = Intent(Intent.ACTION_VIEW, uri)

View File

@ -0,0 +1,55 @@
package com.tommasoberlose.anotherwidget.services
import android.app.job.JobInfo
import android.app.job.JobInfo.TriggerContentUri
import android.app.job.JobParameters
import android.app.job.JobScheduler
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
import android.os.Build
import android.provider.CalendarContract
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
class EventListenerJob : JobService() {
override fun onStartJob(params: JobParameters): Boolean {
CalendarHelper.updateEventList(this)
schedule(
this
)
return false
}
@Synchronized
override fun onStopJob(params: JobParameters): Boolean {
return false
}
companion object {
private const val jobId = 1005
fun schedule(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val componentName = ComponentName(
context,
EventListenerJob::class.java
)
with(context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler) {
schedule(
JobInfo.Builder(jobId, componentName)
.addTriggerContentUri(TriggerContentUri(
CalendarContract.CONTENT_URI,
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
))
.build()
)
}
}
}
fun remove(context: Context) {
val js = context.getSystemService(JobScheduler::class.java)
js?.cancel(jobId)
}
}
}

View File

@ -3,33 +3,22 @@ package com.tommasoberlose.anotherwidget.ui.activities
import android.app.Activity import android.app.Activity
import android.os.Bundle import android.os.Bundle
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import android.content.Intent import android.content.Intent
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import com.tommasoberlose.anotherwidget.components.events.ApplicationListEvent import android.content.pm.ResolveInfo
import android.text.Editable
import android.text.TextWatcher
import android.view.View import android.view.View
import android.view.Window
import android.widget.ImageView import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.databinding.Observable
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 androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialFadeThrough import com.bumptech.glide.Glide
import com.tommasoberlose.anotherwidget.components.events.AppInfoSavedEvent
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.ChooseApplicationViewModel
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.utils.toast
import kotlinx.android.synthetic.main.activity_choose_application.* import kotlinx.android.synthetic.main.activity_choose_application.*
import kotlinx.android.synthetic.main.activity_choose_application.list_view import kotlinx.android.synthetic.main.activity_choose_application.list_view
import kotlinx.coroutines.* import kotlinx.coroutines.*
@ -71,14 +60,16 @@ class ChooseApplicationActivity : AppCompatActivity() {
finish() finish()
} }
} }
.register<ApplicationInfo>(R.layout.application_info_layout) { item, injector -> .register<ResolveInfo>(R.layout.application_info_layout) { item, injector ->
injector injector
.text(R.id.text, pm.getApplicationLabel(item).toString()) .text(R.id.text, item.loadLabel(pm))
.with<ImageView>(R.id.icon) {
try { Glide
injector.image(R.id.icon, item.loadIcon(pm)) .with(this)
} catch (ignore: Exception) { .load(item.loadIcon(pm))
} .centerCrop()
.into(it)
}
injector.clicked(R.id.item) { injector.clicked(R.id.item) {
saveApp(item) saveApp(item)
@ -110,9 +101,7 @@ class ChooseApplicationActivity : AppCompatActivity() {
viewModel.appList.value!! viewModel.appList.value!!
} else { } else {
viewModel.appList.value!!.filter { viewModel.appList.value!!.filter {
pm.getApplicationLabel( it.loadLabel(pm).contains(search, true)
it
).toString().contains(search, true)
} }
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -130,10 +119,10 @@ class ChooseApplicationActivity : AppCompatActivity() {
} }
} }
private fun saveApp(app: ApplicationInfo) { private fun saveApp(app: ResolveInfo) {
val resultIntent = Intent() val resultIntent = Intent()
resultIntent.putExtra(Constants.RESULT_APP_NAME, pm.getApplicationLabel(app).toString()) resultIntent.putExtra(Constants.RESULT_APP_NAME, app.loadLabel(pm))
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.packageName) resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.resolvePackageName)
setResult(Activity.RESULT_OK, resultIntent) setResult(Activity.RESULT_OK, resultIntent)
finish() finish()
} }

View File

@ -0,0 +1,124 @@
package com.tommasoberlose.anotherwidget.ui.activities
import android.app.Activity
import android.location.Address
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
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.bulk
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomDateBinding
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.DateHelper
import com.tommasoberlose.anotherwidget.ui.viewmodels.CustomDateViewModel
import com.tommasoberlose.anotherwidget.utils.openURI
import kotlinx.android.synthetic.main.activity_custom_date.*
import kotlinx.android.synthetic.main.activity_custom_location.action_back
import kotlinx.android.synthetic.main.activity_custom_location.list_view
import kotlinx.coroutines.*
import net.idik.lib.slimadapter.SlimAdapter
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
class CustomDateActivity : AppCompatActivity() {
private lateinit var adapter: SlimAdapter
private lateinit var viewModel: CustomDateViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(CustomDateViewModel::class.java)
val binding = DataBindingUtil.setContentView<ActivityCustomDateBinding>(this, R.layout.activity_custom_date)
list_view.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(this)
list_view.layoutManager = mLayoutManager
adapter = SlimAdapter.create()
adapter
.register<String>(R.layout.custom_date_example_item) { item, injector ->
injector
.text(R.id.custom_date_example_format, item)
.text(R.id.custom_date_example_value, SimpleDateFormat(item, Locale.getDefault()).format(DATE.time))
}
.attachTo(list_view)
adapter.updateData(
listOf(
"d", "dd", "EE", "EEEE", "MM", "MMM", "MMMM", "yy", "yyyy"
)
)
setupListener()
subscribeUi(binding, viewModel)
date_format.requestFocus()
}
private var formatJob: Job? = null
private fun subscribeUi(binding: ActivityCustomDateBinding, viewModel: CustomDateViewModel) {
binding.viewModel = viewModel
viewModel.dateInput.observe(this, Observer { dateFormat ->
formatJob?.cancel()
formatJob = lifecycleScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
loader.visibility = View.VISIBLE
}
delay(200)
val text = if (dateFormat != "") {
try {
SimpleDateFormat(dateFormat, Locale.getDefault()).format(DATE.time)
} catch (e: Exception) {
ERROR_STRING
}
} else {
"__"
}
withContext(Dispatchers.Main) {
action_save.isVisible = text != ERROR_STRING
loader.visibility = View.INVISIBLE
date_format_value.text = text
}
}
})
}
private fun setupListener() {
action_back.setOnClickListener {
onBackPressed()
}
action_save.setOnClickListener {
Preferences.dateFormat = viewModel.dateInput.value ?: ""
finish()
}
action_date_format_info.setOnClickListener {
openURI("https://developer.android.com/reference/java/text/SimpleDateFormat")
}
}
companion object {
const val ERROR_STRING = "--"
val DATE: Calendar = Calendar.getInstance().apply {
set(Calendar.MONTH, 10)
set(Calendar.DAY_OF_MONTH, 1)
set(Calendar.YEAR, 1993)
}
}
}

View File

@ -27,7 +27,6 @@ import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.components.events.CustomLocationEvent
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
import com.tommasoberlose.anotherwidget.databinding.ActivityCustomLocationBinding import com.tommasoberlose.anotherwidget.databinding.ActivityCustomLocationBinding
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences

View File

@ -2,37 +2,43 @@ package com.tommasoberlose.anotherwidget.ui.activities
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.app.Activity import android.app.Activity
import android.os.Bundle
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.view.View
import com.tommasoberlose.anotherwidget.R
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.drawable.Drawable import android.os.Bundle
import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.widget.LinearLayout import android.view.View
import android.widget.RelativeLayout import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.addListener import androidx.core.animation.addListener
import androidx.core.animation.doOnEnd
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.global.RequestCode import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
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
import com.tommasoberlose.anotherwidget.utils.* import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.getCurrentWallpaper
import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.ui.widgets.TheWidget
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener { class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
@ -62,19 +68,38 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
}.attach() }.attach()
// Init clock
clock.setTextColor(ColorHelper.getFontColor())
clock.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity))
clock.format12Hour = "hh:mm"
clock.isVisible = Preferences.showClock
preview.layoutParams = preview.layoutParams.apply {
height = 160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0
}
Preferences.preferences.registerOnSharedPreferenceChangeListener(this) Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
subscribeUi(viewModel) subscribeUi(viewModel)
updateUI() updateUI()
CalendarHelper.updateEventList(this)
WeatherHelper.updateWeather(this)
} }
private var uiJob: Job? = null
private fun updateUI() { private fun updateUI() {
lifecycleScope.launch(Dispatchers.IO) { preview.setCardBackgroundColor(getColor(if (ColorHelper.getFontColor().isColorDark()) android.R.color.white else R.color.colorAccent))
val generatedView = TheWidget.generateWidgetView(this@MainActivity, preview.measuredWidth) val generatedView = MainWidget.generateWidgetView(this@MainActivity)
generatedView.measure(0, 0) generatedView.measure(0, 0)
val bitmap = Util.getBitmapFromView(generatedView, generatedView.measuredWidth, generatedView.measuredHeight) preview.measure(0, 0)
uiJob?.cancel()
uiJob = lifecycleScope.launch(Dispatchers.IO) {
val bitmap = BitmapHelper.getBitmapFromView(generatedView, if (preview.width > 0) preview.width else generatedView.measuredWidth, generatedView.measuredHeight)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
// Clock // Clock
clock.setTextColor(Util.getFontColor()) clock.setTextColor(ColorHelper.getFontColor())
clock.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity)) clock.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity))
clock.format12Hour = "hh:mm" clock.format12Hour = "hh:mm"
@ -112,7 +137,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}.start() }.start()
ValueAnimator.ofInt( ValueAnimator.ofInt(
preview.measuredHeight, preview.height,
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0 160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0
).apply { ).apply {
duration = 500L duration = 500L
@ -126,14 +151,20 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
widget_bitmap.setImageBitmap(bitmap) widget_bitmap.setImageBitmap(bitmap)
widget_loader.animate().scaleX(0f).scaleY(0f).start()
widget.animate().alpha(1f).start()
} }
} }
} }
private fun subscribeUi(viewModel: MainViewModel) { private fun subscribeUi(viewModel: MainViewModel) {
viewModel.showWallpaper.observe(this, Observer { viewModel.showWallpaper.observe(this, Observer {
widget_bg.setImageDrawable(if (it) Util.getCurrentWallpaper(this) else null) widget_bg.setImageDrawable(if (it) getCurrentWallpaper() else null)
}) })
logo.setOnClickListener {
// startActivity(Intent(this, SupportDevActivity::class.java))
}
} }
override fun onBackPressed() { override fun onBackPressed() {
@ -171,11 +202,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
if (extras.containsKey(Actions.ACTION_EXTRA_OPEN_WEATHER_PROVIDER)) { if (extras.containsKey(Actions.ACTION_EXTRA_OPEN_WEATHER_PROVIDER)) {
startActivityForResult(Intent(this, WeatherProviderActivity::class.java), RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code) startActivityForResult(Intent(this, WeatherProviderActivity::class.java), RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code)
} }
if (extras.containsKey(Actions.ACTION_EXTRA_DISABLE_GPS_NOTIFICATION)) {
Preferences.showGpsInformation = false
sendBroadcast(Intent(Actions.ACTION_WEATHER_UPDATE))
finish()
}
} }
} }
@ -193,6 +219,23 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) { override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
updateUI() updateUI()
Util.updateWidget(this) MainWidget.updateWidget(this)
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
class UpdateUiMessageEvent
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
updateUI()
} }
} }

View File

@ -5,6 +5,7 @@ import android.content.Intent
import android.location.Address import android.location.Address
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -26,7 +27,6 @@ import net.idik.lib.slimadapter.SlimAdapter
class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener { class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
private val BILLING_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAox5CcxuoLJ6CmNS7s6lVQzJ253njKKGF8MoQ/gQ5gEw2Fr03fBvtHpiVMpnjhNLw5NMeIpzRvkVqeQ7BfkC7c0BLCJUqf/fFA11ArQe8na6QKt5O4d+v4sbHtP7mm3GQNPOBaqRzcpFZaiAbfk6mnalo+tzM47GXrQFt5bNSrMctCs7bbChqJfH2cyMW0F8DHWEEeO5xElBmH3lh4FVpwIUTPYJIV3n0yhE3qqRA0WXkDej66g/uAt/rebmMZLmwNwIive5cObU4o41YyKRv2wSAicrv3W40LftzXAOOordIbmzDFN8ksh3VrnESqwCDGG97nZVbPG/+3LD0xHWiRwIDAQAB"
private lateinit var viewModel: SupportDevViewModel private lateinit var viewModel: SupportDevViewModel
private lateinit var adapter: SlimAdapter private lateinit var adapter: SlimAdapter
@ -35,7 +35,7 @@ class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
viewModel = ViewModelProvider(this).get(SupportDevViewModel::class.java) viewModel = ViewModelProvider(this).get(SupportDevViewModel::class.java)
viewModel.billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build() viewModel.billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build()
val binding = DataBindingUtil.setContentView<ActivitySupportDevBinding>(this, R.layout.activity_support_dev) DataBindingUtil.setContentView<ActivitySupportDevBinding>(this, R.layout.activity_support_dev)
list_view.setHasFixedSize(true) list_view.setHasFixedSize(true)

View File

@ -1,21 +1,14 @@
package com.tommasoberlose.anotherwidget.ui.activities package com.tommasoberlose.anotherwidget.ui.activities
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.content.DialogInterface
import android.content.SharedPreferences
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.Editable
import android.text.Html import android.text.Html
import android.text.TextWatcher
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.utils.Util
import com.tommasoberlose.anotherwidget.utils.WeatherUtil
import com.tommasoberlose.anotherwidget.utils.openURI import com.tommasoberlose.anotherwidget.utils.openURI
import kotlinx.android.synthetic.main.activity_weather_provider.* import kotlinx.android.synthetic.main.activity_weather_provider.*
@ -46,18 +39,4 @@ class WeatherProviderActivity : AppCompatActivity() {
} }
api_key.editText?.setText(Preferences.weatherProviderApi) api_key.editText?.setText(Preferences.weatherProviderApi)
} }
override fun onBackPressed() {
if (api_key.editText?.text.toString() == "") {
AlertDialog.Builder(this)
.setMessage(getString(R.string.error_weather_api_key))
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.yes) { _, _ ->
super.onBackPressed()
}
.show()
} else {
super.onBackPressed()
}
}
} }

View File

@ -14,23 +14,21 @@ 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.google.android.material.bottomsheet.BottomSheetDialog
import com.karumi.dexter.Dexter import com.karumi.dexter.Dexter
import com.karumi.dexter.MultiplePermissionsReport import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.BuildConfig
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentAdvancedSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentAdvancedSettingsBinding
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.utils.CalendarUtil import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.utils.Util import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.openURI import com.tommasoberlose.anotherwidget.utils.openURI
import kotlinx.android.synthetic.main.fragment_advanced_settings.* import kotlinx.android.synthetic.main.fragment_advanced_settings.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -57,7 +55,7 @@ class AdvancedSettingsFragment : Fragment() {
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java) viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
val binding = DataBindingUtil.inflate<FragmentAdvancedSettingsBinding>(inflater, R.layout.fragment_advanced_settings, container, false) val binding = DataBindingUtil.inflate<FragmentAdvancedSettingsBinding>(inflater, R.layout.fragment_advanced_settings, container, false)
subscribeUi(binding, viewModel) subscribeUi(viewModel)
binding.lifecycleOwner = this binding.lifecycleOwner = this
binding.viewModel = viewModel binding.viewModel = viewModel
@ -69,10 +67,11 @@ class AdvancedSettingsFragment : Fragment() {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
setupListener() setupListener()
app_version.text = "v%s".format(BuildConfig.VERSION_NAME)
} }
private fun subscribeUi( private fun subscribeUi(
binding: FragmentAdvancedSettingsBinding,
viewModel: MainViewModel viewModel: MainViewModel
) { ) {
viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer { viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer {
@ -94,8 +93,8 @@ class AdvancedSettingsFragment : Fragment() {
private fun setupListener() { private fun setupListener() {
action_change_theme.setOnClickListener { action_change_theme.setOnClickListener {
maintainScrollPosition { maintainScrollPosition {
BottomSheetMenu<Int>(requireContext()) BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_theme_title))
.selectResource(Preferences.darkThemePreference) .setSelectedValue(Preferences.darkThemePreference)
.addItem( .addItem(
getString(R.string.settings_subtitle_dark_theme_light), getString(R.string.settings_subtitle_dark_theme_light),
AppCompatDelegate.MODE_NIGHT_NO AppCompatDelegate.MODE_NIGHT_NO
@ -116,11 +115,23 @@ class AdvancedSettingsFragment : Fragment() {
action_show_wallpaper.setOnClickListener { action_show_wallpaper.setOnClickListener {
maintainScrollPosition { maintainScrollPosition {
if (Preferences.showWallpaper) { BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_title_show_wallpaper))
Preferences.showWallpaper = false .setSelectedValue(Preferences.showWallpaper)
} else { .addItem(
requirePermission() getString(R.string.settings_visible),
} true
)
.addItem(
getString(R.string.settings_not_visible),
false
)
.addOnSelectItemListener { value ->
if (value) {
requirePermission()
} else {
Preferences.showWallpaper = value
}
}.show()
} }
} }
@ -137,8 +148,8 @@ class AdvancedSettingsFragment : Fragment() {
} }
action_refresh_widget.setOnClickListener { action_refresh_widget.setOnClickListener {
Util.updateWidget(requireContext()) MainWidget.updateWidget(requireContext())
CalendarUtil.updateEventList(requireContext()) CalendarHelper.updateEventList(requireContext())
} }
} }

View File

@ -4,12 +4,11 @@ import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
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.SimpleAdapter
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
@ -25,7 +24,7 @@ import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.components.CalendarSelector import com.tommasoberlose.anotherwidget.models.CalendarSelector
import com.tommasoberlose.anotherwidget.databinding.FragmentCalendarSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentCalendarSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
@ -33,16 +32,19 @@ import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
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.utils.CalendarUtil import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.utils.Util import com.tommasoberlose.anotherwidget.helpers.DateHelper
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
import com.tommasoberlose.anotherwidget.ui.activities.CustomDateActivity
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.toast import com.tommasoberlose.anotherwidget.utils.toast
import kotlinx.android.synthetic.main.fragment_calendar_settings.* import kotlinx.android.synthetic.main.fragment_calendar_settings.*
import kotlinx.android.synthetic.main.fragment_calendar_settings.scrollView import kotlinx.android.synthetic.main.fragment_calendar_settings.scrollView
import kotlinx.android.synthetic.main.fragment_weather_settings.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.Comparator
class CalendarSettingsFragment : Fragment() { class CalendarSettingsFragment : Fragment() {
@ -85,6 +87,12 @@ class CalendarSettingsFragment : Fragment() {
viewModel.showEvents.observe(viewLifecycleOwner, Observer { viewModel.showEvents.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
binding.isCalendarEnabled = it binding.isCalendarEnabled = it
if (it) {
CalendarHelper.setEventUpdatesAndroidN(requireContext())
} else {
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
}
} }
checkReadEventsPermission() checkReadEventsPermission()
}) })
@ -106,7 +114,7 @@ class CalendarSettingsFragment : Fragment() {
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer { viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
second_row_info_label.text = getString(Util.getSecondRowInfoString(it)) second_row_info_label.text = getString(SettingsStringHelper.getSecondRowInfoString(it))
} }
}) })
@ -118,23 +126,18 @@ class CalendarSettingsFragment : Fragment() {
viewModel.showUntil.observe(viewLifecycleOwner, Observer { viewModel.showUntil.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_until_label.text = getString(Util.getShowUntilString(it)) show_until_label.text = getString(SettingsStringHelper.getShowUntilString(it))
} }
checkReadEventsPermission() checkReadEventsPermission()
}) })
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer { viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
show_multiple_events_label.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible) show_multiple_events_label.setTextKeepState(if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
}) })
viewModel.dateFormat.observe(viewLifecycleOwner, Observer { viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
val now = Calendar.getInstance() date_format_label.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
var dateStringValue: String = String.format("%s%s", SimpleDateFormat(Constants.engDateFormat, Locale.getDefault()).format(now.time)[0].toUpperCase(), SimpleDateFormat(Constants.engDateFormat, Locale.getDefault()).format(now.time).substring(1))
if (it) {
dateStringValue = String.format("%s%s", SimpleDateFormat(Constants.itDateFormat, Locale.getDefault()).format(now.time)[0].toUpperCase(), SimpleDateFormat(Constants.itDateFormat, Locale.getDefault()).format(now.time).substring(1))
}
date_format_label.text = dateStringValue
} }
}) })
@ -159,26 +162,51 @@ class CalendarSettingsFragment : Fragment() {
} }
action_filter_calendar.setOnClickListener { action_filter_calendar.setOnClickListener {
val calendarSelectorList: List<CalendarSelector> = CalendarUtil.getCalendarList(requireContext()).map { CalendarSelector(it.id.toInt(), it.displayName, it.accountName) } val calendarSelectorList: List<CalendarSelector> = CalendarHelper.getCalendarList(requireContext()).map {
var calFiltered = Preferences.calendarFilter CalendarSelector(
it.id,
it.displayName,
it.accountName
)
}.sortedWith(Comparator { cal1, cal2 ->
when {
cal1.accountName != cal2.accountName -> {
cal1.accountName.compareTo(cal2.accountName)
}
cal1.accountName == cal1.name -> {
-1
}
cal2.accountName == cal2.accountName -> {
1
}
else -> {
cal1.name.compareTo(cal2.name)
}
}
})
if (calendarSelectorList.isNotEmpty()) { if (calendarSelectorList.isNotEmpty()) {
val calNames = calendarSelectorList.map { if (it.name == it.account_name) String.format("%s: %s", getString(R.string.main_calendar), it.name) else it.name }.toTypedArray() val filteredCalendarIds = CalendarHelper.getFilteredCalendarIdList()
val calSelected = calendarSelectorList.map { !calFiltered.contains(" " + it.id.toString() + ",") }.toBooleanArray() val visibleCalendarIds = calendarSelectorList.map { it.id }.filter { id: Long -> !filteredCalendarIds.contains(id) }
AlertDialog.Builder(requireContext()).setTitle(getString(R.string.settings_filter_calendar_subtitle)) val dialog = BottomSheetMenu<Long>(requireContext(), header = getString(R.string.settings_filter_calendar_subtitle), isMultiSelection = true)
.setMultiChoiceItems(calNames, calSelected) { _, item, isChecked -> .setSelectedValues(visibleCalendarIds)
val dialogItem: String = String.format(" %s%s", calendarSelectorList.get(item).id, ",")
calFiltered = calFiltered.replace(dialogItem, ""); calendarSelectorList.indices.forEach { index ->
if (!isChecked) { if (index == 0 || calendarSelectorList[index].accountName != calendarSelectorList[index - 1].accountName) {
calFiltered += dialogItem dialog.addItem(calendarSelectorList[index].accountName)
}
} }
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
Preferences.calendarFilter = calFiltered dialog.addItem(
} if (calendarSelectorList[index].name == calendarSelectorList[index].accountName) getString(R.string.account_events) else calendarSelectorList[index].name,
.setNegativeButton(android.R.string.cancel, null) calendarSelectorList[index].id
.show() )
}
dialog.addOnMultipleSelectItemListener { values ->
CalendarHelper.filterCalendar(calendarSelectorList.map { it.id }.filter { !values.contains(it) })
checkReadEventsPermission()
}.show()
} else { } else {
requireActivity().toast(getString(R.string.calendar_settings_list_error)) requireActivity().toast(getString(R.string.calendar_settings_list_error))
} }
@ -186,7 +214,7 @@ class CalendarSettingsFragment : Fragment() {
action_show_all_day.setOnClickListener { action_show_all_day.setOnClickListener {
if (Preferences.showEvents) { if (Preferences.showEvents) {
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.calendarAllDay) BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_all_day_title)).setSelectedValue(Preferences.calendarAllDay)
.addItem(getString(R.string.settings_all_day_subtitle_visible), true) .addItem(getString(R.string.settings_all_day_subtitle_visible), true)
.addItem(getString(R.string.settings_all_day_subtitle_gone), false) .addItem(getString(R.string.settings_all_day_subtitle_gone), false)
.addOnSelectItemListener { value -> .addOnSelectItemListener { value ->
@ -197,7 +225,7 @@ class CalendarSettingsFragment : Fragment() {
action_show_declined_events.setOnClickListener { action_show_declined_events.setOnClickListener {
if (Preferences.showEvents) { if (Preferences.showEvents) {
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.showDeclinedEvents) BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_declined_events_title)).setSelectedValue(Preferences.showDeclinedEvents)
.addItem(getString(R.string.settings_visible), true) .addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false) .addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value -> .addOnSelectItemListener { value ->
@ -208,7 +236,7 @@ class CalendarSettingsFragment : Fragment() {
action_show_multiple_events.setOnClickListener { action_show_multiple_events.setOnClickListener {
if (Preferences.showEvents) { if (Preferences.showEvents) {
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.showNextEvent) BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_multiple_events_title)).setSelectedValue(Preferences.showNextEvent)
.addItem(getString(R.string.settings_visible), true) .addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false) .addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value -> .addOnSelectItemListener { value ->
@ -219,7 +247,7 @@ class CalendarSettingsFragment : Fragment() {
action_show_diff_time.setOnClickListener { action_show_diff_time.setOnClickListener {
if (Preferences.showEvents) { if (Preferences.showEvents) {
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.showDiffTime) BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_diff_time_title)).setSelectedValue(Preferences.showDiffTime)
.addItem(getString(R.string.settings_visible), true) .addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false) .addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value -> .addOnSelectItemListener { value ->
@ -230,9 +258,9 @@ class CalendarSettingsFragment : Fragment() {
action_second_row_info.setOnClickListener { action_second_row_info.setOnClickListener {
if (Preferences.showEvents) { if (Preferences.showEvents) {
val dialog = BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.secondRowInformation) val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_second_row_info_title)).setSelectedValue(Preferences.secondRowInformation)
(0 .. 1).forEach { (0 .. 1).forEach {
dialog.addItem(getString(Util.getSecondRowInfoString(it)), it) dialog.addItem(getString(SettingsStringHelper.getSecondRowInfoString(it)), it)
} }
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
Preferences.secondRowInformation = value Preferences.secondRowInformation = value
@ -242,9 +270,9 @@ class CalendarSettingsFragment : Fragment() {
action_show_until.setOnClickListener { action_show_until.setOnClickListener {
if (Preferences.showEvents) { if (Preferences.showEvents) {
val dialog = BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.showUntil) val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
intArrayOf(6,7,0,1,2,3,4,5).forEach { intArrayOf(6,7,0,1,2,3,4,5).forEach {
dialog.addItem(getString(Util.getShowUntilString(it)), it) dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
} }
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
Preferences.showUntil = value Preferences.showUntil = value
@ -252,6 +280,27 @@ class CalendarSettingsFragment : Fragment() {
} }
} }
action_date_format.setOnClickListener {
if (Preferences.showEvents) {
val now = Calendar.getInstance()
val dialog = BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_date_format_title)).setSelectedValue(Preferences.dateFormat)
dialog.addItem(DateHelper.getDefaultDateText(requireContext(), now), "")
if (Preferences.dateFormat != "") {
dialog.addItem(DateHelper.getDateText(requireContext(), now), Preferences.dateFormat)
}
dialog.addItem(getString(R.string.custom_date_format), "-")
dialog.addOnSelectItemListener { value ->
if (value == "-") {
startActivity(Intent(requireActivity(), CustomDateActivity::class.java))
} else {
Preferences.dateFormat = value
}
}.show()
}
}
action_event_app.setOnClickListener { action_event_app.setOnClickListener {
startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java), RequestCode.EVENT_APP_REQUEST_CODE.code) startActivityForResult(Intent(requireContext(), ChooseApplicationActivity::class.java), RequestCode.EVENT_APP_REQUEST_CODE.code)
} }
@ -262,10 +311,10 @@ class CalendarSettingsFragment : Fragment() {
} }
private fun checkReadEventsPermission(showEvents: Boolean = Preferences.showEvents) { private fun checkReadEventsPermission(showEvents: Boolean = Preferences.showEvents) {
if (requireActivity().checkCallingOrSelfPermission(Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) { if (requireActivity().checkGrantedPermission(Manifest.permission.READ_CALENDAR)) {
show_events_label.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible) show_events_label.text = if (showEvents) getString(R.string.show_events_visible) else getString(R.string.show_events_not_visible)
read_calendar_permission_alert_icon.isVisible = false read_calendar_permission_alert_icon.isVisible = false
CalendarUtil.updateEventList(requireContext()) CalendarHelper.updateEventList(requireContext())
} else { } else {
show_events_label.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible) show_events_label.text = if (showEvents) getString(R.string.description_permission_calendar) else getString(R.string.show_events_not_visible)
read_calendar_permission_alert_icon.isVisible = showEvents read_calendar_permission_alert_icon.isVisible = showEvents

View File

@ -3,10 +3,10 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
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 androidx.core.view.isVisible
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
@ -15,7 +15,6 @@ import androidx.lifecycle.lifecycleScope
import com.chibatching.kotpref.bulk import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentCalendarSettingsBinding
import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
@ -23,8 +22,6 @@ import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
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.utils.Util
import com.tommasoberlose.anotherwidget.utils.toast
import kotlinx.android.synthetic.main.fragment_clock_settings.* import kotlinx.android.synthetic.main.fragment_clock_settings.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -67,6 +64,11 @@ class ClockSettingsFragment : Fragment() {
binding: FragmentClockSettingsBinding, binding: FragmentClockSettingsBinding,
viewModel: MainViewModel viewModel: MainViewModel
) { ) {
viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer {
large_clock_warning.isVisible = it
small_clock_warning.isVisible = !it
})
viewModel.showClock.observe(viewLifecycleOwner, Observer { viewModel.showClock.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_clock_label.text = show_clock_label.text =
@ -96,12 +98,16 @@ class ClockSettingsFragment : Fragment() {
} }
private fun setupListener() { private fun setupListener() {
action_hide_large_clock_warning.setOnClickListener {
Preferences.showBigClockWarning = false
}
action_show_clock.setOnClickListener { action_show_clock.setOnClickListener {
Preferences.showClock = !Preferences.showClock Preferences.showClock = !Preferences.showClock
} }
action_clock_text_size.setOnClickListener { action_clock_text_size.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext()).selectResource(Preferences.clockTextSize) val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.settings_clock_text_size_title)).setSelectedValue(Preferences.clockTextSize)
(46 downTo 28).filter { it % 2 == 0 }.forEach { (46 downTo 28).filter { it % 2 == 0 }.forEach {
dialog.addItem("${it}sp", it.toFloat()) dialog.addItem("${it}sp", it.toFloat())
} }
@ -111,7 +117,7 @@ class ClockSettingsFragment : Fragment() {
} }
action_show_next_alarm.setOnClickListener { action_show_next_alarm.setOnClickListener {
BottomSheetMenu<Boolean>(requireContext()).selectResource(Preferences.showNextAlarm) BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_next_alarm_title)).setSelectedValue(Preferences.showNextAlarm)
.addItem(getString(R.string.settings_visible), true) .addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false) .addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value -> .addOnSelectItemListener { value ->

View File

@ -13,20 +13,17 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetColorPicker
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding import com.tommasoberlose.anotherwidget.databinding.FragmentGeneralSettingsBinding
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.global.RequestCode import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
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.utils.Util
import com.tommasoberlose.anotherwidget.utils.toPixel
import com.tommasoberlose.anotherwidget.utils.toast
import dev.sasikanth.colorsheet.ColorSheet
import kotlinx.android.synthetic.main.fragment_general_settings.* import kotlinx.android.synthetic.main.fragment_general_settings.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.util.*
class GeneralSettingsFragment : Fragment() { class GeneralSettingsFragment : Fragment() {
@ -50,7 +47,7 @@ class GeneralSettingsFragment : Fragment() {
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java) viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
val binding = DataBindingUtil.inflate<FragmentGeneralSettingsBinding>(inflater, R.layout.fragment_general_settings, container, false) val binding = DataBindingUtil.inflate<FragmentGeneralSettingsBinding>(inflater, R.layout.fragment_general_settings, container, false)
subscribeUi(binding, viewModel) subscribeUi(viewModel)
binding.lifecycleOwner = this binding.lifecycleOwner = this
binding.viewModel = viewModel binding.viewModel = viewModel
@ -66,7 +63,6 @@ class GeneralSettingsFragment : Fragment() {
private fun subscribeUi( private fun subscribeUi(
binding: FragmentGeneralSettingsBinding,
viewModel: MainViewModel viewModel: MainViewModel
) { ) {
@ -95,13 +91,13 @@ class GeneralSettingsFragment : Fragment() {
viewModel.textShadow.observe(viewLifecycleOwner, Observer { viewModel.textShadow.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
text_shadow_label.text = getString(Util.getTextShadowString(it)) text_shadow_label.text = getString(SettingsStringHelper.getTextShadowString(it))
} }
}) })
viewModel.customFont.observe(viewLifecycleOwner, Observer { viewModel.customFont.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
custom_font_label.text = getString(Util.getCustomFontLabel(it)) custom_font_label.text = getString(SettingsStringHelper.getCustomFontLabel(it))
} }
}) })
} }
@ -117,7 +113,7 @@ class GeneralSettingsFragment : Fragment() {
private fun setupListener() { private fun setupListener() {
action_main_text_size.setOnClickListener { action_main_text_size.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext()).selectResource(Preferences.textMainSize) val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_main_text_size)).setSelectedValue(Preferences.textMainSize)
(32 downTo 20).filter { it % 2 == 0 }.forEach { (32 downTo 20).filter { it % 2 == 0 }.forEach {
dialog.addItem("${it}sp", it.toFloat()) dialog.addItem("${it}sp", it.toFloat())
} }
@ -127,7 +123,7 @@ class GeneralSettingsFragment : Fragment() {
} }
action_second_text_size.setOnClickListener { action_second_text_size.setOnClickListener {
val dialog = BottomSheetMenu<Float>(requireContext()).selectResource(Preferences.textSecondSize) val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.title_second_text_size)).setSelectedValue(Preferences.textSecondSize)
(24 downTo 12).filter { it % 2 == 0 }.forEach { (24 downTo 12).filter { it % 2 == 0 }.forEach {
dialog.addItem("${it}sp", it.toFloat()) dialog.addItem("${it}sp", it.toFloat())
} }
@ -143,21 +139,21 @@ class GeneralSettingsFragment : Fragment() {
Preferences.textGlobalColor = "#FFFFFF" Preferences.textGlobalColor = "#FFFFFF"
Color.parseColor(Preferences.textGlobalColor) Color.parseColor(Preferences.textGlobalColor)
} }
ColorSheet() BottomSheetColorPicker(requireContext(),
.cornerRadius(16.toPixel(requireContext()))
.colorPicker(
colors = requireActivity().resources.getIntArray(R.array.grey), colors = requireActivity().resources.getIntArray(R.array.grey),
selectedColor = textColor, header = getString(R.string.settings_font_color_title),
listener = { color -> selected = textColor,
Preferences.textGlobalColor = "#" + Integer.toHexString(color) onColorSelected = { color: Int ->
}) val colorString = Integer.toHexString(color)
.show(requireActivity().supportFragmentManager) Preferences.textGlobalColor = "#" + if (colorString.length > 6) colorString.substring(2) else colorString
}
).show()
} }
action_text_shadow.setOnClickListener { action_text_shadow.setOnClickListener {
val dialog = BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.textShadow) val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.title_text_shadow)).setSelectedValue(Preferences.textShadow)
(2 downTo 0).forEach { (2 downTo 0).forEach {
dialog.addItem(getString(Util.getTextShadowString(it)), it) dialog.addItem(getString(SettingsStringHelper.getTextShadowString(it)), it)
} }
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
Preferences.textShadow = value Preferences.textShadow = value
@ -165,9 +161,9 @@ class GeneralSettingsFragment : Fragment() {
} }
action_custom_font.setOnClickListener { action_custom_font.setOnClickListener {
val dialog = BottomSheetMenu<Int>(requireContext()).selectResource(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(Util.getCustomFontLabel(it)), it) dialog.addItem(getString(SettingsStringHelper.getCustomFontLabel(it)), it)
} }
dialog.addOnSelectItemListener { value -> dialog.addOnSelectItemListener { value ->
Preferences.customFont = value Preferences.customFont = value

View File

@ -3,7 +3,6 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.Manifest import android.Manifest
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -26,13 +25,15 @@ import com.tommasoberlose.anotherwidget.databinding.FragmentWeatherSettingsBindi
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.global.RequestCode import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.activities.WeatherProviderActivity import com.tommasoberlose.anotherwidget.ui.activities.WeatherProviderActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.utils.Util import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import kotlinx.android.synthetic.main.fragment_weather_settings.* import kotlinx.android.synthetic.main.fragment_weather_settings.*
import kotlinx.android.synthetic.main.fragment_weather_settings.scrollView import kotlinx.android.synthetic.main.fragment_weather_settings.scrollView
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -76,6 +77,10 @@ class WeatherSettingsFragment : Fragment() {
binding: FragmentWeatherSettingsBinding, binding: FragmentWeatherSettingsBinding,
viewModel: MainViewModel viewModel: MainViewModel
) { ) {
viewModel.showWeatherWarning.observe(viewLifecycleOwner, Observer {
weather_warning.isVisible = it
})
viewModel.showWeather.observe(viewLifecycleOwner, Observer { viewModel.showWeather.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
show_weather_label.text = show_weather_label.text =
@ -113,7 +118,7 @@ class WeatherSettingsFragment : Fragment() {
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer { viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer {
maintainScrollPosition { maintainScrollPosition {
label_weather_refresh_period.text = getString(Util.getRefreshPeriodString(it)) label_weather_refresh_period.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
} }
checkLocationPermission() checkLocationPermission()
}) })
@ -127,7 +132,7 @@ class WeatherSettingsFragment : Fragment() {
} }
private fun checkLocationPermission() { private fun checkLocationPermission() {
if (requireActivity().checkCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (requireActivity().checkGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
location_permission_alert_icon.isVisible = false location_permission_alert_icon.isVisible = false
WeatherReceiver.setUpdates(requireContext()) WeatherReceiver.setUpdates(requireContext())
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") { } else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
@ -139,6 +144,9 @@ class WeatherSettingsFragment : Fragment() {
} }
private fun setupListener() { private fun setupListener() {
action_hide_weather_warning.setOnClickListener {
Preferences.showWeatherWarning = false
}
action_show_weather.setOnClickListener { action_show_weather.setOnClickListener {
Preferences.showWeather = !Preferences.showWeather Preferences.showWeather = !Preferences.showWeather
@ -164,7 +172,7 @@ class WeatherSettingsFragment : Fragment() {
action_change_unit.setOnClickListener { action_change_unit.setOnClickListener {
if (Preferences.showWeather) { if (Preferences.showWeather) {
BottomSheetMenu<String>(requireContext()).selectResource(Preferences.weatherTempUnit) BottomSheetMenu<String>(requireContext(), header = getString(R.string.settings_unit_title)).setSelectedValue(Preferences.weatherTempUnit)
.addItem(getString(R.string.fahrenheit), "F") .addItem(getString(R.string.fahrenheit), "F")
.addItem(getString(R.string.celsius), "C") .addItem(getString(R.string.celsius), "C")
.addOnSelectItemListener { value -> .addOnSelectItemListener { value ->
@ -176,9 +184,9 @@ class WeatherSettingsFragment : Fragment() {
action_weather_refresh_period.setOnClickListener { action_weather_refresh_period.setOnClickListener {
if (Preferences.showWeather) { if (Preferences.showWeather) {
val dialog = val dialog =
BottomSheetMenu<Int>(requireContext()).selectResource(Preferences.weatherRefreshPeriod) BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_weather_refresh_period_title)).setSelectedValue(Preferences.weatherRefreshPeriod)
(5 downTo 0).forEach { (5 downTo 0).forEach {
dialog.addItem(getString(Util.getRefreshPeriodString(it)), it) dialog.addItem(getString(SettingsStringHelper.getRefreshPeriodString(it)), it)
} }
dialog dialog
.addOnSelectItemListener { value -> .addOnSelectItemListener { value ->
@ -202,13 +210,14 @@ class WeatherSettingsFragment : Fragment() {
when (requestCode) { when (requestCode) {
Constants.RESULT_CODE_CUSTOM_LOCATION -> { Constants.RESULT_CODE_CUSTOM_LOCATION -> {
WeatherReceiver.setUpdates(requireContext()) WeatherReceiver.setUpdates(requireContext())
checkLocationPermission()
} }
RequestCode.WEATHER_APP_REQUEST_CODE.code -> { RequestCode.WEATHER_APP_REQUEST_CODE.code -> {
Preferences.bulk { Preferences.bulk {
weatherAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_weather_app) weatherAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_weather_app)
weatherAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: "" weatherAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
} }
Util.updateWidget(requireContext()) MainWidget.updateWidget(requireContext())
} }
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> { RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
WeatherReceiver.setOneTimeUpdate(requireContext()) WeatherReceiver.setOneTimeUpdate(requireContext())

View File

@ -1,17 +1,21 @@
package com.tommasoberlose.anotherwidget.ui.viewmodels package com.tommasoberlose.anotherwidget.ui.viewmodels
import android.app.Application import android.app.Application
import android.content.Intent
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import androidx.databinding.ObservableField import android.content.pm.ResolveInfo
import androidx.lifecycle.* import androidx.lifecycle.AndroidViewModel
import kotlinx.coroutines.Dispatchers import androidx.lifecycle.LiveData
import kotlinx.coroutines.launch import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.withContext import androidx.lifecycle.liveData
class ChooseApplicationViewModel(application: Application) : AndroidViewModel(application) { class ChooseApplicationViewModel(application: Application) : AndroidViewModel(application) {
val appList: LiveData<List<ApplicationInfo>> = liveData { val appList: LiveData<List<ResolveInfo>> = liveData {
val app = application.packageManager.getInstalledApplications(0) val mainIntent = Intent(Intent.ACTION_MAIN, null).apply {
addCategory(Intent.CATEGORY_LAUNCHER)
}
val app = application.packageManager.queryIntentActivities( mainIntent, 0)
emit(app) emit(app)
} }
val searchInput: MutableLiveData<String> = MutableLiveData("") val searchInput: MutableLiveData<String> = MutableLiveData("")

View File

@ -0,0 +1,10 @@
package com.tommasoberlose.anotherwidget.ui.viewmodels
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.tommasoberlose.anotherwidget.global.Preferences
class CustomDateViewModel(application: Application) : AndroidViewModel(application) {
val dateInput: MutableLiveData<String> = MutableLiveData(if (Preferences.dateFormat == "") "EEEE, MMM dd" else Preferences.dateFormat)
}

View File

@ -26,7 +26,6 @@ class MainViewModel : ViewModel() {
val eventAppName = Preferences.asLiveData(Preferences::eventAppName) val eventAppName = Preferences.asLiveData(Preferences::eventAppName)
// Clock Settings // Clock Settings
val showClock = Preferences.asLiveData(Preferences::showClock) val showClock = Preferences.asLiveData(Preferences::showClock)
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize) val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
@ -35,6 +34,8 @@ class MainViewModel : ViewModel() {
val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm) val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm)
val dateFormat = Preferences.asLiveData(Preferences::dateFormat) val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
val showBigClockWarning = Preferences.asLiveData(Preferences::showBigClockWarning)
// Weather Settings // Weather Settings
val showWeather = Preferences.asLiveData(Preferences::showWeather) val showWeather = Preferences.asLiveData(Preferences::showWeather)
val weatherTempUnit = Preferences.asLiveData(Preferences::weatherTempUnit) val weatherTempUnit = Preferences.asLiveData(Preferences::weatherTempUnit)
@ -45,6 +46,8 @@ class MainViewModel : ViewModel() {
val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd) val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd)
val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning)
// Advanced Settings // Advanced Settings
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference) val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper) val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper)

View File

@ -4,10 +4,10 @@ import android.Manifest
import android.app.PendingIntent import android.app.PendingIntent
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Resources import android.content.res.Resources
import android.graphics.BitmapFactory
import android.graphics.Color import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Bundle import android.os.Bundle
@ -22,25 +22,27 @@ import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
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.global.Actions import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.*
import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver
import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.utils.CalendarUtil import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
import com.tommasoberlose.anotherwidget.utils.Util import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.WeatherUtil import com.tommasoberlose.anotherwidget.utils.convertSpToPixels
import com.tommasoberlose.anotherwidget.utils.getCapWordString
import com.tommasoberlose.anotherwidget.utils.toPixel import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.the_widget.view.* import kotlinx.android.synthetic.main.the_widget.view.*
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.min
class TheWidget : AppWidgetProvider() { class MainWidget : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
for (appWidgetId in appWidgetIds) { for (appWidgetId in appWidgetIds) {
@ -54,8 +56,14 @@ class TheWidget : AppWidgetProvider() {
} }
override fun onEnabled(context: Context) { override fun onEnabled(context: Context) {
CalendarUtil.updateEventList(context) CalendarHelper.updateEventList(context)
WeatherReceiver.setUpdates(context) WeatherReceiver.setUpdates(context)
if (Preferences.showEvents) {
CalendarHelper.setEventUpdatesAndroidN(context)
} else {
CalendarHelper.removeEventUpdatesAndroidN(context)
}
} }
override fun onDisabled(context: Context) { override fun onDisabled(context: Context) {
@ -65,27 +73,37 @@ class TheWidget : AppWidgetProvider() {
companion object { companion object {
fun updateWidget(context: Context) {
val widgetManager = AppWidgetManager.getInstance(context)
val widgetComponent = ComponentName(context, MainWidget::class.java)
val widgetIds = widgetManager.getAppWidgetIds(widgetComponent)
val update = Intent(context, MainWidget::class.java)
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds)
update.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
context.sendBroadcast(update)
}
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager,
appWidgetId: Int) { appWidgetId: Int) {
val displayMetrics = Resources.getSystem().displayMetrics val displayMetrics = Resources.getSystem().displayMetrics
var height = 110.toPixel(context) var height = 110.toPixel(context)
val width = displayMetrics.widthPixels val width = displayMetrics.widthPixels
if (Preferences.showClock) { if (Preferences.showClock) {
height += Util.convertSpToPixels(Preferences.clockTextSize, context).toInt() + 16.toPixel(context) height += Preferences.clockTextSize.convertSpToPixels(context).toInt() + 16.toPixel(context)
} }
if (Preferences.textMainSize > 30 && Preferences.textSecondSize > 22) { if (Preferences.textMainSize > 30 && Preferences.textSecondSize > 22) {
height += 24.toPixel(context) height += 24.toPixel(context)
} }
generateWidgetView(context, appWidgetId, appWidgetManager, width - 16.toPixel(context), height) generateWidgetView(context, appWidgetId, appWidgetManager, width - 16.toPixel(context))
} }
private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int, h: Int) { private fun generateWidgetView(context: Context, appWidgetId: Int, appWidgetManager: AppWidgetManager, w: Int) {
var views = RemoteViews(context.packageName, R.layout.the_widget_sans) var views = RemoteViews(context.packageName, R.layout.the_widget_sans)
val generatedView = generateWidgetView(context, w) val generatedView = generateWidgetView(context)
generatedView.measure(0, 0) generatedView.measure(0, 0)
views.setImageViewBitmap(R.id.bitmap_container, Util.getBitmapFromView(generatedView, w, generatedView.measuredHeight)) views.setImageViewBitmap(R.id.bitmap_container, BitmapHelper.getBitmapFromView(generatedView, w - 32.toPixel(context), generatedView.measuredHeight))
// Clock // Clock
views = updateClockView(context, views, appWidgetId) views = updateClockView(context, views, appWidgetId)
@ -98,29 +116,30 @@ class TheWidget : AppWidgetProvider() {
} }
private fun updateCalendarView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews { private fun updateCalendarView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews {
val eventRepository = EventRepository(context)
v.empty_date.measure(0, 0) v.empty_date.measure(0, 0)
views.setImageViewBitmap(R.id.empty_date_rect, Util.getBitmapFromView(v.empty_date)) views.setImageViewBitmap(R.id.empty_date_rect, BitmapHelper.getBitmapFromView(v.empty_date))
views.setViewVisibility(R.id.empty_layout_rect, View.VISIBLE) views.setViewVisibility(R.id.empty_layout_rect, View.VISIBLE)
views.setViewVisibility(R.id.calendar_layout_rect, View.GONE) views.setViewVisibility(R.id.calendar_layout_rect, View.GONE)
views.setViewVisibility(R.id.second_row_rect, View.GONE) views.setViewVisibility(R.id.second_row_rect, View.GONE)
val calPIntent = PendingIntent.getActivity(context, widgetID, Util.getCalendarIntent(context), 0) val calPIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getCalendarIntent(context), 0)
views.setOnClickPendingIntent(R.id.empty_date_rect, calPIntent) views.setOnClickPendingIntent(R.id.empty_date_rect, calPIntent)
val nextEvent = CalendarUtil.getNextEvent() val nextEvent = eventRepository.getNextEvent()
val nextAlarm = Util.getNextAlarm(context) val nextAlarm = AlarmHelper.getNextAlarm(context)
if (Preferences.showEvents && Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR) && nextEvent != null) { if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null) {
if (Preferences.showNextEvent && CalendarUtil.getEventsCount() > 1) { if (Preferences.showNextEvent && eventRepository.getEventsCount() > 1) {
v.action_next.measure(0, 0) v.action_next.measure(0, 0)
views.setImageViewBitmap(R.id.action_next_rect, Util.getBitmapFromView(v.action_next)) views.setImageViewBitmap(R.id.action_next_rect, BitmapHelper.getBitmapFromView(v.action_next))
views.setViewVisibility(R.id.action_next_rect, View.VISIBLE) views.setViewVisibility(R.id.action_next_rect, View.VISIBLE)
views.setOnClickPendingIntent(R.id.action_next_rect, PendingIntent.getBroadcast(context, widgetID, Intent(context, NewCalendarEventReceiver::class.java).apply { action = Actions.ACTION_GO_TO_NEXT_EVENT }, 0)) views.setOnClickPendingIntent(R.id.action_next_rect, PendingIntent.getBroadcast(context, widgetID, Intent(context, NewCalendarEventReceiver::class.java).apply { action = Actions.ACTION_GO_TO_NEXT_EVENT }, 0))
v.action_previous.measure(0, 0) v.action_previous.measure(0, 0)
views.setImageViewBitmap(R.id.action_previous_rect, Util.getBitmapFromView(v.action_previous)) views.setImageViewBitmap(R.id.action_previous_rect, BitmapHelper.getBitmapFromView(v.action_previous))
views.setViewVisibility(R.id.action_previous_rect, View.VISIBLE) views.setViewVisibility(R.id.action_previous_rect, View.VISIBLE)
views.setOnClickPendingIntent(R.id.action_previous_rect, PendingIntent.getBroadcast(context, widgetID, Intent(context, NewCalendarEventReceiver::class.java).apply { action = Actions.ACTION_GO_TO_PREVIOUS_EVENT }, 0)) views.setOnClickPendingIntent(R.id.action_previous_rect, PendingIntent.getBroadcast(context, widgetID, Intent(context, NewCalendarEventReceiver::class.java).apply { action = Actions.ACTION_GO_TO_PREVIOUS_EVENT }, 0))
} else { } else {
@ -128,44 +147,44 @@ class TheWidget : AppWidgetProvider() {
views.setViewVisibility(R.id.action_previous_rect, View.GONE) views.setViewVisibility(R.id.action_previous_rect, View.GONE)
} }
val pIntent = PendingIntent.getActivity(context, widgetID, Util.getEventIntent(context, nextEvent), 0) val pIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getEventIntent(context, nextEvent), 0)
views.setOnClickPendingIntent(R.id.next_event_rect, pIntent) views.setOnClickPendingIntent(R.id.next_event_rect, pIntent)
views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, pIntent) views.setOnClickPendingIntent(R.id.next_event_difference_time_rect, pIntent)
if (Preferences.showDiffTime && Calendar.getInstance().timeInMillis < nextEvent.startDate) { if (Preferences.showDiffTime && Calendar.getInstance().timeInMillis < (nextEvent.startDate - 1000 * 60 * 60)) {
v.next_event_difference_time.measure(0, 0) v.next_event_difference_time.measure(0, 0)
views.setImageViewBitmap(R.id.next_event_difference_time_rect, Util.getBitmapFromView(v.next_event_difference_time)) views.setImageViewBitmap(R.id.next_event_difference_time_rect, BitmapHelper.getBitmapFromView(v.next_event_difference_time))
views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE) views.setViewVisibility(R.id.next_event_difference_time_rect, View.VISIBLE)
} else { } else {
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE) views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
} }
if (nextEvent.address != "" && Preferences.secondRowInformation == 1) { if (nextEvent.address != "" && Preferences.secondRowInformation == 1) {
val mapIntent = PendingIntent.getActivity(context, widgetID, Util.getGoogleMapsIntentFromAddress(context, nextEvent.address), 0) val mapIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getGoogleMapsIntentFromAddress(context, nextEvent.address), 0)
views.setOnClickPendingIntent(R.id.second_row_rect, mapIntent) views.setOnClickPendingIntent(R.id.second_row_rect, mapIntent)
} else { } else {
views.setOnClickPendingIntent(R.id.next_event_rect, pIntent) views.setOnClickPendingIntent(R.id.next_event_rect, pIntent)
} }
v.next_event.measure(0, 0) v.next_event.measure(0, 0)
views.setImageViewBitmap(R.id.next_event_rect, Util.getBitmapFromView(v.next_event)) views.setImageViewBitmap(R.id.next_event_rect, BitmapHelper.getBitmapFromView(v.next_event))
v.second_row.measure(0, 0) v.second_row.measure(0, 0)
views.setImageViewBitmap(R.id.second_row_rect, Util.getBitmapFromView(v.second_row)) views.setImageViewBitmap(R.id.second_row_rect, BitmapHelper.getBitmapFromView(v.second_row))
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE) views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
views.setViewVisibility(R.id.empty_layout_rect, View.GONE) views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE) views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
} else if (Preferences.secondRowInformation == 2 && nextAlarm != "") { } else if (Preferences.showNextAlarm && nextAlarm != "") {
val clockIntent = PendingIntent.getActivity(context, widgetID, Util.getClockIntent(context), 0) val clockIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getClockIntent(context), 0)
views.setOnClickPendingIntent(R.id.second_row_rect, clockIntent) views.setOnClickPendingIntent(R.id.second_row_rect, clockIntent)
v.next_event.measure(0, 0) v.next_event.measure(0, 0)
views.setImageViewBitmap(R.id.next_event_rect, Util.getBitmapFromView(v.next_event)) views.setImageViewBitmap(R.id.next_event_rect, BitmapHelper.getBitmapFromView(v.next_event))
v.second_row.measure(0, 0) v.second_row.measure(0, 0)
views.setImageViewBitmap(R.id.second_row_rect, Util.getBitmapFromView(v.second_row)) views.setImageViewBitmap(R.id.second_row_rect, BitmapHelper.getBitmapFromView(v.second_row))
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE) views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
views.setViewVisibility(R.id.empty_layout_rect, View.GONE) views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
@ -189,10 +208,10 @@ class TheWidget : AppWidgetProvider() {
views.setOnClickPendingIntent(R.id.calendar_weather_rect, weatherPIntent) views.setOnClickPendingIntent(R.id.calendar_weather_rect, weatherPIntent)
v.weather.measure(0, 0) v.weather.measure(0, 0)
views.setImageViewBitmap(R.id.weather_rect, Util.getBitmapFromView(v.weather)) views.setImageViewBitmap(R.id.weather_rect, BitmapHelper.getBitmapFromView(v.weather))
v.calendar_weather.measure(0, 0) v.calendar_weather.measure(0, 0)
views.setImageViewBitmap(R.id.calendar_weather_rect, Util.getBitmapFromView(v.calendar_weather)) views.setImageViewBitmap(R.id.calendar_weather_rect, BitmapHelper.getBitmapFromView(v.calendar_weather))
} else { } else {
views.setViewVisibility(R.id.weather_rect, View.GONE) views.setViewVisibility(R.id.weather_rect, View.GONE)
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE) views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
@ -204,9 +223,9 @@ class TheWidget : AppWidgetProvider() {
if (!Preferences.showClock) { if (!Preferences.showClock) {
views.setViewVisibility(R.id.time, View.GONE) views.setViewVisibility(R.id.time, View.GONE)
} else { } else {
views.setTextColor(R.id.time, Util.getFontColor()) views.setTextColor(R.id.time, ColorHelper.getFontColor())
views.setTextViewTextSize(R.id.time, TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(context)) views.setTextViewTextSize(R.id.time, TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(context))
val clockPIntent = PendingIntent.getActivity(context, widgetID, Util.getClockIntent(context), 0) val clockPIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getClockIntent(context), 0)
views.setOnClickPendingIntent(R.id.time, clockPIntent) views.setOnClickPendingIntent(R.id.time, clockPIntent)
views.setViewVisibility(R.id.time, View.VISIBLE) views.setViewVisibility(R.id.time, View.VISIBLE)
} }
@ -214,29 +233,42 @@ class TheWidget : AppWidgetProvider() {
return views return views
} }
fun generateWidgetView(context: Context, maxWidth: Int): View {
// Generates the widget bitmap from the view
fun generateWidgetView(context: Context): View {
val eventRepository = EventRepository(context)
val v = View.inflate(context, R.layout.the_widget, null) val v = View.inflate(context, R.layout.the_widget, null)
val now = Calendar.getInstance() val now = Calendar.getInstance()
v.empty_layout.visibility = View.VISIBLE v.empty_layout.visibility = View.VISIBLE
v.calendar_layout.visibility = View.GONE v.calendar_layout.visibility = View.GONE
v.action_next.isVisible = false
v.action_previous.isVisible = false
val flags: Int = DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH v.empty_date.text = DateHelper.getDateText(context, now)
v.empty_date.text = Util.getCapWordString("${SimpleDateFormat("EEEE", Locale.getDefault()).format(now.time)}, ${DateUtils.formatDateTime(context, now.timeInMillis, flags)}")
val nextEvent = CalendarUtil.getNextEvent() val nextEvent = eventRepository.getNextEvent()
val nextAlarm = Util.getNextAlarm(context) val nextAlarm = AlarmHelper.getNextAlarm(context)
if (Preferences.showEvents && Util.checkGrantedPermission(context, 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 && CalendarUtil.getEventsCount() > 1 v.action_next.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.action_previous.isVisible = Preferences.showNextEvent && CalendarUtil.getEventsCount() > 1 v.action_previous.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.next_event.text = nextEvent.title v.next_event.text = nextEvent.title
if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) { if (Preferences.showDiffTime && now.timeInMillis < (nextEvent.startDate - 1000 * 60 * 60)) {
v.next_event_difference_time.text = Util.getDifferenceText(context, now.timeInMillis, nextEvent.startDate).toLowerCase(Locale.getDefault()) v.next_event_difference_time.text = if (!nextEvent.allDay) {
SettingsStringHelper.getDifferenceText(
context,
now.timeInMillis,
nextEvent.startDate
)
.toLowerCase(Locale.getDefault())
} else {
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 {
v.next_event_difference_time.visibility = View.GONE v.next_event_difference_time.visibility = View.GONE
@ -271,21 +303,22 @@ class TheWidget : AppWidgetProvider() {
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 {
v.next_event_date.text = Util.getCapWordString(DateUtils.formatDateTime(context, now.timeInMillis, flags)) val flags: Int = DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NO_YEAR or DateUtils.FORMAT_ABBREV_MONTH
v.next_event_date.text = DateUtils.formatDateTime(context, now.timeInMillis, flags).getCapWordString()
} }
} }
v.empty_layout.visibility = View.GONE v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE v.calendar_layout.visibility = View.VISIBLE
} else if (Preferences.secondRowInformation == 2 && nextAlarm != "") { } else if (Preferences.showNextAlarm && nextAlarm != "") {
v.second_row_icon.setImageDrawable( v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable( ContextCompat.getDrawable(
context, context,
R.drawable.round_alarm R.drawable.round_alarm
) )
) )
v.next_event.text = Util.getCapWordString("${SimpleDateFormat("EEEE", Locale.getDefault()).format(now.time)}, ${DateUtils.formatDateTime(context, now.timeInMillis, flags)}") v.next_event.text = DateHelper.getDateText(context, now)
v.next_event_date.text = Util.getNextAlarm(context) v.next_event_date.text = AlarmHelper.getNextAlarm(context)
v.empty_layout.visibility = View.GONE v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE v.calendar_layout.visibility = View.VISIBLE
} }
@ -293,11 +326,11 @@ class TheWidget : AppWidgetProvider() {
// Color // Color
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).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).forEach {
it.setTextColor(Util.getFontColor()) it.setTextColor(ColorHelper.getFontColor())
} }
listOf<ImageView>(v.second_row_icon, v.action_next, v.action_previous).forEach { listOf<ImageView>(v.second_row_icon, v.action_next, v.action_previous).forEach {
it.setColorFilter(Util.getFontColor()) it.setColorFilter(ColorHelper.getFontColor())
} }
// Text Size // Text Size
@ -318,8 +351,8 @@ class TheWidget : AppWidgetProvider() {
v.second_row_icon.scaleX = Preferences.textSecondSize / 18f v.second_row_icon.scaleX = Preferences.textSecondSize / 18f
v.second_row_icon.scaleY = Preferences.textSecondSize / 18f v.second_row_icon.scaleY = Preferences.textSecondSize / 18f
v.weather_icon.scaleX = Preferences.textSecondSize / 18f v.weather_icon.scaleX = Preferences.textSecondSize / 16f
v.weather_icon.scaleY = Preferences.textSecondSize / 18f v.weather_icon.scaleY = Preferences.textSecondSize / 16f
v.empty_weather_icon.scaleX = Preferences.textMainSize / 20f v.empty_weather_icon.scaleX = Preferences.textMainSize / 20f
v.empty_weather_icon.scaleY = Preferences.textMainSize / 20f v.empty_weather_icon.scaleY = Preferences.textMainSize / 20f
@ -374,8 +407,8 @@ class TheWidget : AppWidgetProvider() {
v.weather_icon.visibility = View.GONE v.weather_icon.visibility = View.GONE
v.empty_weather_icon.visibility = View.GONE v.empty_weather_icon.visibility = View.GONE
} else { } else {
v.weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon)) v.weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
v.empty_weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon)) v.empty_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
} }
@ -387,9 +420,6 @@ class TheWidget : AppWidgetProvider() {
v.calendar_weather.visibility = View.GONE v.calendar_weather.visibility = View.GONE
} }
// Apply max width
v.main_layout.layoutParams = RelativeLayout.LayoutParams(maxWidth, RelativeLayout.LayoutParams.WRAP_CONTENT)
return v return v
} }
} }

View File

@ -1,186 +0,0 @@
package com.tommasoberlose.anotherwidget.utils
import android.Manifest
import android.content.ContentUris
import android.content.Context
import android.provider.CalendarContract
import android.util.Log
import com.chibatching.kotpref.blockingBulk
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.components.events.Event
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import io.realm.Realm
import io.realm.RealmResults
import me.everything.providers.android.calendar.CalendarProvider
import java.util.*
import kotlin.Comparator
import kotlin.collections.ArrayList
/**
* Created by tommaso on 08/10/17.
*/
object CalendarUtil {
fun updateEventList(context: Context) {
if (Preferences.showEvents) {
val eventList = ArrayList<Event>()
val now = Calendar.getInstance()
val limit = Calendar.getInstance()
when (Preferences.showUntil) {
0 -> limit.add(Calendar.HOUR, 3)
1 -> limit.add(Calendar.HOUR, 6)
2 -> limit.add(Calendar.HOUR, 12)
3 -> limit.add(Calendar.DAY_OF_MONTH, 1)
4 -> limit.add(Calendar.DAY_OF_MONTH, 3)
5 -> limit.add(Calendar.DAY_OF_MONTH, 7)
6 -> limit.add(Calendar.MINUTE, 30)
7 -> limit.add(Calendar.HOUR, 1)
else -> limit.add(Calendar.HOUR, 6)
}
val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
ContentUris.appendId(builder, now.timeInMillis)
ContentUris.appendId(builder, limit.timeInMillis)
if (!Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)) {
resetNextEventData(context)
} else {
val provider = CalendarProvider(context)
val data = provider.getInstances(now.timeInMillis, limit.timeInMillis)
if (data != null) {
val instances = data.list
for (instance in instances) {
try {
val e = provider.getEvent(instance.eventId)
if (e != null && instance.begin <= limit.timeInMillis && (Preferences.calendarAllDay || !e.allDay) && !(Preferences.calendarFilter.contains(" " + e.calendarId + ",")) && (Preferences.showDeclinedEvents || e.selfAttendeeStatus.toInt() != CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED)) {
if (e.allDay) {
val start = Calendar.getInstance()
start.timeInMillis = instance.begin
val end = Calendar.getInstance()
end.timeInMillis = instance.end
instance.begin = start.timeInMillis - start.timeZone.getOffset(start.timeInMillis)
instance.end = end.timeInMillis - end.timeZone.getOffset(end.timeInMillis)
}
eventList.add(Event(instance.id, e.id, e.title ?: "", instance.begin, instance.end, e.calendarId.toInt(), e.allDay, e.eventLocation ?: ""))
}
} catch (ignored: Exception) {}
}
}
if (eventList.isEmpty()) {
resetNextEventData(context)
} else {
eventList.sortWith(Comparator { event: Event, event1: Event ->
if (event.allDay && event1.allDay) {
event.startDate.compareTo(event1.startDate)
} else if (event.allDay) {
1
} else if (event1.allDay) {
-1
} else {
event1.startDate.compareTo(event.startDate)
}
})
eventList.reverse()
saveEvents(eventList)
saveNextEventData(context, eventList[0])
}
}
} else {
resetNextEventData(context)
}
UpdatesReceiver.setUpdates(context)
Util.updateWidget(context)
}
fun getCalendarList(context: Context): List<me.everything.providers.android.calendar.Calendar> {
val calendarList = ArrayList<me.everything.providers.android.calendar.Calendar>()
if (!Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)) {
return calendarList
}
val provider = CalendarProvider(context)
val data = provider.calendars
return if (data != null) {
data.list
} else {
calendarList
}
}
private fun saveEvents(eventList: ArrayList<Event>) {
Realm.getDefaultInstance().executeTransactionAsync { realm ->
realm.where(Event::class.java).findAll().deleteAllFromRealm()
realm.copyToRealm(eventList)
}
}
private fun resetNextEventData(context: Context) {
Realm.getDefaultInstance().executeTransactionAsync {
it.where(Event::class.java).findAll().deleteAllFromRealm()
}
Preferences.bulk {
remove(Preferences::nextEventId)
remove(Preferences::nextEventName)
remove(Preferences::nextEventStartDate)
remove(Preferences::nextEventAllDay)
remove(Preferences::nextEventLocation)
remove(Preferences::nextEventEndDate)
remove(Preferences::nextEventCalendarId)
}
Util.updateWidget(context)
}
private fun saveNextEventData(context: Context, event: Event) {
Preferences.nextEventId = event.id
Util.updateWidget(context)
}
fun getNextEvent(): Event? {
val realm = Realm.getDefaultInstance()
return realm.where(Event::class.java).equalTo("id", Preferences.nextEventId).findFirst() ?: realm.where(Event::class.java).findFirst()
}
fun goToNextEvent(context: Context) {
val eventList = Realm.getDefaultInstance().where(Event::class.java).findAll()
if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
if (index > -1 && index < eventList.size - 1) {
Preferences.nextEventId = eventList[index + 1]!!.id
} else {
Preferences.nextEventId = eventList.first()!!.id
}
} else {
resetNextEventData(context)
}
UpdatesReceiver.setUpdates(context)
Util.updateWidget(context)
}
fun goToPreviousEvent(context: Context) {
val eventList = Realm.getDefaultInstance().where(Event::class.java).findAll()
if (eventList.isNotEmpty()) {
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
if (index > 0) {
Preferences.nextEventId = eventList[index - 1]!!.id
} else {
Preferences.nextEventId = eventList.last()!!.id
}
} else {
resetNextEventData(context)
}
UpdatesReceiver.setUpdates(context)
Util.updateWidget(context)
}
fun getEvents(): RealmResults<Event> = Realm.getDefaultInstance().where(Event::class.java).findAll()
fun getEventsCount(): Int = Realm.getDefaultInstance().where(Event::class.java).findAll().size
}

View File

@ -8,6 +8,7 @@ import android.widget.Toast
import android.animation.Animator import android.animation.Animator
import android.animation.AnimatorListenerAdapter import android.animation.AnimatorListenerAdapter
import android.app.Activity import android.app.Activity
import android.app.WallpaperManager
import android.content.* import android.content.*
import android.net.Uri import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
@ -18,8 +19,15 @@ import android.util.Patterns
import java.security.NoSuchAlgorithmException import java.security.NoSuchAlgorithmException
import kotlin.math.max import kotlin.math.max
import android.content.Intent import android.content.Intent
import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.util.DisplayMetrics
import android.util.TypedValue import android.util.TypedValue
import android.view.animation.Animation
import android.view.animation.Transformation
import android.widget.LinearLayout
import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.R
import java.util.*
fun PackageManager.missingSystemFeature(name: String): Boolean = !hasSystemFeature(name) fun PackageManager.missingSystemFeature(name: String): Boolean = !hasSystemFeature(name)
@ -33,10 +41,11 @@ fun Context.toast(message: String) {
fun Int.toPixel(context: Context): Int = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics).toInt() fun Int.toPixel(context: Context): Int = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics).toInt()
fun Float.toPixel(context: Context): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, context.resources.displayMetrics) fun Float.toPixel(context: Context): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, context.resources.displayMetrics)
fun View.reveal(initialX: Int, initialY: Int) { fun View.reveal(initialX: Int? = null, initialY: Int? = null) {
when (visibility) { when (visibility) {
View.VISIBLE -> { View.VISIBLE -> {
val anim = ViewAnimationUtils.createCircularReveal(this, initialX, initialY, max(width.toFloat(), height.toFloat()), 0f) val anim = ViewAnimationUtils.createCircularReveal(this, initialX ?: this.measuredWidth / 2, initialY ?: this.measuredHeight / 2, max(width.toFloat(), height.toFloat()), 0f)
.apply { .apply {
duration = 200 duration = 200
} }
@ -48,7 +57,7 @@ fun View.reveal(initialX: Int, initialY: Int) {
}) })
anim.start() anim.start()
} else -> { } else -> {
val anim = ViewAnimationUtils.createCircularReveal(this, initialX, initialY, 0f, max(width.toFloat(), height.toFloat())) val anim = ViewAnimationUtils.createCircularReveal(this, initialX ?: this.measuredWidth / 2, initialY ?: this.measuredHeight / 2, 0f, max(width.toFloat(), height.toFloat()))
.apply { .apply {
duration = 200 duration = 200
} }
@ -58,6 +67,58 @@ fun View.reveal(initialX: Int, initialY: Int) {
} }
} }
fun View.expand() {
if (visibility != View.VISIBLE) {
measure(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
val targetHeight = measuredHeight
layoutParams.height = 0
visibility = View.VISIBLE
val a = object : Animation() {
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
layoutParams.height = if (interpolatedTime == 1f)
LinearLayout.LayoutParams.WRAP_CONTENT
else
(targetHeight * interpolatedTime).toInt()
translationY = 0f
requestLayout()
}
override fun willChangeBounds(): Boolean {
return true
}
}
a.duration = 500L
startAnimation(a)
}
}
fun View.collapse() {
if (visibility != View.GONE) {
val initialHeight = measuredHeight
val a = object : Animation() {
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
if (interpolatedTime == 1f) {
visibility = View.GONE
} else {
layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
requestLayout()
}
}
override fun willChangeBounds(): Boolean {
return true
}
}
a.duration = 500L //(initialHeight / v.context.resources.displayMetrics.density).toLong()
startAnimation(a)
}
}
fun Context.openURI(url: String) { fun Context.openURI(url: String) {
try { try {
val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder() val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder()
@ -117,14 +178,38 @@ fun Activity.isDarkTheme(): Boolean {
fun Activity.isNotificationAccessGranted(): Boolean = Settings.Secure.getString(this.contentResolver,"enabled_notification_listeners").contains(this.packageName) fun Activity.isNotificationAccessGranted(): Boolean = Settings.Secure.getString(this.contentResolver,"enabled_notification_listeners").contains(this.packageName)
//fun Activity.sendEmailTo(email: String) { fun Float.convertDpToPixel(context: Context): Float {
// val i = Intent(Intent.ACTION_VIEW).apply { val resources: Resources = context.resources
// data = Uri.parse("mailto:$email") val metrics: DisplayMetrics = resources.displayMetrics
// } val px: Float = this * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)
// try { return px
// startActivity(Intent.createChooser(i, getString(R.string.settings_title_feedback))) }
// } catch (ex: java.lang.Exception) {
// toast(getString(R.string.generic_error)) fun Float.convertSpToPixels(context: Context): Float {
// } return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this, context.resources.displayMetrics)
// }
//}
fun Context.checkGrantedPermission(permission: String): Boolean {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}
fun Context.getCurrentWallpaper(): Drawable? = try {
WallpaperManager.getInstance(this).drawable
} catch (e: Exception) {
null
}
fun String.getCapWordString(): String {
return try {
val ar = this.split(" ")
var newText = ""
for (t: String in ar) {
newText += " "
newText += t.substring(0, 1).toUpperCase(Locale.getDefault())
newText += t.substring(1)
}
newText.substring(1)
} catch (e: Exception) {
this
}
}

View File

@ -1,521 +0,0 @@
package com.tommasoberlose.anotherwidget.utils
import android.app.*
import android.appwidget.AppWidgetManager
import android.content.*
import android.content.pm.PackageManager
import android.content.res.Resources
import android.graphics.*
import android.graphics.drawable.Drawable
import android.net.Uri
import android.util.DisplayMetrics
import com.tommasoberlose.anotherwidget.R
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.util.TypedValue
import android.content.Intent
import android.content.ComponentName
import android.provider.AlarmClock
import android.provider.CalendarContract
import android.text.format.DateFormat
import android.text.format.DateUtils
import android.util.Log
import android.view.View
import android.view.animation.Animation
import android.view.animation.Transformation
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import com.tommasoberlose.anotherwidget.components.events.Event
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.ui.widgets.TheWidget
import org.joda.time.DateTime
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
/**
* Created by tommaso on 05/10/17.
*/
object Util {
fun checkGrantedPermission(context: Context, permission: String): Boolean {
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
}
fun updateWidget(context: Context) {
val widgetManager = AppWidgetManager.getInstance(context)
val widgetComponent = ComponentName(context, TheWidget::class.java)
val widgetIds = widgetManager.getAppWidgetIds(widgetComponent)
val update = Intent(context, TheWidget::class.java)
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds)
update.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
context.sendBroadcast(update)
}
fun showWeatherErrorNotification(context: Context) {
TODO("weather notification")
// val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
// val SP = PreferenceManager.getDefaultSharedPreferences(context)
//
// if (SP.getBoolean(Constants.PREF_SHOW_GPS_NOTIFICATION, true) && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) && SP.getInt(Constants.PREF_WEATHER_PROVIDER, Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) == Constants.WEATHER_PROVIDER_GOOGLE_AWARENESS) {
// val settingsIntent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
// val pi: PendingIntent = PendingIntent.getActivity(context, 50, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT)
//
// val providerIntent2 = Intent(context, MainActivity::class.java)
// providerIntent2.flags = Intent.FLAG_ACTIVITY_NEW_TASK
// providerIntent2.putExtra(Constants.ACTION_EXTRA_OPEN_WEATHER_PROVIDER, true)
// val pi2: PendingIntent = PendingIntent.getActivity(context, 51, providerIntent2, PendingIntent.FLAG_UPDATE_CURRENT)
//
// val providerIntentDisable = Intent(context, MainActivity::class.java)
// providerIntentDisable.flags = Intent.FLAG_ACTIVITY_NEW_TASK
// providerIntentDisable.putExtra(Constants.ACTION_EXTRA_DISABLE_GPS_NOTIFICATION, true)
// val piDisable: PendingIntent = PendingIntent.getActivity(context, 52, providerIntentDisable, PendingIntent.FLAG_UPDATE_CURRENT)
//
// val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Error")
// .setSmallIcon(R.drawable.ic_stat_name)
// .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
// .setContentTitle(context.getString(R.string.notification_gps_title))
// .setContentText(context.getString(R.string.notification_gps_subtitle))
// .addAction(R.drawable.ic_action_sync, context.getString(R.string.change_provider), pi2)
// .addAction(R.drawable.ic_action_settings, context.getString(R.string.disable_notification), piDisable)
// .setContentIntent(pi)
//
// mNotificationManager.notify(10, mBuilder.build());
// } else {
// mNotificationManager.cancel(10)
// }
}
fun getGoogleMapsIntentFromAddress(context: Context, address:String): Intent {
val gmmIntentUri: Uri = Uri.parse("geo:0,0?q=$address")
val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
mapIntent.`package` = "com.google.android.apps.maps"
return if (mapIntent.resolveActivity(context.packageManager) != null) {
mapIntent
} else {
val map = "http://maps.google.co.in/maps?q=$address"
val i = Intent(Intent.ACTION_VIEW, Uri.parse(map));
i
}
}
fun getCurrentWallpaper(context: Context): Drawable? = try {
WallpaperManager.getInstance(context).drawable
} catch (e: Exception) {
// BitmapDrawable(context.resources, getResizedBitmap(BitmapFactory.decodeResource(context.resources, R.drawable.pixel_2_wallpaper), 800))
null
}
fun getBitmapFromView(view: View): Bitmap {
//Define a bitmap with the same size as the view
val measuredWidth = View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.UNSPECIFIED)
val measuredHeight = View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.UNSPECIFIED)
view.measure(measuredWidth, measuredHeight)
view.layout(0,0, measuredWidth, measuredHeight)
val returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
//Bind a canvas to it
val canvas = Canvas(returnedBitmap)
// draw the view on the canvas
view.draw(canvas)
//return the bitmap
return returnedBitmap
}
fun getBitmapFromView(view: View, w: Int, h: Int): Bitmap {
//Define a bitmap with the same size as the view
val measuredWidth = View.MeasureSpec.makeMeasureSpec(w, View.MeasureSpec.EXACTLY)
val measuredHeight = View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.EXACTLY)
view.measure(measuredWidth, measuredHeight)
view.layout(0,0, measuredWidth, measuredHeight)
val returnedBitmap = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight, Bitmap.Config.ARGB_8888)
//Bind a canvas to it
val canvas = Canvas(returnedBitmap)
// draw the view on the canvas
view.draw(canvas)
//return the bitmap
return returnedBitmap
}
fun convertDpToPixel(dp: Float, context: Context): Float {
val resources: Resources = context.resources
val metrics: DisplayMetrics = resources.displayMetrics
val px: Float = dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)
return px
}
fun convertSpToPixels(sp: Float, context: Context): Float {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.resources.displayMetrics)
}
fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap {
var width = image.width
var height = image.height
val bitmapRatio = width.toFloat() / height.toFloat()
if (bitmapRatio > 1) {
width = maxSize
height = (width / bitmapRatio).toInt()
} else {
height = maxSize
width = (height * bitmapRatio).toInt()
}
return Bitmap.createScaledBitmap(image, width, height, true)
}
fun getRefreshPeriodString(period: Int): Int {
return when (period) {
0 -> R.string.settings_weather_refresh_period_subtitle_0
1 -> R.string.settings_weather_refresh_period_subtitle_1
2 -> R.string.settings_weather_refresh_period_subtitle_2
3 -> R.string.settings_weather_refresh_period_subtitle_3
4 -> R.string.settings_weather_refresh_period_subtitle_4
5 -> R.string.settings_weather_refresh_period_subtitle_5
else -> R.string.settings_weather_refresh_period_subtitle_0
}
}
fun getShowUntilString(period: Int): Int {
return when (period) {
0 -> R.string.settings_show_until_subtitle_0
1 -> R.string.settings_show_until_subtitle_1
2 -> R.string.settings_show_until_subtitle_2
3 -> R.string.settings_show_until_subtitle_3
4 -> R.string.settings_show_until_subtitle_4
5 -> R.string.settings_show_until_subtitle_5
6 -> R.string.settings_show_until_subtitle_6
7 -> R.string.settings_show_until_subtitle_7
else -> R.string.settings_show_until_subtitle_1
}
}
fun getSecondRowInfoString(info: Int): Int {
return when (info) {
0 -> R.string.settings_second_row_info_subtitle_0
1 -> R.string.settings_second_row_info_subtitle_1
2 -> R.string.settings_second_row_info_subtitle_2
else -> R.string.settings_second_row_info_subtitle_0
}
}
fun getTextShadowString(shadow: Int): Int {
return when (shadow) {
0 -> R.string.settings_text_shadow_subtitle_none
1 -> R.string.settings_text_shadow_subtitle_low
2 -> R.string.settings_text_shadow_subtitle_high
else -> R.string.settings_text_shadow_subtitle_low
}
}
fun getCustomFontLabel(shadow: Int): Int {
return when (shadow) {
0 -> R.string.custom_font_subtitle_0
1 -> R.string.custom_font_subtitle_1
else -> R.string.custom_font_subtitle_1
}
}
fun getCalendarIntent(context: Context): Intent {
return when (Preferences.calendarAppPackage) {
"" -> {
Intent(Intent.ACTION_MAIN).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addCategory(Intent.CATEGORY_APP_CALENDAR)
}
}
"_" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.calendarAppPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
} catch (e: Exception) {
e.printStackTrace()
Intent(Intent.ACTION_MAIN).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
addCategory(Intent.CATEGORY_APP_CALENDAR)
}
}
}
}
}
fun getWeatherIntent(context: Context): Intent {
return when (Preferences.weatherAppPackage) {
"" -> {
Intent(Intent.ACTION_VIEW).apply {
addCategory(Intent.CATEGORY_DEFAULT)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
data = Uri.parse("dynact://velour/weather/ProxyActivity")
component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
}
}
"_" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.weatherAppPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
} catch (e: Exception) {
Intent(Intent.ACTION_VIEW).apply {
addCategory(Intent.CATEGORY_DEFAULT)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
data = Uri.parse("dynact://velour/weather/ProxyActivity")
component = ComponentName("com.google.android.googlequicksearchbox", "com.google.android.apps.gsa.velour.DynamicActivityTrampoline")
}
}
}
}
}
fun getEventIntent(context: Context, e: Event): Intent {
return when (Preferences.eventAppPackage) {
"" -> {
val uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, e.eventID)
Intent(Intent.ACTION_VIEW).apply {
data = uri
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra("beginTime", e.startDate)
putExtra("endTime", e.endDate)
}
}
"_" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.eventAppPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
} catch (ex: Exception) {
val uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, e.id)
Intent(Intent.ACTION_VIEW).apply {
data = uri
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra("beginTime", e.startDate)
putExtra("endTime", e.endDate)
}
}
}
}
}
fun getClockIntent(context: Context): Intent {
return when (Preferences.clockAppPackage) {
"" -> {
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
}
"_" -> {
Intent()
}
else -> {
val pm: PackageManager = context.packageManager
try {
pm.getLaunchIntentForPackage(Preferences.clockAppPackage)!!.apply {
addCategory(Intent.CATEGORY_LAUNCHER)
}
} catch (e: Exception) {
Intent(AlarmClock.ACTION_SHOW_ALARMS).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
}
}
}
}
fun getCapWordString(text: String): String {
return try {
val ar = text.split(" ")
var newText = ""
for (t: String in ar) {
newText += " "
newText += t.substring(0, 1).toUpperCase(Locale.getDefault())
newText += t.substring(1)
}
newText.substring(1)
} catch (e: Exception) {
text
}
}
fun showLocationNotification(context: Context, show: Boolean) {
TODO("Show location notification")
// val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
//
// if (show) {
// val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Config")
// .setSmallIcon(R.drawable.ic_stat_name)
// .setPriority(Notification.PRIORITY_MIN)
// .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
// .setContentTitle(context.getString(R.string.notification_gps_title))
// .setContentText(context.getString(R.string.notification_gps_subtitle))
// .setAutoCancel(true);
//
// val intent: Intent = Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
// val pi: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// mBuilder.setContentIntent(pi);
// mNotificationManager.notify(1, mBuilder.build());
// } else {
// mNotificationManager.cancel(1);
// }
}
fun showWeatherNotification(context: Context, show: Boolean) {
TODO("Show location notification")
// val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
//
// if (show) {
// val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Config")
// .setSmallIcon(R.drawable.ic_stat_name)
// .setColor(ContextCompat.getColor(context, R.color.colorPrimary))
// .setContentTitle(context.getString(R.string.settings_weather_provider_api_key_title))
// .setContentText(context.getString(R.string.settings_weather_provider_api_key_subtitle_not_set))
// .setAutoCancel(true);
//
// val intent: Intent = Intent(context, MainActivity::class.java);
// intent.putExtra(Constants.ACTION_EXTRA_OPEN_WEATHER_PROVIDER, true)
// val pi: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// mBuilder.setContentIntent(pi);
// mNotificationManager.notify(2, mBuilder.build());
// } else {
// mNotificationManager.cancel(2);
// }
}
fun expand(v: View) {
if (v.visibility != View.VISIBLE) {
v.measure(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
val targetHeight = v.measuredHeight
v.layoutParams.height = 0
v.visibility = View.VISIBLE
val a = object : Animation() {
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
v.layoutParams.height = if (interpolatedTime == 1f)
LinearLayout.LayoutParams.WRAP_CONTENT
else
(targetHeight * interpolatedTime).toInt()
v.translationY = 0f
v.requestLayout()
}
override fun willChangeBounds(): Boolean {
return true
}
}
a.duration = 500L
v.startAnimation(a)
}
}
fun collapse(v: View) {
if (v.visibility != View.GONE) {
val initialHeight = v.measuredHeight
val a = object : Animation() {
protected override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
if (interpolatedTime == 1f) {
v.visibility = View.GONE
} else {
v.layoutParams.height = initialHeight - (initialHeight * interpolatedTime).toInt()
v.requestLayout()
}
}
override fun willChangeBounds(): Boolean {
return true
}
}
a.duration = 500L //(initialHeight / v.context.resources.displayMetrics.density).toLong()
v.startAnimation(a)
}
}
fun getEmojiByUnicode(unicode: Int): String {
return String(Character.toChars(unicode))
}
fun getDifferenceText(context: Context, now: Long, start: Long): String {
val nowDate = DateTime(now)
val eventDate = DateTime(start)
var difference = start - now
difference += 60 * 1000 - (difference % (60 * 1000))
when {
difference <= 0 || TimeUnit.MILLISECONDS.toHours(difference) < 1 -> {
return ""
}
TimeUnit.MILLISECONDS.toHours(difference) < 12 -> {
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.HOUR_IN_MILLIS).toString()
}
eventDate.dayOfYear == nowDate.plusDays(1).dayOfYear -> {
return String.format("%s", context.getString(R.string.tomorrow))
}
eventDate.dayOfYear == nowDate.dayOfYear -> {
return String.format("%s", context.getString(R.string.today))
}
else -> {
return DateUtils.getRelativeTimeSpanString(start, now, DateUtils.DAY_IN_MILLIS).toString()
}
}
}
fun getFontColor(): Int {
return try {
Color.parseColor(Preferences.textGlobalColor)
} catch (e: Exception) {
Color.parseColor("#FFFFFF")
}
}
fun getTintedDrawable(context: Context, inputDrawable: Int, color: Int): Drawable? = ContextCompat.getDrawable(context, inputDrawable)?.apply {
DrawableCompat.setTint(this, color)
DrawableCompat.setTintMode(this, PorterDuff.Mode.SRC_IN)
}
fun changeBitmapColor(sourceBitmap: Bitmap, color: Int): Bitmap {
val resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0,
sourceBitmap.width - 1, sourceBitmap.height - 1)
val p = Paint()
val filter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)
p.colorFilter = filter
val canvas = Canvas(resultBitmap)
canvas.drawBitmap(resultBitmap, 0f, 0f, p)
return resultBitmap
}
fun getNextAlarm(context: Context): String = with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
return if (nextAlarmClock != null && nextAlarmClock.triggerTime - Calendar.getInstance().timeInMillis > 5 * 60 * 1000) {
DateFormat.getTimeFormat(context).format(Date(nextAlarmClock.triggerTime))
} else {
""
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M9,16.17L5.53,12.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.18,4.18c0.39,0.39 1.02,0.39 1.41,0L20.29,7.71c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L9,16.17z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,16h2v2h-2zM12.61,6.04c-2.06,-0.3 -3.88,0.97 -4.43,2.79 -0.18,0.58 0.26,1.17 0.87,1.17h0.2c0.41,0 0.74,-0.29 0.88,-0.67 0.32,-0.89 1.27,-1.5 2.3,-1.28 0.95,0.2 1.65,1.13 1.57,2.1 -0.1,1.34 -1.62,1.63 -2.45,2.88 0,0.01 -0.01,0.01 -0.01,0.02 -0.01,0.02 -0.02,0.03 -0.03,0.05 -0.09,0.15 -0.18,0.32 -0.25,0.5 -0.01,0.03 -0.03,0.05 -0.04,0.08 -0.01,0.02 -0.01,0.04 -0.02,0.07 -0.12,0.34 -0.2,0.75 -0.2,1.25h2c0,-0.42 0.11,-0.77 0.28,-1.07 0.02,-0.03 0.03,-0.06 0.05,-0.09 0.08,-0.14 0.18,-0.27 0.28,-0.39 0.01,-0.01 0.02,-0.03 0.03,-0.04 0.1,-0.12 0.21,-0.23 0.33,-0.34 0.96,-0.91 2.26,-1.65 1.99,-3.56 -0.24,-1.74 -1.61,-3.21 -3.35,-3.47z"/>
</vector>

View File

@ -34,6 +34,7 @@
android:foreground="?attr/selectableItemBackgroundBorderless" android:foreground="?attr/selectableItemBackgroundBorderless"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:id="@+id/action_back" android:id="@+id/action_back"
android:layout_alignParentLeft="true"
android:tint="@color/colorPrimaryText" android:tint="@color/colorPrimaryText"
android:src="@drawable/round_arrow_back" /> android:src="@drawable/round_arrow_back" />
<TextView <TextView
@ -68,8 +69,9 @@
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
android:inputType="textCapWords" android:inputType="textCapWords"
android:textAlignment="viewStart"
android:id="@+id/search" android:id="@+id/search"
android:gravity="center_vertical" android:gravity="center_vertical|start"
android:hint="@string/search" android:hint="@string/search"
android:text="@={viewModel.searchInput}" android:text="@={viewModel.searchInput}"
android:autofillHints="" /> android:autofillHints="" />

View File

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.tommasoberlose.anotherwidget.ui.viewmodels.CustomDateViewModel" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorPrimaryDark">
<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:foreground="?attr/selectableItemBackgroundBorderless"
android:layout_centerVertical="true"
android:id="@+id/action_back"
android:layout_alignParentLeft="true"
android: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/custom_date_format"
android:gravity="center"
style="@style/AnotherWidget.Main.Title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/action_save"
android:gravity="center"
android:layout_centerVertical="true"
android:padding="16dp"
android:layout_alignParentRight="true"
android:textColor="@color/colorAccent"
android:id="@+id/action_save"
android:textAppearance="@style/TextAppearance.MaterialComponents.Button"/>
</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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/colorPrimaryDark"
android:paddingStart="16dp"
android:paddingEnd="56dp"
android:id="@+id/date_format"
android:gravity="center_vertical|start"
android:textDirection="locale"
android:textAlignment="viewStart"
android:lines="1"
android:maxLines="1"
android:singleLine="true"
android:hint="@string/settings_date_format_title"
android:text="@={viewModel.dateInput}"
android:autofillHints=""
tools:ignore="TextFields" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="8dp"
android:layout_centerVertical="true"
android:src="@drawable/round_help_outline"
android:layout_alignParentEnd="true"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
app:tint="@color/colorSecondaryText"
android:layout_marginEnd="4dp"
android:id="@+id/action_date_format_info" />
</RelativeLayout>
</com.google.android.material.card.MaterialCardView>
</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">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:id="@+id/date_format_value"
android:textAppearance="@style/TextAppearance.AppCompat.Button"
android:letterSpacing="0"
android:textColor="@color/colorPrimaryText"
android:textSize="20sp"
app:textAllCaps="false"
android:gravity="center"
android:maxLines="1"
android:lines="1"
android:singleLine="true"
android:ellipsize="end"
android:layout_marginTop="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp" />
</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:paddingBottom="16dp"
android:paddingTop="16dp"
android:clipToPadding="false"
android:id="@+id/list_view" />
</RelativeLayout>
</LinearLayout>
</layout>

View File

@ -33,6 +33,7 @@
android:padding="10dp" android:padding="10dp"
android:foreground="?attr/selectableItemBackgroundBorderless" android:foreground="?attr/selectableItemBackgroundBorderless"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:id="@+id/action_back" android:id="@+id/action_back"
android:tint="@color/colorPrimaryText" android:tint="@color/colorPrimaryText"
android:src="@drawable/round_arrow_back" /> android:src="@drawable/round_arrow_back" />
@ -69,8 +70,10 @@
android:paddingRight="16dp" android:paddingRight="16dp"
android:inputType="textCapWords" android:inputType="textCapWords"
android:id="@+id/location" android:id="@+id/location"
android:gravity="center_vertical" android:gravity="center_vertical|start"
android:hint="@string/search" android:hint="@string/search"
android:textAlignment="viewStart"
android:textDirection="locale"
android:text="@={viewModel.locationInput}" android:text="@={viewModel.locationInput}"
android:autofillHints="" /> android:autofillHints="" />
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View File

@ -25,13 +25,26 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingLeft="8dp" android:paddingLeft="8dp"
android:paddingRight="8dp"> android:paddingRight="8dp">
<TextView <ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_splash_logo"
android:layout_alignParentBottom="true"
android:layout_marginBottom="3dp"
android:id="@+id/logo"/>
<LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:orientation="horizontal"
android:text="@string/app_name" android:layout_centerInParent="true">
android:gravity="center" <TextView
style="@style/AnotherWidget.Main.Title"/> android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/app_name"
android:gravity="center"
android:layout_marginBottom="1dp"
style="@style/AnotherWidget.Main.Title"/>
</LinearLayout>
</RelativeLayout> </RelativeLayout>
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
@ -40,8 +53,6 @@
android:id="@+id/preview" android:id="@+id/preview"
android:animateLayoutChanges="true" android:animateLayoutChanges="true"
app:cardBackgroundColor="@color/colorPrimary" app:cardBackgroundColor="@color/colorPrimary"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
app:cardCornerRadius="9dp" app:cardCornerRadius="9dp"
@ -61,6 +72,7 @@
android:layout_gravity="center" android:layout_gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:id="@+id/widget" android:id="@+id/widget"
android:alpha="0"
android:gravity="center"> android:gravity="center">
<TextClock <TextClock
android:id="@+id/clock" android:id="@+id/clock"
@ -79,6 +91,13 @@
android:id="@+id/widget_bitmap" android:id="@+id/widget_bitmap"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
</LinearLayout> </LinearLayout>
<ProgressBar
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerInParent="true"
android:indeterminate="true"
android:indeterminateTint="@android:color/white"
android:id="@+id/widget_loader" />
</RelativeLayout> </RelativeLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
@ -126,14 +145,19 @@
android:visibility="gone" android:visibility="gone"
app:cardBackgroundColor="@color/colorAccent" app:cardBackgroundColor="@color/colorAccent"
app:cardCornerRadius="0dp" app:cardCornerRadius="0dp"
android:id="@+id/action_add_widget"
android:clickable="true"
android:focusable="true"
app:cardElevation="4dp"> app:cardElevation="4dp">
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="72dp"
android:text="@string/add_widget" android:text="@string/add_widget"
android:layout_marginTop="-8dp"
android:clickable="false"
android:focusable="false"
android:gravity="center" android:gravity="center"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:id="@+id/action_add_widget"
app:cornerRadius="0dp" app:cornerRadius="0dp"
style="@style/Widget.MaterialComponents.Button.TextButton"/> style="@style/Widget.MaterialComponents.Button.TextButton"/>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View File

@ -38,6 +38,7 @@
android:padding="10dp" android:padding="10dp"
android:foreground="?attr/selectableItemBackgroundBorderless" android:foreground="?attr/selectableItemBackgroundBorderless"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:id="@+id/action_back" android:id="@+id/action_back"
android:tint="@color/colorPrimaryText" android:tint="@color/colorPrimaryText"
android:src="@drawable/round_arrow_back" /> android:src="@drawable/round_arrow_back" />
@ -57,7 +58,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textSize="16sp" android:textSize="16sp"
android:gravity="center" android:gravity="center"
android:text="This is a single developer project,\nso thank you for the support!" /> android:text="@string/support_dev_subtitle" />
</LinearLayout> </LinearLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View File

@ -25,7 +25,7 @@
android:padding="10dp" android:padding="10dp"
android:foreground="?attr/selectableItemBackgroundBorderless" android:foreground="?attr/selectableItemBackgroundBorderless"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_alignParentStart="true" android:layout_alignParentLeft="true"
android:id="@+id/action_back" android:id="@+id/action_back"
android:tint="@color/colorPrimaryText" android:tint="@color/colorPrimaryText"
android:src="@drawable/round_arrow_back" /> android:src="@drawable/round_arrow_back" />
@ -42,7 +42,7 @@
android:text="@string/action_save" android:text="@string/action_save"
android:gravity="center" android:gravity="center"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_alignParentEnd="true" android:layout_alignParentRight="true"
android:padding="16dp" android:padding="16dp"
android:textColor="@color/colorAccent" android:textColor="@color/colorAccent"
android:id="@+id/action_save" android:id="@+id/action_save"
@ -74,17 +74,21 @@
android:textStyle="bold" android:textStyle="bold"
android:nextFocusUp="@id/api_key" android:nextFocusUp="@id/api_key"
android:nextFocusLeft="@id/api_key" android:nextFocusLeft="@id/api_key"
android:gravity="center_vertical" android:gravity="center_vertical|start"
android:textColor="@color/colorPrimaryText" android:textColor="@color/colorPrimaryText"
app:boxBackgroundColor="@color/colorPrimaryDark" app:boxBackgroundColor="@color/colorPrimaryDark"
app:boxStrokeColor="@color/colorAccent" app:boxStrokeColor="@color/colorAccent"
app:hintTextColor="@color/colorAccent" app:hintTextColor="@color/colorAccent"
android:hint="@string/api_key_hint" android:hint="@string/api_key_hint"
android:textAlignment="viewStart"
android:textDirection="locale"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"> style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
/> android:textAlignment="viewStart"
android:textDirection="locale"
android:gravity="center_vertical|start" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
</LinearLayout> </LinearLayout>
@ -99,6 +103,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title" style="@style/AnotherWidget.Settings.Title"
android:gravity="start"
android:textAlignment="viewStart"
android:text="@string/api_key_title_1"/> android:text="@string/api_key_title_1"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
@ -106,12 +112,15 @@
style="@style/AnotherWidget.Main.Subtitle" style="@style/AnotherWidget.Main.Subtitle"
android:textSize="16sp" android:textSize="16sp"
android:gravity="start" android:gravity="start"
android:textAlignment="viewStart"
android:text="@string/api_key_subtitle_1"/> android:text="@string/api_key_subtitle_1"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title" style="@style/AnotherWidget.Settings.Title"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:gravity="start"
android:textAlignment="viewStart"
android:text="@string/api_key_title_2"/> android:text="@string/api_key_title_2"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
@ -119,12 +128,15 @@
style="@style/AnotherWidget.Main.Subtitle" style="@style/AnotherWidget.Main.Subtitle"
android:textSize="16sp" android:textSize="16sp"
android:gravity="start" android:gravity="start"
android:textAlignment="viewStart"
android:text="@string/api_key_subtitle_2"/> android:text="@string/api_key_subtitle_2"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="@style/AnotherWidget.Settings.Title" style="@style/AnotherWidget.Settings.Title"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:gravity="start"
android:textAlignment="viewStart"
android:text="@string/api_key_title_3"/> android:text="@string/api_key_title_3"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
@ -132,6 +144,7 @@
style="@style/AnotherWidget.Main.Subtitle" style="@style/AnotherWidget.Main.Subtitle"
android:textSize="16sp" android:textSize="16sp"
android:gravity="start" android:gravity="start"
android:textAlignment="viewStart"
android:text="@string/api_key_subtitle_3"/> android:text="@string/api_key_subtitle_3"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
@ -139,6 +152,7 @@
style="@style/AnotherWidget.Main.Subtitle" style="@style/AnotherWidget.Main.Subtitle"
android:textSize="16sp" android:textSize="16sp"
android:gravity="start" android:gravity="start"
android:textAlignment="viewStart"
android:id="@+id/last_info"/> android:id="@+id/last_info"/>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:layout_width="match_parent" android:layout_width="match_parent"
@ -148,6 +162,7 @@
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:gravity="start|center_vertical" android:gravity="start|center_vertical"
android:textAlignment="viewStart"
android:layout_marginStart="-8dp" android:layout_marginStart="-8dp"
style="@style/Widget.MaterialComponents.Button.TextButton" style="@style/Widget.MaterialComponents.Button.TextButton"
android:textAllCaps="false" android:textAllCaps="false"

View File

@ -7,9 +7,13 @@
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:focusable="true" android:focusable="true"
android:clickable="true" android:clickable="true"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:orientation="horizontal" android:orientation="horizontal"
android:id="@+id/item" android:id="@+id/item"
android:gravity="center_vertical"> android:gravity="center_vertical|start">
<ImageView <ImageView
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
@ -22,10 +26,14 @@
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_weight="2"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center_vertical" android:gravity="center_vertical|start"
android:paddingEnd="24dp"
android:lines="1"
android:textAlignment="viewStart"
android:maxLines="1"
android:ellipsize="end"
android:textColor="@color/colorPrimaryText" android:textColor="@color/colorPrimaryText"
style="@style/AnotherWidget.Settings.Title"/> style="@style/AnotherWidget.Settings.Title"/>
</LinearLayout> </LinearLayout>

Some files were not shown because too many files have changed in this diff Show More