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"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>

View File

@ -18,8 +18,8 @@ android {
applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 23
targetSdkVersion 29
versionCode 40
versionName "2.0"
versionCode 48
versionName "2.0.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@ -36,6 +36,10 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
@ -65,6 +69,7 @@ dependencies {
implementation 'com.google.android.material:material:1.2.0-alpha06'
implementation 'androidx.browser:browser:1.2.0'
implementation 'net.idik:slimadapter:2.1.2'
implementation 'com.google.android:flexbox:2.0.1'
// Lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
@ -81,9 +86,9 @@ dependencies {
// Other
implementation 'androidx.multidex:multidex:2.0.1'
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 'com.github.bumptech.glide:glide:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
//Weather
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
@ -96,6 +101,7 @@ dependencies {
// KTX
implementation "androidx.core:core-ktx:1.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.
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:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name=".components.AWApplication"
android:name=".AWApplication"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
@ -28,9 +28,10 @@
<activity android:name=".ui.activities.CustomLocationActivity" 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.CustomDateActivity" android:launchMode="singleInstance" />
<receiver android:name=".ui.widgets.TheWidget">
<receiver android:name=".ui.widgets.MainWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@ -65,6 +66,7 @@
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
<action android:name="android.intent.action.DATE_CHANGED" />
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
</receiver>
<receiver
@ -76,6 +78,7 @@
<action android:name="com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
</receiver>
@ -88,6 +91,8 @@
</intent-filter>
</receiver>
<service android:name=".services.EventListenerJob" android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
</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 androidx.appcompat.app.AppCompatDelegate
@ -23,5 +23,22 @@ class AWApplication : Application() {
.deleteRealmIfMigrationNeeded()
.build()
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.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.annotation.MenuRes
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.card.MaterialCardView
import com.tommasoberlose.anotherwidget.R
import kotlinx.android.synthetic.main.bottom_sheet_menu.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
* 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 var selectedRes: T? = null
private var selectedRes: ArrayList<T> = ArrayList()
private var callback: ((selectedValue: T) -> Unit)? = null
private var multipleSelectionCallback: ((selectedValues: ArrayList<T>) -> Unit)? = null
fun selectResource(res: T): BottomSheetMenu<T> {
selectedRes = res
fun setSelectedValue(res: T): BottomSheetMenu<T> {
selectedRes = ArrayList(listOf(res))
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))
return this
}
@ -39,6 +48,11 @@ open class BottomSheetMenu<T>(context: Context, private val header: String? = nu
return this
}
fun addOnMultipleSelectItemListener(multipleSelectionCallback: (selectedValues: ArrayList<T>) -> Unit): BottomSheetMenu<T> {
this.multipleSelectionCallback = multipleSelectionCallback
return this
}
override fun show() {
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
for (item in items) {
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_item, null)
itemView.label.text = item.title
itemView.isSelected = item.value == selectedRes
itemView.setOnClickListener {
callback?.invoke(item.value)
this.dismiss()
if (item.value != null) {
val itemView = View.inflate(context, R.layout.bottom_sheet_menu_item, null)
itemView.label.text = item.title
if (isMultiSelection) {
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)
)
} 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)
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 customLocationAdd by stringPref(key = "PREF_CUSTOM_LOCATION_ADD", default = "")
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 showUntil by intPref(key = "PREF_SHOW_UNTIL", default = 1)
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 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 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.tommasoberlose.anotherwidget.R
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.
*/
object WeatherUtil {
object WeatherHelper {
fun updateWeather(context: Context) {
val networkApi = WeatherNetworkApi(context)
if (Preferences.customLocationAdd != "") {
weatherNetworkRequest(
context
)
networkApi.updateWeather()
} else {
LocationServices.getFusedLocationProviderClient(context).lastLocation.addOnSuccessListener {
Preferences.customLocationLat = it.latitude.toString()
Preferences.customLocationLon = it.longitude.toString()
weatherNetworkRequest(context)
networkApi.updateWeather()
}
}
}
private fun weatherNetworkRequest(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) {
fun removeWeather(context: Context) {
Preferences.remove(Preferences::weatherTemp)
Preferences.remove(Preferences::weatherTempUnit)
Util.updateWidget(context)
MainWidget.updateWidget(context)
}
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 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.Intent
import android.util.Log
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
class NewCalendarEventReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when {
intent.action.equals(Intent.ACTION_PROVIDER_CHANGED) -> {
CalendarUtil.updateEventList(context)
val eventRepository = EventRepository(context)
Log.d("ciao", "nuovo evento")
when (intent.action) {
Intent.ACTION_PROVIDER_CHANGED,
Intent.ACTION_TIME_CHANGED -> {
CalendarHelper.updateEventList(context)
}
intent.action == Actions.ACTION_GO_TO_NEXT_EVENT -> {
CalendarUtil.goToNextEvent(context)
Actions.ACTION_GO_TO_NEXT_EVENT -> {
eventRepository.goToNextEvent()
}
intent.action == Actions.ACTION_GO_TO_PREVIOUS_EVENT -> {
CalendarUtil.goToPreviousEvent(context)
Actions.ACTION_GO_TO_PREVIOUS_EVENT -> {
eventRepository.goToPreviousEvent()
}
}
}

View File

@ -5,12 +5,13 @@ import android.content.Context
import android.content.Intent
import android.app.AlarmManager
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.Preferences
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
import com.tommasoberlose.anotherwidget.utils.Util
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import org.joda.time.Period
import java.text.DateFormat
import java.util.*
@ -20,11 +21,11 @@ class UpdatesReceiver : BroadcastReceiver() {
when (intent.action) {
Intent.ACTION_BOOT_COMPLETED,
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",
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) {
removeUpdates(context)
val eventRepository = EventRepository(context)
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
// Update the widget every hour till the event

View File

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

View File

@ -5,8 +5,7 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.utils.Util
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.helpers.IntentHelper
class WidgetClickListenerReceiver : BroadcastReceiver() {
@ -15,10 +14,10 @@ class WidgetClickListenerReceiver : BroadcastReceiver() {
if (intent.action == Actions.ACTION_OPEN_WEATHER_INTENT) {
context.sendBroadcast(Intent(Actions.ACTION_WEATHER_UPDATE))
try {
context.startActivity(Util.getWeatherIntent(context))
context.startActivity(IntentHelper.getWeatherIntent(context))
} catch (e: Exception) {
try {
context.applicationContext.startActivity(Util.getWeatherIntent(context.applicationContext))
context.applicationContext.startActivity(IntentHelper.getWeatherIntent(context.applicationContext))
} catch (e: Exception) {
val uri = Uri.parse("http://www.google.com/#q=weather")
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.os.Bundle
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.pm.ApplicationInfo
import com.tommasoberlose.anotherwidget.components.events.ApplicationListEvent
import android.text.Editable
import android.text.TextWatcher
import android.content.pm.ResolveInfo
import android.view.View
import android.view.Window
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.databinding.Observable
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialFadeThrough
import com.tommasoberlose.anotherwidget.components.events.AppInfoSavedEvent
import com.bumptech.glide.Glide
import com.tommasoberlose.anotherwidget.databinding.ActivityChooseApplicationBinding
import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants
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.list_view
import kotlinx.coroutines.*
@ -71,14 +60,16 @@ class ChooseApplicationActivity : AppCompatActivity() {
finish()
}
}
.register<ApplicationInfo>(R.layout.application_info_layout) { item, injector ->
.register<ResolveInfo>(R.layout.application_info_layout) { item, injector ->
injector
.text(R.id.text, pm.getApplicationLabel(item).toString())
try {
injector.image(R.id.icon, item.loadIcon(pm))
} catch (ignore: Exception) {
}
.text(R.id.text, item.loadLabel(pm))
.with<ImageView>(R.id.icon) {
Glide
.with(this)
.load(item.loadIcon(pm))
.centerCrop()
.into(it)
}
injector.clicked(R.id.item) {
saveApp(item)
@ -110,9 +101,7 @@ class ChooseApplicationActivity : AppCompatActivity() {
viewModel.appList.value!!
} else {
viewModel.appList.value!!.filter {
pm.getApplicationLabel(
it
).toString().contains(search, true)
it.loadLabel(pm).contains(search, true)
}
}
withContext(Dispatchers.Main) {
@ -130,10 +119,10 @@ class ChooseApplicationActivity : AppCompatActivity() {
}
}
private fun saveApp(app: ApplicationInfo) {
private fun saveApp(app: ResolveInfo) {
val resultIntent = Intent()
resultIntent.putExtra(Constants.RESULT_APP_NAME, pm.getApplicationLabel(app).toString())
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.packageName)
resultIntent.putExtra(Constants.RESULT_APP_NAME, app.loadLabel(pm))
resultIntent.putExtra(Constants.RESULT_APP_PACKAGE, app.resolvePackageName)
setResult(Activity.RESULT_OK, resultIntent)
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.listener.PermissionRequest
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.ActivityCustomLocationBinding
import com.tommasoberlose.anotherwidget.global.Preferences

View File

@ -2,37 +2,43 @@ package com.tommasoberlose.anotherwidget.ui.activities
import android.animation.ValueAnimator
import android.app.Activity
import android.os.Bundle
import android.appwidget.AppWidgetManager
import android.view.View
import com.tommasoberlose.anotherwidget.R
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
import android.widget.LinearLayout
import android.view.View
import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.addListener
import androidx.core.animation.doOnEnd
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.google.android.material.tabs.TabLayoutMediator
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Preferences
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.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 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.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
@ -62,19 +68,38 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}
}.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)
subscribeUi(viewModel)
updateUI()
CalendarHelper.updateEventList(this)
WeatherHelper.updateWeather(this)
}
private var uiJob: Job? = null
private fun updateUI() {
lifecycleScope.launch(Dispatchers.IO) {
val generatedView = TheWidget.generateWidgetView(this@MainActivity, preview.measuredWidth)
generatedView.measure(0, 0)
val bitmap = Util.getBitmapFromView(generatedView, generatedView.measuredWidth, generatedView.measuredHeight)
preview.setCardBackgroundColor(getColor(if (ColorHelper.getFontColor().isColorDark()) android.R.color.white else R.color.colorAccent))
val generatedView = MainWidget.generateWidgetView(this@MainActivity)
generatedView.measure(0, 0)
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) {
// Clock
clock.setTextColor(Util.getFontColor())
clock.setTextColor(ColorHelper.getFontColor())
clock.setTextSize(TypedValue.COMPLEX_UNIT_SP, Preferences.clockTextSize.toPixel(this@MainActivity))
clock.format12Hour = "hh:mm"
@ -112,7 +137,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}.start()
ValueAnimator.ofInt(
preview.measuredHeight,
preview.height,
160.toPixel(this@MainActivity) + if (Preferences.showClock) 100.toPixel(this@MainActivity) else 0
).apply {
duration = 500L
@ -126,14 +151,20 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}
widget_bitmap.setImageBitmap(bitmap)
widget_loader.animate().scaleX(0f).scaleY(0f).start()
widget.animate().alpha(1f).start()
}
}
}
private fun subscribeUi(viewModel: MainViewModel) {
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() {
@ -171,11 +202,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
if (extras.containsKey(Actions.ACTION_EXTRA_OPEN_WEATHER_PROVIDER)) {
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) {
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.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
@ -26,7 +27,6 @@ import net.idik.lib.slimadapter.SlimAdapter
class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
private val BILLING_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAox5CcxuoLJ6CmNS7s6lVQzJ253njKKGF8MoQ/gQ5gEw2Fr03fBvtHpiVMpnjhNLw5NMeIpzRvkVqeQ7BfkC7c0BLCJUqf/fFA11ArQe8na6QKt5O4d+v4sbHtP7mm3GQNPOBaqRzcpFZaiAbfk6mnalo+tzM47GXrQFt5bNSrMctCs7bbChqJfH2cyMW0F8DHWEEeO5xElBmH3lh4FVpwIUTPYJIV3n0yhE3qqRA0WXkDej66g/uAt/rebmMZLmwNwIive5cObU4o41YyKRv2wSAicrv3W40LftzXAOOordIbmzDFN8ksh3VrnESqwCDGG97nZVbPG/+3LD0xHWiRwIDAQAB"
private lateinit var viewModel: SupportDevViewModel
private lateinit var adapter: SlimAdapter
@ -35,7 +35,7 @@ class SupportDevActivity : AppCompatActivity(), PurchasesUpdatedListener {
viewModel = ViewModelProvider(this).get(SupportDevViewModel::class.java)
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)

View File

@ -1,21 +1,14 @@
package com.tommasoberlose.anotherwidget.ui.activities
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.DialogInterface
import android.content.SharedPreferences
import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.text.Html
import android.text.TextWatcher
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.tommasoberlose.anotherwidget.R
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 kotlinx.android.synthetic.main.activity_weather_provider.*
@ -46,18 +39,4 @@ class WeatherProviderActivity : AppCompatActivity() {
}
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.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.karumi.dexter.Dexter
import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.BuildConfig
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentAdvancedSettingsBinding
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.SupportDevActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
import com.tommasoberlose.anotherwidget.utils.Util
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
import com.tommasoberlose.anotherwidget.utils.openURI
import kotlinx.android.synthetic.main.fragment_advanced_settings.*
import kotlinx.coroutines.delay
@ -57,7 +55,7 @@ class AdvancedSettingsFragment : Fragment() {
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
val binding = DataBindingUtil.inflate<FragmentAdvancedSettingsBinding>(inflater, R.layout.fragment_advanced_settings, container, false)
subscribeUi(binding, viewModel)
subscribeUi(viewModel)
binding.lifecycleOwner = this
binding.viewModel = viewModel
@ -69,10 +67,11 @@ class AdvancedSettingsFragment : Fragment() {
super.onActivityCreated(savedInstanceState)
setupListener()
app_version.text = "v%s".format(BuildConfig.VERSION_NAME)
}
private fun subscribeUi(
binding: FragmentAdvancedSettingsBinding,
viewModel: MainViewModel
) {
viewModel.darkThemePreference.observe(viewLifecycleOwner, Observer {
@ -94,8 +93,8 @@ class AdvancedSettingsFragment : Fragment() {
private fun setupListener() {
action_change_theme.setOnClickListener {
maintainScrollPosition {
BottomSheetMenu<Int>(requireContext())
.selectResource(Preferences.darkThemePreference)
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_theme_title))
.setSelectedValue(Preferences.darkThemePreference)
.addItem(
getString(R.string.settings_subtitle_dark_theme_light),
AppCompatDelegate.MODE_NIGHT_NO
@ -116,11 +115,23 @@ class AdvancedSettingsFragment : Fragment() {
action_show_wallpaper.setOnClickListener {
maintainScrollPosition {
if (Preferences.showWallpaper) {
Preferences.showWallpaper = false
} else {
requirePermission()
}
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_title_show_wallpaper))
.setSelectedValue(Preferences.showWallpaper)
.addItem(
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 {
Util.updateWidget(requireContext())
CalendarUtil.updateEventList(requireContext())
MainWidget.updateWidget(requireContext())
CalendarHelper.updateEventList(requireContext())
}
}

View File

@ -4,12 +4,11 @@ import android.Manifest
import android.app.Activity
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.SimpleAdapter
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
@ -25,7 +24,7 @@ import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.R
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.global.Constants
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.MainActivity
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
import com.tommasoberlose.anotherwidget.utils.Util
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
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 kotlinx.android.synthetic.main.fragment_calendar_settings.*
import kotlinx.android.synthetic.main.fragment_calendar_settings.scrollView
import kotlinx.android.synthetic.main.fragment_weather_settings.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*
import kotlin.Comparator
class CalendarSettingsFragment : Fragment() {
@ -85,6 +87,12 @@ class CalendarSettingsFragment : Fragment() {
viewModel.showEvents.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
binding.isCalendarEnabled = it
if (it) {
CalendarHelper.setEventUpdatesAndroidN(requireContext())
} else {
CalendarHelper.removeEventUpdatesAndroidN(requireContext())
}
}
checkReadEventsPermission()
})
@ -106,7 +114,7 @@ class CalendarSettingsFragment : Fragment() {
viewModel.secondRowInformation.observe(viewLifecycleOwner, Observer {
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 {
maintainScrollPosition {
show_until_label.text = getString(Util.getShowUntilString(it))
show_until_label.text = getString(SettingsStringHelper.getShowUntilString(it))
}
checkReadEventsPermission()
})
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 {
maintainScrollPosition {
val now = 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
date_format_label.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
}
})
@ -159,26 +162,51 @@ class CalendarSettingsFragment : Fragment() {
}
action_filter_calendar.setOnClickListener {
val calendarSelectorList: List<CalendarSelector> = CalendarUtil.getCalendarList(requireContext()).map { CalendarSelector(it.id.toInt(), it.displayName, it.accountName) }
var calFiltered = Preferences.calendarFilter
val calendarSelectorList: List<CalendarSelector> = CalendarHelper.getCalendarList(requireContext()).map {
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()) {
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 calSelected = calendarSelectorList.map { !calFiltered.contains(" " + it.id.toString() + ",") }.toBooleanArray()
val filteredCalendarIds = CalendarHelper.getFilteredCalendarIdList()
val visibleCalendarIds = calendarSelectorList.map { it.id }.filter { id: Long -> !filteredCalendarIds.contains(id) }
AlertDialog.Builder(requireContext()).setTitle(getString(R.string.settings_filter_calendar_subtitle))
.setMultiChoiceItems(calNames, calSelected) { _, item, isChecked ->
val dialogItem: String = String.format(" %s%s", calendarSelectorList.get(item).id, ",")
calFiltered = calFiltered.replace(dialogItem, "");
if (!isChecked) {
calFiltered += dialogItem
}
val dialog = BottomSheetMenu<Long>(requireContext(), header = getString(R.string.settings_filter_calendar_subtitle), isMultiSelection = true)
.setSelectedValues(visibleCalendarIds)
calendarSelectorList.indices.forEach { index ->
if (index == 0 || calendarSelectorList[index].accountName != calendarSelectorList[index - 1].accountName) {
dialog.addItem(calendarSelectorList[index].accountName)
}
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
Preferences.calendarFilter = calFiltered
}
.setNegativeButton(android.R.string.cancel, null)
.show()
dialog.addItem(
if (calendarSelectorList[index].name == calendarSelectorList[index].accountName) getString(R.string.account_events) else calendarSelectorList[index].name,
calendarSelectorList[index].id
)
}
dialog.addOnMultipleSelectItemListener { values ->
CalendarHelper.filterCalendar(calendarSelectorList.map { it.id }.filter { !values.contains(it) })
checkReadEventsPermission()
}.show()
} else {
requireActivity().toast(getString(R.string.calendar_settings_list_error))
}
@ -186,7 +214,7 @@ class CalendarSettingsFragment : Fragment() {
action_show_all_day.setOnClickListener {
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_gone), false)
.addOnSelectItemListener { value ->
@ -197,7 +225,7 @@ class CalendarSettingsFragment : Fragment() {
action_show_declined_events.setOnClickListener {
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_not_visible), false)
.addOnSelectItemListener { value ->
@ -208,7 +236,7 @@ class CalendarSettingsFragment : Fragment() {
action_show_multiple_events.setOnClickListener {
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_not_visible), false)
.addOnSelectItemListener { value ->
@ -219,7 +247,7 @@ class CalendarSettingsFragment : Fragment() {
action_show_diff_time.setOnClickListener {
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_not_visible), false)
.addOnSelectItemListener { value ->
@ -230,9 +258,9 @@ class CalendarSettingsFragment : Fragment() {
action_second_row_info.setOnClickListener {
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 {
dialog.addItem(getString(Util.getSecondRowInfoString(it)), it)
dialog.addItem(getString(SettingsStringHelper.getSecondRowInfoString(it)), it)
}
dialog.addOnSelectItemListener { value ->
Preferences.secondRowInformation = value
@ -242,9 +270,9 @@ class CalendarSettingsFragment : Fragment() {
action_show_until.setOnClickListener {
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 {
dialog.addItem(getString(Util.getShowUntilString(it)), it)
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
}
dialog.addOnSelectItemListener { 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 {
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) {
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)
read_calendar_permission_alert_icon.isVisible = false
CalendarUtil.updateEventList(requireContext())
CalendarHelper.updateEventList(requireContext())
} else {
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

View File

@ -3,10 +3,10 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
@ -15,7 +15,6 @@ import androidx.lifecycle.lifecycleScope
import com.chibatching.kotpref.bulk
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.databinding.FragmentCalendarSettingsBinding
import com.tommasoberlose.anotherwidget.databinding.FragmentClockSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants
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.MainActivity
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.coroutines.delay
import kotlinx.coroutines.launch
@ -67,6 +64,11 @@ class ClockSettingsFragment : Fragment() {
binding: FragmentClockSettingsBinding,
viewModel: MainViewModel
) {
viewModel.showBigClockWarning.observe(viewLifecycleOwner, Observer {
large_clock_warning.isVisible = it
small_clock_warning.isVisible = !it
})
viewModel.showClock.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_clock_label.text =
@ -96,12 +98,16 @@ class ClockSettingsFragment : Fragment() {
}
private fun setupListener() {
action_hide_large_clock_warning.setOnClickListener {
Preferences.showBigClockWarning = false
}
action_show_clock.setOnClickListener {
Preferences.showClock = !Preferences.showClock
}
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 {
dialog.addItem("${it}sp", it.toFloat())
}
@ -111,7 +117,7 @@ class ClockSettingsFragment : Fragment() {
}
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_not_visible), false)
.addOnSelectItemListener { value ->

View File

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

View File

@ -3,7 +3,6 @@ package com.tommasoberlose.anotherwidget.ui.fragments
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
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.Preferences
import com.tommasoberlose.anotherwidget.global.RequestCode
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.ui.activities.ChooseApplicationActivity
import com.tommasoberlose.anotherwidget.ui.activities.CustomLocationActivity
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
import com.tommasoberlose.anotherwidget.ui.activities.WeatherProviderActivity
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.scrollView
import kotlinx.coroutines.delay
@ -76,6 +77,10 @@ class WeatherSettingsFragment : Fragment() {
binding: FragmentWeatherSettingsBinding,
viewModel: MainViewModel
) {
viewModel.showWeatherWarning.observe(viewLifecycleOwner, Observer {
weather_warning.isVisible = it
})
viewModel.showWeather.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_weather_label.text =
@ -113,7 +118,7 @@ class WeatherSettingsFragment : Fragment() {
viewModel.weatherRefreshPeriod.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
label_weather_refresh_period.text = getString(Util.getRefreshPeriodString(it))
label_weather_refresh_period.text = getString(SettingsStringHelper.getRefreshPeriodString(it))
}
checkLocationPermission()
})
@ -127,7 +132,7 @@ class WeatherSettingsFragment : Fragment() {
}
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
WeatherReceiver.setUpdates(requireContext())
} else if (Preferences.showWeather && Preferences.customLocationAdd == "") {
@ -139,6 +144,9 @@ class WeatherSettingsFragment : Fragment() {
}
private fun setupListener() {
action_hide_weather_warning.setOnClickListener {
Preferences.showWeatherWarning = false
}
action_show_weather.setOnClickListener {
Preferences.showWeather = !Preferences.showWeather
@ -164,7 +172,7 @@ class WeatherSettingsFragment : Fragment() {
action_change_unit.setOnClickListener {
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.celsius), "C")
.addOnSelectItemListener { value ->
@ -176,9 +184,9 @@ class WeatherSettingsFragment : Fragment() {
action_weather_refresh_period.setOnClickListener {
if (Preferences.showWeather) {
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 {
dialog.addItem(getString(Util.getRefreshPeriodString(it)), it)
dialog.addItem(getString(SettingsStringHelper.getRefreshPeriodString(it)), it)
}
dialog
.addOnSelectItemListener { value ->
@ -202,13 +210,14 @@ class WeatherSettingsFragment : Fragment() {
when (requestCode) {
Constants.RESULT_CODE_CUSTOM_LOCATION -> {
WeatherReceiver.setUpdates(requireContext())
checkLocationPermission()
}
RequestCode.WEATHER_APP_REQUEST_CODE.code -> {
Preferences.bulk {
weatherAppName = data?.getStringExtra(Constants.RESULT_APP_NAME) ?: getString(R.string.default_weather_app)
weatherAppPackage = data?.getStringExtra(Constants.RESULT_APP_PACKAGE) ?: ""
}
Util.updateWidget(requireContext())
MainWidget.updateWidget(requireContext())
}
RequestCode.WEATHER_PROVIDER_REQUEST_CODE.code -> {
WeatherReceiver.setOneTimeUpdate(requireContext())

View File

@ -1,17 +1,21 @@
package com.tommasoberlose.anotherwidget.ui.viewmodels
import android.app.Application
import android.content.Intent
import android.content.pm.ApplicationInfo
import androidx.databinding.ObservableField
import androidx.lifecycle.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import android.content.pm.ResolveInfo
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.liveData
class ChooseApplicationViewModel(application: Application) : AndroidViewModel(application) {
val appList: LiveData<List<ApplicationInfo>> = liveData {
val app = application.packageManager.getInstalledApplications(0)
val appList: LiveData<List<ResolveInfo>> = liveData {
val mainIntent = Intent(Intent.ACTION_MAIN, null).apply {
addCategory(Intent.CATEGORY_LAUNCHER)
}
val app = application.packageManager.queryIntentActivities( mainIntent, 0)
emit(app)
}
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)
// Clock Settings
val showClock = Preferences.asLiveData(Preferences::showClock)
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
@ -35,6 +34,8 @@ class MainViewModel : ViewModel() {
val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm)
val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
val showBigClockWarning = Preferences.asLiveData(Preferences::showBigClockWarning)
// Weather Settings
val showWeather = Preferences.asLiveData(Preferences::showWeather)
val weatherTempUnit = Preferences.asLiveData(Preferences::weatherTempUnit)
@ -45,6 +46,8 @@ class MainViewModel : ViewModel() {
val customLocationAdd = Preferences.asLiveData(Preferences::customLocationAdd)
val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning)
// Advanced Settings
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
val showWallpaper = Preferences.asLiveData(Preferences::showWallpaper)

View File

@ -4,10 +4,10 @@ import android.Manifest
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.Typeface
import android.os.Bundle
@ -22,25 +22,27 @@ import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.db.EventRepository
import com.tommasoberlose.anotherwidget.global.Actions
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.*
import com.tommasoberlose.anotherwidget.receivers.NewCalendarEventReceiver
import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
import com.tommasoberlose.anotherwidget.receivers.WeatherReceiver
import com.tommasoberlose.anotherwidget.utils.CalendarUtil
import com.tommasoberlose.anotherwidget.utils.Util
import com.tommasoberlose.anotherwidget.utils.WeatherUtil
import com.tommasoberlose.anotherwidget.receivers.WidgetClickListenerReceiver
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
import com.tommasoberlose.anotherwidget.utils.convertSpToPixels
import com.tommasoberlose.anotherwidget.utils.getCapWordString
import com.tommasoberlose.anotherwidget.utils.toPixel
import kotlinx.android.synthetic.main.the_widget.view.*
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.math.min
class TheWidget : AppWidgetProvider() {
class MainWidget : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
for (appWidgetId in appWidgetIds) {
@ -54,8 +56,14 @@ class TheWidget : AppWidgetProvider() {
}
override fun onEnabled(context: Context) {
CalendarUtil.updateEventList(context)
CalendarHelper.updateEventList(context)
WeatherReceiver.setUpdates(context)
if (Preferences.showEvents) {
CalendarHelper.setEventUpdatesAndroidN(context)
} else {
CalendarHelper.removeEventUpdatesAndroidN(context)
}
}
override fun onDisabled(context: Context) {
@ -65,27 +73,37 @@ class TheWidget : AppWidgetProvider() {
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,
appWidgetId: Int) {
val displayMetrics = Resources.getSystem().displayMetrics
var height = 110.toPixel(context)
val width = displayMetrics.widthPixels
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) {
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)
val generatedView = generateWidgetView(context, w)
val generatedView = generateWidgetView(context)
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
views = updateClockView(context, views, appWidgetId)
@ -98,29 +116,30 @@ class TheWidget : AppWidgetProvider() {
}
private fun updateCalendarView(context: Context, v: View, views: RemoteViews, widgetID: Int): RemoteViews {
val eventRepository = EventRepository(context)
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.calendar_layout_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)
val nextEvent = CalendarUtil.getNextEvent()
val nextAlarm = Util.getNextAlarm(context)
val nextEvent = eventRepository.getNextEvent()
val nextAlarm = AlarmHelper.getNextAlarm(context)
if (Preferences.showEvents && Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR) && nextEvent != null) {
if (Preferences.showNextEvent && CalendarUtil.getEventsCount() > 1) {
if (Preferences.showEvents && context.checkGrantedPermission(Manifest.permission.READ_CALENDAR) && nextEvent != null) {
if (Preferences.showNextEvent && eventRepository.getEventsCount() > 1) {
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.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)
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.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 {
@ -128,44 +147,44 @@ class TheWidget : AppWidgetProvider() {
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_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)
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)
} else {
views.setViewVisibility(R.id.next_event_difference_time_rect, View.GONE)
}
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)
} else {
views.setOnClickPendingIntent(R.id.next_event_rect, pIntent)
}
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)
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.empty_layout_rect, View.GONE)
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
} else if (Preferences.secondRowInformation == 2 && nextAlarm != "") {
val clockIntent = PendingIntent.getActivity(context, widgetID, Util.getClockIntent(context), 0)
} else if (Preferences.showNextAlarm && nextAlarm != "") {
val clockIntent = PendingIntent.getActivity(context, widgetID, IntentHelper.getClockIntent(context), 0)
views.setOnClickPendingIntent(R.id.second_row_rect, clockIntent)
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)
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.empty_layout_rect, View.GONE)
@ -189,10 +208,10 @@ class TheWidget : AppWidgetProvider() {
views.setOnClickPendingIntent(R.id.calendar_weather_rect, weatherPIntent)
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)
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 {
views.setViewVisibility(R.id.weather_rect, View.GONE)
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
@ -204,9 +223,9 @@ class TheWidget : AppWidgetProvider() {
if (!Preferences.showClock) {
views.setViewVisibility(R.id.time, View.GONE)
} 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))
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.setViewVisibility(R.id.time, View.VISIBLE)
}
@ -214,29 +233,42 @@ class TheWidget : AppWidgetProvider() {
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 now = Calendar.getInstance()
v.empty_layout.visibility = View.VISIBLE
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 = Util.getCapWordString("${SimpleDateFormat("EEEE", Locale.getDefault()).format(now.time)}, ${DateUtils.formatDateTime(context, now.timeInMillis, flags)}")
v.empty_date.text = DateHelper.getDateText(context, now)
val nextEvent = CalendarUtil.getNextEvent()
val nextAlarm = Util.getNextAlarm(context)
val nextEvent = eventRepository.getNextEvent()
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
v.action_next.isVisible = Preferences.showNextEvent && CalendarUtil.getEventsCount() > 1
v.action_previous.isVisible = Preferences.showNextEvent && CalendarUtil.getEventsCount() > 1
v.action_next.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.action_previous.isVisible = Preferences.showNextEvent && eventRepository.getEventsCount() > 1
v.next_event.text = nextEvent.title
if (Preferences.showDiffTime && now.timeInMillis < nextEvent.startDate) {
v.next_event_difference_time.text = Util.getDifferenceText(context, now.timeInMillis, nextEvent.startDate).toLowerCase(Locale.getDefault())
if (Preferences.showDiffTime && now.timeInMillis < (nextEvent.startDate - 1000 * 60 * 60)) {
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
} else {
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)
} 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.calendar_layout.visibility = View.VISIBLE
} else if (Preferences.secondRowInformation == 2 && nextAlarm != "") {
} else if (Preferences.showNextAlarm && nextAlarm != "") {
v.second_row_icon.setImageDrawable(
ContextCompat.getDrawable(
context,
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_date.text = Util.getNextAlarm(context)
v.next_event.text = DateHelper.getDateText(context, now)
v.next_event_date.text = AlarmHelper.getNextAlarm(context)
v.empty_layout.visibility = View.GONE
v.calendar_layout.visibility = View.VISIBLE
}
@ -293,11 +326,11 @@ class TheWidget : AppWidgetProvider() {
// 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 {
it.setTextColor(Util.getFontColor())
it.setTextColor(ColorHelper.getFontColor())
}
listOf<ImageView>(v.second_row_icon, v.action_next, v.action_previous).forEach {
it.setColorFilter(Util.getFontColor())
it.setColorFilter(ColorHelper.getFontColor())
}
// Text Size
@ -318,8 +351,8 @@ class TheWidget : AppWidgetProvider() {
v.second_row_icon.scaleX = Preferences.textSecondSize / 18f
v.second_row_icon.scaleY = Preferences.textSecondSize / 18f
v.weather_icon.scaleX = Preferences.textSecondSize / 18f
v.weather_icon.scaleY = Preferences.textSecondSize / 18f
v.weather_icon.scaleX = Preferences.textSecondSize / 16f
v.weather_icon.scaleY = Preferences.textSecondSize / 16f
v.empty_weather_icon.scaleX = 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.empty_weather_icon.visibility = View.GONE
} else {
v.weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon))
v.empty_weather_icon.setImageResource(WeatherUtil.getWeatherIconResource(icon))
v.weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
v.empty_weather_icon.setImageResource(WeatherHelper.getWeatherIconResource(icon))
v.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
}
// Apply max width
v.main_layout.layoutParams = RelativeLayout.LayoutParams(maxWidth, RelativeLayout.LayoutParams.WRAP_CONTENT)
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.AnimatorListenerAdapter
import android.app.Activity
import android.app.WallpaperManager
import android.content.*
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
@ -18,8 +19,15 @@ import android.util.Patterns
import java.security.NoSuchAlgorithmException
import kotlin.math.max
import android.content.Intent
import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.animation.Animation
import android.view.animation.Transformation
import android.widget.LinearLayout
import com.tommasoberlose.anotherwidget.R
import java.util.*
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 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) {
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 {
duration = 200
}
@ -48,7 +57,7 @@ fun View.reveal(initialX: Int, initialY: Int) {
})
anim.start()
} 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 {
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) {
try {
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.sendEmailTo(email: String) {
// val i = Intent(Intent.ACTION_VIEW).apply {
// data = Uri.parse("mailto:$email")
// }
// try {
// startActivity(Intent.createChooser(i, getString(R.string.settings_title_feedback)))
// } catch (ex: java.lang.Exception) {
// toast(getString(R.string.generic_error))
// }
//
//}
fun Float.convertDpToPixel(context: Context): Float {
val resources: Resources = context.resources
val metrics: DisplayMetrics = resources.displayMetrics
val px: Float = this * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)
return px
}
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:layout_centerVertical="true"
android:id="@+id/action_back"
android:layout_alignParentLeft="true"
android:tint="@color/colorPrimaryText"
android:src="@drawable/round_arrow_back" />
<TextView
@ -68,8 +69,9 @@
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:inputType="textCapWords"
android:textAlignment="viewStart"
android:id="@+id/search"
android:gravity="center_vertical"
android:gravity="center_vertical|start"
android:hint="@string/search"
android:text="@={viewModel.searchInput}"
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:foreground="?attr/selectableItemBackgroundBorderless"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:id="@+id/action_back"
android:tint="@color/colorPrimaryText"
android:src="@drawable/round_arrow_back" />
@ -69,8 +70,10 @@
android:paddingRight="16dp"
android:inputType="textCapWords"
android:id="@+id/location"
android:gravity="center_vertical"
android:gravity="center_vertical|start"
android:hint="@string/search"
android:textAlignment="viewStart"
android:textDirection="locale"
android:text="@={viewModel.locationInput}"
android:autofillHints="" />
</com.google.android.material.card.MaterialCardView>

View File

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

View File

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

View File

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

View File

@ -7,9 +7,13 @@
android:background="?attr/selectableItemBackground"
android:focusable="true"
android:clickable="true"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:orientation="horizontal"
android:id="@+id/item"
android:gravity="center_vertical">
android:gravity="center_vertical|start">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
@ -22,10 +26,14 @@
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_width="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"
style="@style/AnotherWidget.Settings.Title"/>
</LinearLayout>

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