Compare commits
4 Commits
v2.0.6-bet
...
v2.0.7
Author | SHA1 | Date | |
---|---|---|---|
1754b4045b | |||
9a63b9bde2 | |||
26428b65da | |||
97d1caeabc |
BIN
.idea/caches/build_file_checksums.ser
generated
2
.idea/gradle.xml
generated
@ -11,8 +11,6 @@
|
|||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
<option value="$PROJECT_DIR$/app" />
|
<option value="$PROJECT_DIR$/app" />
|
||||||
<option value="$PROJECT_DIR$/googlefit" />
|
|
||||||
<option value="$PROJECT_DIR$/tasksintegration" />
|
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
|
2
.idea/modules.xml
generated
@ -4,8 +4,6 @@
|
|||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/Another Widget.iml" filepath="$PROJECT_DIR$/Another Widget.iml" group="Another Widget" />
|
<module fileurl="file://$PROJECT_DIR$/Another Widget.iml" filepath="$PROJECT_DIR$/Another Widget.iml" group="Another Widget" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" />
|
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="Another Widget/app" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/googlefit/googlefit.iml" filepath="$PROJECT_DIR$/googlefit/googlefit.iml" group="Another Widget/googlefit" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/tasksintegration/tasksintegration.iml" filepath="$PROJECT_DIR$/tasksintegration/tasksintegration.iml" group="Another Widget/tasksintegration" />
|
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -10,6 +10,10 @@ apply plugin: 'kotlin-android-extensions'
|
|||||||
|
|
||||||
apply plugin: 'realm-android'
|
apply plugin: 'realm-android'
|
||||||
|
|
||||||
|
def apiKeyPropertiesFile = rootProject.file("apikey.properties")
|
||||||
|
def apiKeyProperties = new Properties()
|
||||||
|
apiKeyProperties.load(new FileInputStream(apiKeyPropertiesFile))
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 29
|
||||||
buildToolsVersion "29.0.3"
|
buildToolsVersion "29.0.3"
|
||||||
@ -18,10 +22,12 @@ android {
|
|||||||
applicationId "com.tommasoberlose.anotherwidget"
|
applicationId "com.tommasoberlose.anotherwidget"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 80
|
versionCode 84
|
||||||
versionName "2.0.6"
|
versionName "2.0.7"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
manifestPlaceholders = [ "AWARENESS_API_KEY": apiKeyProperties['AWARENESS_API_KEY']]
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -52,10 +58,6 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewBinding.enabled = true
|
viewBinding.enabled = true
|
||||||
|
|
||||||
dynamicFeatures = [":tasksintegration", ":googlefit"]
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -98,6 +100,10 @@ dependencies {
|
|||||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
||||||
|
|
||||||
|
// Fitness
|
||||||
|
implementation 'com.google.android.gms:play-services-fitness:18.0.0'
|
||||||
|
implementation 'com.google.android.gms:play-services-auth:18.0.0'
|
||||||
|
|
||||||
//Weather
|
//Weather
|
||||||
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
|
implementation 'com.github.KwabenBerko:OpenWeatherMap-Android-Library:2.0.2'
|
||||||
implementation 'com.google.android.gms:play-services-location:17.0.0'
|
implementation 'com.google.android.gms:play-services-location:17.0.0'
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="com.android.vending.BILLING" />
|
<uses-permission android:name="com.android.vending.BILLING" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
<uses-permission android:name="android.gms.permission.ACTIVITY_RECOGNITION"/>
|
||||||
|
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
|
||||||
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -146,6 +150,29 @@
|
|||||||
<action android:name="android.service.notification.NotificationListenerService" />
|
<action android:name="android.service.notification.NotificationListenerService" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.BatteryLevelReceiver"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
|
||||||
|
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
|
||||||
|
<action android:name="android.intent.action.BATTERY_LOW"/>
|
||||||
|
<action android:name="android.intent.action.BATTERY_OKAY"/>
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.FenceReceiver"
|
||||||
|
android:exported="false"
|
||||||
|
android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.mypackage.ACTION_PROCESS_ACTIVITY_TRANSITIONS" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.android.awareness.API_KEY"
|
||||||
|
android:value="${AWARENESS_API_KEY}"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -1,6 +1,7 @@
|
|||||||
package com.tommasoberlose.anotherwidget
|
package com.tommasoberlose.anotherwidget
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.util.Log
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import com.chibatching.kotpref.Kotpref
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import kotlinx.android.synthetic.main.custom_notes_dialog_layout.view.*
|
||||||
|
|
||||||
|
class CustomNotesDialog(context: Context) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
val view = View.inflate(context, R.layout.custom_notes_dialog_layout, null)
|
||||||
|
view.notes.setText(Preferences.customNotes)
|
||||||
|
|
||||||
|
view.action_positive.setOnClickListener {
|
||||||
|
Preferences.customNotes = view.notes.text.toString()
|
||||||
|
this.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
view.notes.requestFocus()
|
||||||
|
|
||||||
|
setContentView(view)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.isColorDark
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.models.GlanceProvider
|
||||||
|
import kotlinx.android.synthetic.main.glance_provider_sort_bottom_menu.view.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import net.idik.lib.slimadapter.SlimAdapter
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
class GlanceProviderSortMenu(
|
||||||
|
context: Context
|
||||||
|
) : BottomSheetDialog(context, R.style.BottomSheetDialogTheme) {
|
||||||
|
|
||||||
|
private lateinit var adapter: SlimAdapter
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
val view = View.inflate(context, R.layout.glance_provider_sort_bottom_menu, null)
|
||||||
|
|
||||||
|
// Header
|
||||||
|
view.header_text.text = context.getString(R.string.settings_sort_glance_providers_title)
|
||||||
|
|
||||||
|
// List
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
|
||||||
|
view.menu.setHasFixedSize(true)
|
||||||
|
val mLayoutManager = LinearLayoutManager(context)
|
||||||
|
view.menu.layoutManager = mLayoutManager
|
||||||
|
|
||||||
|
adapter = SlimAdapter.create()
|
||||||
|
adapter
|
||||||
|
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
|
||||||
|
injector
|
||||||
|
.text(R.id.title, item.title)
|
||||||
|
.with<ImageView>(R.id.icon) {
|
||||||
|
it.setImageDrawable(ContextCompat.getDrawable(context, item.icon))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.attachTo(view.menu)
|
||||||
|
|
||||||
|
val mIth = ItemTouchHelper(
|
||||||
|
object : ItemTouchHelper.SimpleCallback(
|
||||||
|
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
|
||||||
|
ItemTouchHelper.LEFT
|
||||||
|
) {
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder
|
||||||
|
): Boolean {
|
||||||
|
val fromPos = viewHolder.adapterPosition
|
||||||
|
val toPos = target.adapterPosition
|
||||||
|
// move item in `fromPos` to `toPos` in adapter.
|
||||||
|
adapter.notifyItemMoved(fromPos, toPos)
|
||||||
|
|
||||||
|
val list = GlanceProviderHelper.getGlanceProviders()
|
||||||
|
Collections.swap(list, fromPos, toPos)
|
||||||
|
GlanceProviderHelper.saveGlanceProviderOrder(list)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSwiped(
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
direction: Int
|
||||||
|
) {
|
||||||
|
// remove from adapter
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
mIth.attachToRecyclerView(view.menu)
|
||||||
|
|
||||||
|
adapter.updateData(
|
||||||
|
GlanceProviderHelper.getGlanceProviders()
|
||||||
|
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(context, it) }
|
||||||
|
)
|
||||||
|
|
||||||
|
setContentView(view)
|
||||||
|
super.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
package com.tommasoberlose.anotherwidget.db
|
package com.tommasoberlose.anotherwidget.db
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
import com.chibatching.kotpref.bulk
|
import com.chibatching.kotpref.bulk
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.models.Event
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
@ -8,6 +9,8 @@ import com.tommasoberlose.anotherwidget.receivers.UpdatesReceiver
|
|||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmResults
|
import io.realm.RealmResults
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class EventRepository(val context: Context) {
|
class EventRepository(val context: Context) {
|
||||||
private val realm by lazy { Realm.getDefaultInstance() }
|
private val realm by lazy { Realm.getDefaultInstance() }
|
||||||
@ -36,22 +39,36 @@ class EventRepository(val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun saveNextEventData(event: Event) {
|
fun saveNextEventData(event: Event) {
|
||||||
Preferences.nextEventId = event.id
|
Preferences.nextEventId = event.eventID
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNextEvent(): Event? = realm.where(Event::class.java).equalTo("id", Preferences.nextEventId).findFirst() ?: realm.where(Event::class.java).findFirst()
|
fun getNextEvent(): Event? {
|
||||||
|
val nextEvent = getEventByEventId(Preferences.nextEventId)
|
||||||
|
return if (nextEvent != null && nextEvent.endDate > Calendar.getInstance().timeInMillis) {
|
||||||
|
nextEvent
|
||||||
|
} else {
|
||||||
|
val events = getEvents()
|
||||||
|
if (events.isNotEmpty()) {
|
||||||
|
val newNextEvent = events.first()
|
||||||
|
Preferences.nextEventId = newNextEvent!!.eventID
|
||||||
|
newNextEvent
|
||||||
|
} else {
|
||||||
|
resetNextEventData()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getEventByEventId(id: Long): Event? = realm.where(Event::class.java).equalTo("eventID", id).findFirst()
|
fun getEventByEventId(id: Long): Event? = realm.where(Event::class.java).equalTo("eventID", id).findFirst()
|
||||||
|
|
||||||
fun goToNextEvent() {
|
fun goToNextEvent() {
|
||||||
val eventList = realm.where(Event::class.java).findAll()
|
val eventList = getEvents()
|
||||||
|
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
|
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
|
||||||
if (index > -1 && index < eventList.size - 1) {
|
if (index > -1 && index < eventList.size - 1) {
|
||||||
Preferences.nextEventId = eventList[index + 1]!!.id
|
Preferences.nextEventId = eventList[index + 1]!!.eventID
|
||||||
} else {
|
} else {
|
||||||
Preferences.nextEventId = eventList.first()!!.id
|
Preferences.nextEventId = eventList.first()!!.eventID
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resetNextEventData()
|
resetNextEventData()
|
||||||
@ -61,14 +78,13 @@ class EventRepository(val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun goToPreviousEvent() {
|
fun goToPreviousEvent() {
|
||||||
val eventList = realm.where(Event::class.java).findAll()
|
val eventList = getEvents()
|
||||||
|
|
||||||
if (eventList.isNotEmpty()) {
|
if (eventList.isNotEmpty()) {
|
||||||
val index = eventList.indexOfFirst { it.id == Preferences.nextEventId }
|
val index = eventList.indexOfFirst { it.eventID == Preferences.nextEventId }
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
Preferences.nextEventId = eventList[index - 1]!!.id
|
Preferences.nextEventId = eventList[index - 1]!!.eventID
|
||||||
} else {
|
} else {
|
||||||
Preferences.nextEventId = eventList.last()!!.id
|
Preferences.nextEventId = eventList.last()!!.eventID
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resetNextEventData()
|
resetNextEventData()
|
||||||
@ -77,7 +93,10 @@ class EventRepository(val context: Context) {
|
|||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEvents(): RealmResults<Event> = realm.where(Event::class.java).findAll()
|
fun getEvents(): RealmResults<Event> {
|
||||||
|
val now = Calendar.getInstance().timeInMillis
|
||||||
|
return realm.where(Event::class.java).greaterThan("endDate", now).findAll()
|
||||||
|
}
|
||||||
|
|
||||||
fun getEventsCount(): Int = realm.where(Event::class.java).findAll().size
|
fun getEventsCount(): Int = getEvents().size
|
||||||
}
|
}
|
@ -14,4 +14,12 @@ object Constants {
|
|||||||
MEDIUM(2),
|
MEDIUM(2),
|
||||||
LARGE(3)
|
LARGE(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class GlanceProviderId(val id: String) {
|
||||||
|
PLAYING_SONG("PLAYING_SONG"),
|
||||||
|
NEXT_CLOCK_ALARM("NEXT_CLOCK_ALARM"),
|
||||||
|
BATTERY_LEVEL_LOW("BATTERY_LEVEL_LOW"),
|
||||||
|
CUSTOM_INFO("CUSTOM_INFO"),
|
||||||
|
GOOGLE_FIT_STEPS("GOOGLE_FIT_STEPS")
|
||||||
|
}
|
||||||
}
|
}
|
@ -48,6 +48,7 @@ object Preferences : KotprefModel() {
|
|||||||
|
|
||||||
var clockTextColor by stringPref(default = "#FFFFFF")
|
var clockTextColor by stringPref(default = "#FFFFFF")
|
||||||
var clockTextAlpha by stringPref(default = "FF")
|
var clockTextAlpha by stringPref(default = "FF")
|
||||||
|
var showAMPMIndicator by booleanPref(default = true)
|
||||||
|
|
||||||
// Global
|
// Global
|
||||||
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
|
var textMainSize by floatPref(key = "PREF_TEXT_MAIN_SIZE", default = 26f)
|
||||||
@ -57,7 +58,6 @@ object Preferences : KotprefModel() {
|
|||||||
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
|
var showClock by booleanPref(key = "PREF_SHOW_CLOCK", default = false)
|
||||||
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
|
var clockAppName by stringPref(key = "PREF_CLOCK_APP_NAME", default = "")
|
||||||
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")
|
var clockAppPackage by stringPref(key = "PREF_CLOCK_APP_PACKAGE", default = "")
|
||||||
var showNextAlarm by booleanPref(default = false)
|
|
||||||
var textShadow by intPref(key = "PREF_TEXT_SHADOW", default = 1)
|
var textShadow by intPref(key = "PREF_TEXT_SHADOW", default = 1)
|
||||||
var showDiffTime by booleanPref(key = "PREF_SHOW_DIFF_TIME", default = true)
|
var showDiffTime by booleanPref(key = "PREF_SHOW_DIFF_TIME", default = true)
|
||||||
var showDeclinedEvents by booleanPref(key = "PREF_SHOW_DECLINED_EVENTS", default = false)
|
var showDeclinedEvents by booleanPref(key = "PREF_SHOW_DECLINED_EVENTS", default = false)
|
||||||
@ -66,6 +66,8 @@ object Preferences : KotprefModel() {
|
|||||||
var customFontFile by stringPref(key = "PREF_CUSTOM_FONT_FILE")
|
var customFontFile by stringPref(key = "PREF_CUSTOM_FONT_FILE")
|
||||||
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
|
var showNextEvent by booleanPref(key = "PREF_SHOW_NEXT_EVENT", default = true)
|
||||||
|
|
||||||
|
var showDividers by booleanPref(default = true)
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
var showWallpaper by booleanPref(default = true)
|
var showWallpaper by booleanPref(default = true)
|
||||||
var showBigClockWarning by booleanPref(default = true)
|
var showBigClockWarning by booleanPref(default = true)
|
||||||
@ -73,7 +75,16 @@ object Preferences : KotprefModel() {
|
|||||||
var showPreview by booleanPref(default = true)
|
var showPreview by booleanPref(default = true)
|
||||||
var showXiaomiWarning by booleanPref(default = true)
|
var showXiaomiWarning by booleanPref(default = true)
|
||||||
|
|
||||||
// Music
|
// Glance
|
||||||
|
var showGlance by booleanPref(default = true)
|
||||||
|
var enabledGlanceProviderOrder by stringPref(default = "")
|
||||||
|
var customNotes by stringPref(default = "")
|
||||||
|
var showNextAlarm by booleanPref(default = true)
|
||||||
|
var showBatteryCharging by booleanPref(default = false)
|
||||||
|
var isBatteryLevelLow by booleanPref(default = false)
|
||||||
|
var googleFitSteps by longPref(default = -1)
|
||||||
|
var showDailySteps by booleanPref(default = false)
|
||||||
|
|
||||||
var showMusic by booleanPref(default = false)
|
var showMusic by booleanPref(default = false)
|
||||||
var mediaInfoFormat by stringPref(default = "")
|
var mediaInfoFormat by stringPref(default = "")
|
||||||
var mediaPlayerTitle by stringPref(default = "")
|
var mediaPlayerTitle by stringPref(default = "")
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import com.google.android.gms.location.ActivityRecognition
|
||||||
|
import com.google.android.gms.location.ActivityTransition
|
||||||
|
import com.google.android.gms.location.ActivityTransitionRequest
|
||||||
|
import com.google.android.gms.location.DetectedActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.receivers.FenceReceiver
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
|
||||||
|
|
||||||
|
object DailyStepsHelper {
|
||||||
|
fun registerFence(context: Context) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || context.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION)) {
|
||||||
|
val transitions = mutableListOf<ActivityTransition>()
|
||||||
|
|
||||||
|
transitions +=
|
||||||
|
ActivityTransition.Builder()
|
||||||
|
.setActivityType(DetectedActivity.WALKING)
|
||||||
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
transitions +=
|
||||||
|
ActivityTransition.Builder()
|
||||||
|
.setActivityType(DetectedActivity.WALKING)
|
||||||
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
transitions +=
|
||||||
|
ActivityTransition.Builder()
|
||||||
|
.setActivityType(DetectedActivity.RUNNING)
|
||||||
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
transitions +=
|
||||||
|
ActivityTransition.Builder()
|
||||||
|
.setActivityType(DetectedActivity.RUNNING)
|
||||||
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
transitions +=
|
||||||
|
ActivityTransition.Builder()
|
||||||
|
.setActivityType(DetectedActivity.STILL)
|
||||||
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val request = ActivityTransitionRequest(transitions)
|
||||||
|
|
||||||
|
// myPendingIntent is the instance of PendingIntent where the app receives callbacks.
|
||||||
|
val task = ActivityRecognition.getClient(context)
|
||||||
|
.requestActivityTransitionUpdates(
|
||||||
|
request,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
2,
|
||||||
|
Intent(context, FenceReceiver::class.java),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
task.addOnFailureListener { e: Exception ->
|
||||||
|
e.printStackTrace()
|
||||||
|
Preferences.showDailySteps = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unregisterFence(context: Context) {
|
||||||
|
val task = ActivityRecognition.getClient(context)
|
||||||
|
.removeActivityTransitionUpdates(
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
2,
|
||||||
|
Intent(context, FenceReceiver::class.java),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
task.addOnCompleteListener {
|
||||||
|
if (it.isSuccessful) {
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
2,
|
||||||
|
Intent(context, FenceReceiver::class.java),
|
||||||
|
0
|
||||||
|
).cancel()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.helpers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.tommasoberlose.anotherwidget.R
|
||||||
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.models.GlanceProvider
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
object GlanceProviderHelper {
|
||||||
|
fun getGlanceProviders(): ArrayList<Constants.GlanceProviderId> {
|
||||||
|
val enabledProviders = Preferences.enabledGlanceProviderOrder.split(",").filter { it != "" }
|
||||||
|
val providers = Constants.GlanceProviderId.values()
|
||||||
|
|
||||||
|
providers.sortWith(Comparator { p1, p2 ->
|
||||||
|
when {
|
||||||
|
enabledProviders.contains(p1.id) && enabledProviders.contains(p2.id) -> {
|
||||||
|
enabledProviders.indexOf(p1.id).compareTo(enabledProviders.indexOf(p2.id))
|
||||||
|
}
|
||||||
|
enabledProviders.contains(p1.id) -> {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
enabledProviders.contains(p2.id) -> {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
p1.id.compareTo(p2.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return ArrayList(providers.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getGlanceProviderById(context: Context, providerId: Constants.GlanceProviderId): GlanceProvider? {
|
||||||
|
return when(providerId) {
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_next_alarm_title),
|
||||||
|
R.drawable.round_alarm
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_show_music_title),
|
||||||
|
R.drawable.round_music_note
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_custom_notes_title),
|
||||||
|
R.drawable.round_notes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_low_battery_level_title),
|
||||||
|
R.drawable.round_battery_charging_full
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
|
GlanceProvider(providerId.id,
|
||||||
|
context.getString(R.string.settings_daily_steps_title),
|
||||||
|
R.drawable.round_directions_walk
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveGlanceProviderOrder(list: ArrayList<Constants.GlanceProviderId>) {
|
||||||
|
Preferences.enabledGlanceProviderOrder = list.joinToString(separator = ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showGlanceProviders(context: Context): Boolean {
|
||||||
|
return Preferences.showGlance && EventRepository(context).getEventsCount() == 0 && (
|
||||||
|
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
|
||||||
|
(MediaPlayerHelper.isSomeonePlaying(context)) ||
|
||||||
|
(Preferences.isBatteryLevelLow) ||
|
||||||
|
(Preferences.customNotes.isNotEmpty()) ||
|
||||||
|
(Preferences.showDailySteps && Preferences.googleFitSteps > 0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -53,11 +53,4 @@ object WidgetHelper {
|
|||||||
width to second * factor
|
width to second * factor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showSpecialWeather(context: Context): Boolean {
|
|
||||||
return EventRepository(context).getEventsCount() == 0 && (
|
|
||||||
(Preferences.showNextAlarm && AlarmHelper.getNextAlarm(context) != "") ||
|
|
||||||
(MediaPlayerHelper.isSomeonePlaying(context))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.models
|
||||||
|
|
||||||
|
class GlanceProvider(
|
||||||
|
val id: String,
|
||||||
|
val title: String,
|
||||||
|
val icon: Int
|
||||||
|
)
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.receivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.BatteryManager
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
|
||||||
|
class BatteryLevelReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
when(intent.action) {
|
||||||
|
Intent.ACTION_BATTERY_LOW -> Preferences.isBatteryLevelLow = true
|
||||||
|
Intent.ACTION_BATTERY_OKAY -> Preferences.isBatteryLevelLow = false
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.receivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||||
|
import com.google.android.gms.fitness.Fitness
|
||||||
|
import com.google.android.gms.fitness.FitnessOptions
|
||||||
|
import com.google.android.gms.fitness.data.DataSource
|
||||||
|
import com.google.android.gms.fitness.data.DataType
|
||||||
|
import com.google.android.gms.fitness.data.Field.FIELD_STEPS
|
||||||
|
import com.google.android.gms.fitness.request.DataReadRequest
|
||||||
|
import com.google.android.gms.location.ActivityTransitionResult
|
||||||
|
import com.google.android.gms.location.DetectedActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
|
class FenceReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (ActivityTransitionResult.hasResult(intent)) {
|
||||||
|
val result = ActivityTransitionResult.extractResult(intent)!!
|
||||||
|
val lastEvent = result.transitionEvents.last()
|
||||||
|
|
||||||
|
if (lastEvent.activityType == DetectedActivity.WALKING || lastEvent.activityType == DetectedActivity.RUNNING) {
|
||||||
|
requestDailySteps(context)
|
||||||
|
} else {
|
||||||
|
resetDailySteps()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestDailySteps(context: Context) {
|
||||||
|
val fitnessOptions = FitnessOptions.builder()
|
||||||
|
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
|
||||||
|
.addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(context)
|
||||||
|
|
||||||
|
Log.d("ciao", "hasPermission: ${GoogleSignIn.hasPermissions(account, fitnessOptions)}")
|
||||||
|
|
||||||
|
if (GoogleSignIn.hasPermissions(account, fitnessOptions)) {
|
||||||
|
val cal: Calendar = Calendar.getInstance()
|
||||||
|
cal.time = Date()
|
||||||
|
val endTime: Long = cal.timeInMillis
|
||||||
|
cal.add(Calendar.YEAR, -1)
|
||||||
|
val startTime: Long = cal.timeInMillis
|
||||||
|
val readRequest = DataReadRequest.Builder()
|
||||||
|
.aggregate(
|
||||||
|
DataType.TYPE_STEP_COUNT_DELTA,
|
||||||
|
DataType.AGGREGATE_STEP_COUNT_DELTA
|
||||||
|
)
|
||||||
|
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
|
||||||
|
.bucketByTime(1, TimeUnit.DAYS)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
if (account != null) {
|
||||||
|
Fitness.getHistoryClient(context, account)
|
||||||
|
.readData(readRequest)
|
||||||
|
.addOnSuccessListener { response ->
|
||||||
|
Preferences.googleFitSteps =
|
||||||
|
response.dataSets[0].dataPoints[0].getValue(FIELD_STEPS).asFloat()
|
||||||
|
.toLong()
|
||||||
|
Log.d("ciao",
|
||||||
|
"response: ${response.dataSets[0].dataPoints[0].getValue(FIELD_STEPS)
|
||||||
|
.asFloat().toLong()}"
|
||||||
|
)
|
||||||
|
MainWidget.updateWidget(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetDailySteps() {
|
||||||
|
Preferences.googleFitSteps = -1
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat.getSystemService
|
|||||||
import com.tommasoberlose.anotherwidget.db.EventRepository
|
import com.tommasoberlose.anotherwidget.db.EventRepository
|
||||||
import com.tommasoberlose.anotherwidget.global.Actions
|
import com.tommasoberlose.anotherwidget.global.Actions
|
||||||
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
import com.tommasoberlose.anotherwidget.helpers.CalendarHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.models.Event
|
||||||
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
import com.tommasoberlose.anotherwidget.ui.widgets.MainWidget
|
||||||
import org.joda.time.Period
|
import org.joda.time.Period
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -32,47 +33,69 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED,
|
||||||
Actions.ACTION_TIME_UPDATE -> {
|
Actions.ACTION_TIME_UPDATE -> {
|
||||||
MainWidget.updateWidget(context)
|
MainWidget.updateWidget(context)
|
||||||
|
if (intent.hasExtra(EVENT_ID)) {
|
||||||
|
setUpdates(context, intent.getLongExtra(EVENT_ID, -1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val EVENT_ID = "EVENT_ID"
|
||||||
|
|
||||||
fun setUpdates(context: Context) {
|
fun setUpdates(context: Context, eventId: Long? = null) {
|
||||||
removeUpdates(context)
|
|
||||||
|
|
||||||
|
|
||||||
val eventRepository = EventRepository(context)
|
val eventRepository = EventRepository(context)
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
if (eventId == null) {
|
||||||
eventRepository.getEvents().forEach { event ->
|
removeUpdates(context)
|
||||||
val now = Calendar.getInstance().apply {
|
|
||||||
set(Calendar.SECOND, 0)
|
|
||||||
set(Calendar.MILLISECOND, 0)
|
|
||||||
}
|
|
||||||
val diff = Period(now.timeInMillis, event.startDate)
|
|
||||||
if (event.startDate > now.timeInMillis) {
|
|
||||||
// Update the widget every hour till the event
|
|
||||||
(0..diff.hours).forEach {
|
|
||||||
setExactAndAllowWhileIdle(
|
|
||||||
AlarmManager.RTC,
|
|
||||||
if (event.startDate - it * 1000 * 60 * 60 > 60 * 1000) event.startDate - it * 1000 * 60 * 60 else now.timeInMillis + 120000,
|
|
||||||
PendingIntent.getBroadcast(
|
|
||||||
context,
|
|
||||||
event.eventID.toInt() + it,
|
|
||||||
Intent(context, UpdatesReceiver::class.java).apply {
|
|
||||||
action = Actions.ACTION_TIME_UPDATE
|
|
||||||
},
|
|
||||||
0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the widget one second after the event is finished
|
eventRepository.getEvents().forEach { event ->
|
||||||
|
setEventUpdate(context, event)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val event = eventRepository.getEventByEventId(eventId)
|
||||||
|
if (event != null) {
|
||||||
|
setEventUpdate(context, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setEventUpdate(context: Context, event: Event) {
|
||||||
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val now = Calendar.getInstance().apply {
|
||||||
|
set(Calendar.SECOND, 0)
|
||||||
|
set(Calendar.MILLISECOND, 0)
|
||||||
|
}
|
||||||
|
val diff = Period(now.timeInMillis, event.startDate)
|
||||||
|
if (event.startDate > now.timeInMillis) {
|
||||||
|
// Update the widget every hour till the event
|
||||||
setExactAndAllowWhileIdle(
|
setExactAndAllowWhileIdle(
|
||||||
AlarmManager.RTC,
|
AlarmManager.RTC,
|
||||||
if (event.endDate > 60 *1000) event.endDate else now.timeInMillis + 120000,
|
if (event.startDate - diff.hours * 1000 * 60 * 60 > (now.timeInMillis + 120 * 1000)) event.startDate - diff.hours * 1000 * 60 * 60 else now.timeInMillis + 120000,
|
||||||
PendingIntent.getBroadcast(context, 1, Intent(context, UpdatesReceiver::class.java).apply { action = Actions.ACTION_TIME_UPDATE }, 0)
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
event.eventID.toInt(),
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_TIME_UPDATE
|
||||||
|
putExtra(EVENT_ID, event.eventID)
|
||||||
|
},
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Update the widget one second after the event is finished
|
||||||
|
val fireTime =
|
||||||
|
if (event.endDate > now.timeInMillis + 120 * 1000) event.endDate else now.timeInMillis + 120000
|
||||||
|
setExactAndAllowWhileIdle(
|
||||||
|
AlarmManager.RTC,
|
||||||
|
fireTime,
|
||||||
|
PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
event.eventID.toInt(),
|
||||||
|
Intent(context, UpdatesReceiver::class.java).apply {
|
||||||
|
action = Actions.ACTION_TIME_UPDATE
|
||||||
|
},
|
||||||
|
0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,11 +103,8 @@ class UpdatesReceiver : BroadcastReceiver() {
|
|||||||
|
|
||||||
fun removeUpdates(context: Context) {
|
fun removeUpdates(context: Context) {
|
||||||
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
cancel(PendingIntent.getBroadcast(context, 1, Intent(context, UpdatesReceiver::class.java), 0))
|
|
||||||
EventRepository(context).getEvents().forEach {
|
EventRepository(context).getEvents().forEach {
|
||||||
(0..24).forEach { hour ->
|
cancel(PendingIntent.getBroadcast(context, it.eventID.toInt(), Intent(context, UpdatesReceiver::class.java), 0))
|
||||||
cancel(PendingIntent.getBroadcast(context, it.eventID.toInt() * hour, Intent(context, UpdatesReceiver::class.java), 0))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
|
import com.chibatching.kotpref.Kotpref
|
||||||
import com.google.android.material.badge.BadgeDrawable
|
import com.google.android.material.badge.BadgeDrawable
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import com.karumi.dexter.Dexter
|
import com.karumi.dexter.Dexter
|
||||||
|
@ -15,7 +15,7 @@ class ViewPagerAdapter(fragmentActivity: FragmentActivity) :
|
|||||||
1 -> CalendarTabFragment.newInstance()
|
1 -> CalendarTabFragment.newInstance()
|
||||||
2 -> WeatherTabFragment.newInstance()
|
2 -> WeatherTabFragment.newInstance()
|
||||||
3 -> ClockTabFragment.newInstance()
|
3 -> ClockTabFragment.newInstance()
|
||||||
4 -> AtAGlanceTabFragment.newInstance()
|
4 -> GlanceTabFragment.newInstance()
|
||||||
else -> GeneralTabFragment.newInstance()
|
else -> GeneralTabFragment.newInstance()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,165 +0,0 @@
|
|||||||
package com.tommasoberlose.anotherwidget.ui.fragments
|
|
||||||
|
|
||||||
import android.app.AlarmManager
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.databinding.DataBindingUtil
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.tommasoberlose.anotherwidget.R
|
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentAtAGlanceSettingsBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
|
||||||
import kotlinx.android.synthetic.main.fragment_at_a_glance_settings.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_at_a_glance_settings.scrollView
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.lang.Exception
|
|
||||||
|
|
||||||
class AtAGlanceTabFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance() = AtAGlanceTabFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
|
||||||
val binding = DataBindingUtil.inflate<FragmentAtAGlanceSettingsBinding>(inflater, R.layout.fragment_at_a_glance_settings, container, false)
|
|
||||||
|
|
||||||
subscribeUi(binding, viewModel)
|
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
|
||||||
binding.viewModel = viewModel
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
|
|
||||||
setupListener()
|
|
||||||
updateNextAlarmWarningUi()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun subscribeUi(
|
|
||||||
binding: FragmentAtAGlanceSettingsBinding,
|
|
||||||
viewModel: MainViewModel
|
|
||||||
) {
|
|
||||||
|
|
||||||
viewModel.showMusic.observe(viewLifecycleOwner, Observer {
|
|
||||||
checkNotificationPermission()
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
|
|
||||||
updateNextAlarmWarningUi()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupListener() {
|
|
||||||
action_show_music.setOnClickListener {
|
|
||||||
Preferences.showMusic = !Preferences.showMusic
|
|
||||||
}
|
|
||||||
|
|
||||||
action_show_next_alarm.setOnClickListener {
|
|
||||||
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 ->
|
|
||||||
Preferences.showNextAlarm = value
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateNextAlarmWarningUi() {
|
|
||||||
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
|
||||||
val alarm = nextAlarmClock
|
|
||||||
if (AlarmHelper.isAlarmProbablyWrong(requireContext()) && alarm != null && alarm.showIntent != null) {
|
|
||||||
val pm = requireContext().packageManager as PackageManager
|
|
||||||
val appNameOrPackage = try {
|
|
||||||
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
alarm.showIntent?.creatorPackage ?: ""
|
|
||||||
}
|
|
||||||
show_next_alarm_warning.text = getString(R.string.next_alarm_warning).format(appNameOrPackage)
|
|
||||||
} else {
|
|
||||||
maintainScrollPosition {
|
|
||||||
show_next_alarm_label?.text = if (Preferences.showNextAlarm) getString(R.string.settings_visible) else getString(
|
|
||||||
R.string.settings_not_visible)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
|
||||||
updateNextAlarmWarningUi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
activity?.unregisterReceiver(nextAlarmChangeBroadcastReceiver)
|
|
||||||
super.onStop()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkNotificationPermission() {
|
|
||||||
if (NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)) {
|
|
||||||
notification_permission_alert?.isVisible = false
|
|
||||||
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
|
||||||
show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_show_music_enabled_subtitle) else getString(R.string.settings_show_music_disabled_subtitle)
|
|
||||||
} else if (Preferences.showMusic) {
|
|
||||||
notification_permission_alert?.isVisible = true
|
|
||||||
show_music_label?.text = getString(R.string.settings_request_notification_access)
|
|
||||||
notification_permission_alert?.setOnClickListener {
|
|
||||||
activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
show_music_label?.text = getString(R.string.settings_show_music_disabled_subtitle)
|
|
||||||
notification_permission_alert?.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
|
||||||
val scrollPosition = scrollView.scrollY
|
|
||||||
callback.invoke()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
delay(200)
|
|
||||||
scrollView.smoothScrollTo(0, scrollPosition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
checkNotificationPermission()
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,6 +4,7 @@ import android.Manifest
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -128,12 +129,9 @@ class CalendarTabFragment : Fragment() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
|
viewModel.showNextEvent.observe(viewLifecycleOwner, Observer {
|
||||||
show_multiple_events_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
|
||||||
})
|
|
||||||
|
|
||||||
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
|
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
|
show_multiple_events_label?.text =
|
||||||
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -160,6 +158,13 @@ class CalendarTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
show_events_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
|
Preferences.showEvents = enabled
|
||||||
|
if (Preferences.showEvents) {
|
||||||
|
requirePermission()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
action_filter_calendar.setOnClickListener {
|
action_filter_calendar.setOnClickListener {
|
||||||
val calendarSelectorList: List<CalendarSelector> = CalendarHelper.getCalendarList(requireContext()).map {
|
val calendarSelectorList: List<CalendarSelector> = CalendarHelper.getCalendarList(requireContext()).map {
|
||||||
CalendarSelector(
|
CalendarSelector(
|
||||||
@ -270,7 +275,7 @@ class CalendarTabFragment : Fragment() {
|
|||||||
action_show_until.setOnClickListener {
|
action_show_until.setOnClickListener {
|
||||||
if (Preferences.showEvents) {
|
if (Preferences.showEvents) {
|
||||||
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
|
val dialog = BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_until_title)).setSelectedValue(Preferences.showUntil)
|
||||||
intArrayOf(6,7,0,1,2).forEach {
|
intArrayOf(6,7,0,1,2,3).forEach {
|
||||||
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
|
dialog.addItem(getString(SettingsStringHelper.getShowUntilString(it)), it)
|
||||||
}
|
}
|
||||||
dialog.addOnSelectItemListener { value ->
|
dialog.addOnSelectItemListener { value ->
|
||||||
@ -279,27 +284,6 @@ class CalendarTabFragment : 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(requireContext(), CustomDateActivity::class.java))
|
|
||||||
} else {
|
|
||||||
Preferences.dateFormat = value
|
|
||||||
}
|
|
||||||
}.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
action_open_event_details.setOnClickListener {
|
action_open_event_details.setOnClickListener {
|
||||||
if (Preferences.showEvents) {
|
if (Preferences.showEvents) {
|
||||||
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
|
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_event_app_title)).setSelectedValue(Preferences.openEventDetails)
|
||||||
@ -339,6 +323,8 @@ class CalendarTabFragment : Fragment() {
|
|||||||
report?.let {
|
report?.let {
|
||||||
if (report.areAllPermissionsGranted()){
|
if (report.areAllPermissionsGranted()){
|
||||||
checkReadEventsPermission()
|
checkReadEventsPermission()
|
||||||
|
} else {
|
||||||
|
Preferences.showEvents = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,12 @@ class ClockTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewModel.showAMPMIndicator.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
ampm_indicator_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
viewModel.clockTextColor.observe(viewLifecycleOwner, Observer {
|
viewModel.clockTextColor.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
if (Preferences.clockTextAlpha == "00") {
|
if (Preferences.clockTextAlpha == "00") {
|
||||||
@ -154,6 +160,10 @@ class ClockTabFragment : Fragment() {
|
|||||||
Preferences.showClock = !Preferences.showClock
|
Preferences.showClock = !Preferences.showClock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
show_clock_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
|
Preferences.showClock = enabled
|
||||||
|
}
|
||||||
|
|
||||||
action_clock_text_size.setOnClickListener {
|
action_clock_text_size.setOnClickListener {
|
||||||
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.settings_clock_text_size_title)).setSelectedValue(Preferences.clockTextSize)
|
val dialog = BottomSheetMenu<Float>(requireContext(), header = getString(R.string.settings_clock_text_size_title)).setSelectedValue(Preferences.clockTextSize)
|
||||||
(46 downTo 12).filter { it % 2 == 0 }.forEach {
|
(46 downTo 12).filter { it % 2 == 0 }.forEach {
|
||||||
@ -164,6 +174,15 @@ class ClockTabFragment : Fragment() {
|
|||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action_ampm_indicator_size.setOnClickListener {
|
||||||
|
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_ampm_indicator_title)).setSelectedValue(Preferences.showAMPMIndicator)
|
||||||
|
.addItem(getString(R.string.settings_visible), true)
|
||||||
|
.addItem(getString(R.string.settings_not_visible), false)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.showAMPMIndicator = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
action_clock_text_color.setOnClickListener {
|
action_clock_text_color.setOnClickListener {
|
||||||
BottomSheetColorPicker(requireContext(),
|
BottomSheetColorPicker(requireContext(),
|
||||||
colors = colors,
|
colors = colors,
|
||||||
@ -182,7 +201,7 @@ class ClockTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
action_clock_bottom_margin_size.setOnClickListener {
|
action_clock_bottom_margin_size.setOnClickListener {
|
||||||
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_show_next_alarm_title)).setSelectedValue(Preferences.clockBottomMargin)
|
BottomSheetMenu<Int>(requireContext(), header = getString(R.string.settings_clock_bottom_margin_title)).setSelectedValue(Preferences.clockBottomMargin)
|
||||||
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_none), Constants.ClockBottomMargin.NONE.value)
|
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_none), Constants.ClockBottomMargin.NONE.value)
|
||||||
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_small), Constants.ClockBottomMargin.SMALL.value)
|
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_small), Constants.ClockBottomMargin.SMALL.value)
|
||||||
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_medium), Constants.ClockBottomMargin.MEDIUM.value)
|
.addItem(getString(R.string.settings_clock_bottom_margin_subtitle_medium), Constants.ClockBottomMargin.MEDIUM.value)
|
||||||
|
@ -21,7 +21,9 @@ import com.tommasoberlose.anotherwidget.global.RequestCode
|
|||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toHexValue
|
||||||
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
import com.tommasoberlose.anotherwidget.helpers.ColorHelper.toIntValue
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.DateHelper
|
||||||
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
import com.tommasoberlose.anotherwidget.helpers.SettingsStringHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.CustomDateActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
import kotlinx.android.synthetic.main.fragment_general_settings.*
|
import kotlinx.android.synthetic.main.fragment_general_settings.*
|
||||||
@ -29,6 +31,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class GeneralTabFragment : Fragment() {
|
class GeneralTabFragment : Fragment() {
|
||||||
@ -141,11 +144,24 @@ class GeneralTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewModel.dateFormat.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
date_format_label?.text = DateHelper.getDateText(requireContext(), Calendar.getInstance())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
viewModel.customFont.observe(viewLifecycleOwner, Observer {
|
viewModel.customFont.observe(viewLifecycleOwner, Observer {
|
||||||
maintainScrollPosition {
|
maintainScrollPosition {
|
||||||
custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it))
|
custom_font_label?.text = getString(SettingsStringHelper.getCustomFontLabel(it))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewModel.showDividers.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
show_dividers_label?.text =
|
||||||
|
if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maintainScrollPosition(callback: () -> Unit) {
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
@ -195,6 +211,27 @@ class GeneralTabFragment : Fragment() {
|
|||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(requireContext(), CustomDateActivity::class.java))
|
||||||
|
} else {
|
||||||
|
Preferences.dateFormat = value
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
action_background_color.setOnClickListener {
|
action_background_color.setOnClickListener {
|
||||||
BottomSheetColorPicker(requireContext(),
|
BottomSheetColorPicker(requireContext(),
|
||||||
colors = colors,
|
colors = colors,
|
||||||
@ -243,6 +280,15 @@ class GeneralTabFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action_show_dividers.setOnClickListener {
|
||||||
|
BottomSheetMenu<Boolean>(requireContext(), header = getString(R.string.settings_show_multiple_events_title)).setSelectedValue(Preferences.showDividers)
|
||||||
|
.addItem(getString(R.string.settings_visible), true)
|
||||||
|
.addItem(getString(R.string.settings_not_visible), false)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.showDividers = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
@ -0,0 +1,349 @@
|
|||||||
|
package com.tommasoberlose.anotherwidget.ui.fragments
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.AlarmManager
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.databinding.DataBindingUtil
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignIn
|
||||||
|
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||||
|
import com.google.android.gms.fitness.FitnessOptions
|
||||||
|
import com.google.android.gms.fitness.data.DataType
|
||||||
|
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.R
|
||||||
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
|
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
|
||||||
|
import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu
|
||||||
|
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
|
||||||
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.DailyStepsHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
|
import com.tommasoberlose.anotherwidget.ui.viewmodels.MainViewModel
|
||||||
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
|
import kotlinx.android.synthetic.main.fragment_glance_settings.*
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
|
class GlanceTabFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = GlanceTabFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: MainViewModel
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
|
val binding = DataBindingUtil.inflate<FragmentGlanceSettingsBinding>(inflater, R.layout.fragment_glance_settings, container, false)
|
||||||
|
|
||||||
|
subscribeUi(binding, viewModel)
|
||||||
|
|
||||||
|
binding.lifecycleOwner = this
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
|
||||||
|
setupListener()
|
||||||
|
updateNextAlarmWarningUi()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun subscribeUi(
|
||||||
|
binding: FragmentGlanceSettingsBinding,
|
||||||
|
viewModel: MainViewModel
|
||||||
|
) {
|
||||||
|
|
||||||
|
viewModel.showGlance.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
binding.isGlanceVisible = it
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.showMusic.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
checkNotificationPermission()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
updateNextAlarmWarningUi()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.showBatteryCharging.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
show_low_battery_level_warning_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// viewModel.showDailySteps.observe(viewLifecycleOwner, Observer {
|
||||||
|
// maintainScrollPosition {
|
||||||
|
// show_steps_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
// }
|
||||||
|
// checkFitnessPermission()
|
||||||
|
// })
|
||||||
|
|
||||||
|
viewModel.customInfo.observe(viewLifecycleOwner, Observer {
|
||||||
|
maintainScrollPosition {
|
||||||
|
show_custom_notes_label?.text = if (it == "") getString(R.string.settings_not_visible) else it
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListener() {
|
||||||
|
|
||||||
|
action_show_glance.setOnClickListener {
|
||||||
|
Preferences.showGlance = !Preferences.showGlance
|
||||||
|
}
|
||||||
|
|
||||||
|
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
|
Preferences.showGlance = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
action_sort_glance_providers.setOnClickListener {
|
||||||
|
GlanceProviderSortMenu(requireContext())
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
action_show_music.setOnClickListener {
|
||||||
|
if (Preferences.showGlance) {
|
||||||
|
BottomSheetMenu<Boolean>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_show_music_title)
|
||||||
|
).setSelectedValue(Preferences.showMusic)
|
||||||
|
.addItem(getString(R.string.settings_visible), true)
|
||||||
|
.addItem(getString(R.string.settings_not_visible), false)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.showMusic = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action_show_next_alarm.setOnClickListener {
|
||||||
|
if (Preferences.showGlance) {
|
||||||
|
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 ->
|
||||||
|
Preferences.showNextAlarm = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action_show_low_battery_level_warning.setOnClickListener {
|
||||||
|
if (Preferences.showGlance) {
|
||||||
|
BottomSheetMenu<Boolean>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_low_battery_level_title)
|
||||||
|
).setSelectedValue(Preferences.showBatteryCharging)
|
||||||
|
.addItem(getString(R.string.settings_visible), true)
|
||||||
|
.addItem(getString(R.string.settings_not_visible), false)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.showBatteryCharging = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action_show_steps.setOnClickListener {
|
||||||
|
if (Preferences.showGlance) {
|
||||||
|
BottomSheetMenu<Boolean>(
|
||||||
|
requireContext(),
|
||||||
|
header = getString(R.string.settings_daily_steps_title)
|
||||||
|
).setSelectedValue(Preferences.showDailySteps)
|
||||||
|
.addItem(getString(R.string.settings_visible), true)
|
||||||
|
.addItem(getString(R.string.settings_not_visible), false)
|
||||||
|
.addOnSelectItemListener { value ->
|
||||||
|
Preferences.showDailySteps = value
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action_show_custom_notes.setOnClickListener {
|
||||||
|
if (Preferences.showGlance) {
|
||||||
|
CustomNotesDialog(requireContext()).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateNextAlarmWarningUi() {
|
||||||
|
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
|
||||||
|
val alarm = nextAlarmClock
|
||||||
|
if (AlarmHelper.isAlarmProbablyWrong(requireContext()) && alarm != null && alarm.showIntent != null) {
|
||||||
|
val pm = requireContext().packageManager as PackageManager
|
||||||
|
val appNameOrPackage = try {
|
||||||
|
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
alarm.showIntent?.creatorPackage ?: ""
|
||||||
|
}
|
||||||
|
show_next_alarm_warning.text =
|
||||||
|
getString(R.string.next_alarm_warning).format(appNameOrPackage)
|
||||||
|
} else {
|
||||||
|
show_next_alarm_label?.text = if (Preferences.showNextAlarm) getString(R.string.settings_visible) else getString(
|
||||||
|
R.string.settings_not_visible)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
updateNextAlarmWarningUi()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
activity?.unregisterReceiver(nextAlarmChangeBroadcastReceiver)
|
||||||
|
super.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkNotificationPermission() {
|
||||||
|
if (NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)) {
|
||||||
|
notification_permission_alert?.isVisible = false
|
||||||
|
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
|
||||||
|
show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
} else if (Preferences.showMusic) {
|
||||||
|
notification_permission_alert?.isVisible = true
|
||||||
|
show_music_label?.text = getString(R.string.settings_request_notification_access)
|
||||||
|
notification_permission_alert?.setOnClickListener {
|
||||||
|
activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
show_music_label?.text = getString(R.string.settings_not_visible)
|
||||||
|
notification_permission_alert?.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private fun checkFitnessPermission() {
|
||||||
|
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION) == true) {
|
||||||
|
// fitness_permission_alert?.isVisible = false
|
||||||
|
// if (Preferences.showDailySteps) {
|
||||||
|
// val fitnessOptions = FitnessOptions.builder()
|
||||||
|
// .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
|
||||||
|
// .addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
|
||||||
|
// .build()
|
||||||
|
//
|
||||||
|
// val account: GoogleSignInAccount = GoogleSignIn.getLastSignedInAccount(requireContext()) ?: GoogleSignIn.getAccountForExtension(requireContext(), fitnessOptions)
|
||||||
|
//
|
||||||
|
// if (!GoogleSignIn.hasPermissions(account, fitnessOptions)) {
|
||||||
|
// GoogleSignIn.requestPermissions(
|
||||||
|
// requireActivity(),
|
||||||
|
// 1,
|
||||||
|
// account,
|
||||||
|
// fitnessOptions)
|
||||||
|
// } else {
|
||||||
|
// DailyStepsHelper.registerFence(requireContext())
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// DailyStepsHelper.unregisterFence(requireContext())
|
||||||
|
// }
|
||||||
|
// show_steps_label?.text = if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
|
||||||
|
// } else if (Preferences.showDailySteps) {
|
||||||
|
// DailyStepsHelper.unregisterFence(requireContext())
|
||||||
|
// fitness_permission_alert?.isVisible = true
|
||||||
|
// show_steps_label?.text = getString(R.string.settings_request_fitness_access)
|
||||||
|
// fitness_permission_alert?.setOnClickListener {
|
||||||
|
// requireFitnessPermission()
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// DailyStepsHelper.unregisterFence(requireContext())
|
||||||
|
// show_steps_label?.text = getString(R.string.settings_not_visible)
|
||||||
|
// fitness_permission_alert?.isVisible = false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onActivityResult(
|
||||||
|
// requestCode: Int,
|
||||||
|
// resultCode: Int,
|
||||||
|
// data: Intent?
|
||||||
|
// ) {
|
||||||
|
// if (resultCode == Activity.RESULT_OK) {
|
||||||
|
// if (requestCode == 1) {
|
||||||
|
// DailyStepsHelper.registerFence(requireContext())
|
||||||
|
// } else {
|
||||||
|
// Preferences.showDailySteps = false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private fun requireFitnessPermission() {
|
||||||
|
// Dexter.withContext(requireContext())
|
||||||
|
// .withPermissions(
|
||||||
|
// "com.google.android.gms.permission.ACTIVITY_RECOGNITION",
|
||||||
|
// "android.gms.permission.ACTIVITY_RECOGNITION",
|
||||||
|
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACTIVITY_RECOGNITION else "com.google.android.gms.permission.ACTIVITY_RECOGNITION"
|
||||||
|
// ).withListener(object: MultiplePermissionsListener {
|
||||||
|
// override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
|
||||||
|
// report?.let {
|
||||||
|
// if (report.areAllPermissionsGranted()){
|
||||||
|
// checkFitnessPermission()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// override fun onPermissionRationaleShouldBeShown(
|
||||||
|
// permissions: MutableList<PermissionRequest>?,
|
||||||
|
// token: PermissionToken?
|
||||||
|
// ) {
|
||||||
|
// // Remember to invoke this method when the custom rationale is closed
|
||||||
|
// // or just by default if you don't want to use any custom rationale.
|
||||||
|
// token?.continuePermissionRequest()
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// .check()
|
||||||
|
// }
|
||||||
|
|
||||||
|
private fun maintainScrollPosition(callback: () -> Unit) {
|
||||||
|
val scrollPosition = scrollView.scrollY
|
||||||
|
callback.invoke()
|
||||||
|
lifecycleScope.launch {
|
||||||
|
delay(200)
|
||||||
|
scrollView.smoothScrollTo(0, scrollPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
checkNotificationPermission()
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Log
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -28,8 +29,6 @@ import com.google.android.material.tabs.TabLayoutMediator
|
|||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentAdvancedSettingsBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentAppMainBinding
|
|
||||||
import com.tommasoberlose.anotherwidget.global.Constants
|
import com.tommasoberlose.anotherwidget.global.Constants
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
|
import com.tommasoberlose.anotherwidget.helpers.BitmapHelper
|
||||||
@ -53,6 +52,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = MainFragment()
|
fun newInstance() = MainFragment()
|
||||||
|
private const val PREVIEW_BASE_HEIGHT = 120
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var viewModel: MainViewModel
|
private lateinit var viewModel: MainViewModel
|
||||||
@ -98,7 +98,7 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
time_container.isVisible = Preferences.showClock
|
time_container.isVisible = Preferences.showClock
|
||||||
|
|
||||||
preview.layoutParams = preview.layoutParams.apply {
|
preview.layoutParams = preview.layoutParams.apply {
|
||||||
height = 160.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(requireContext()) else 0
|
height = PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(requireContext()) else 0
|
||||||
}
|
}
|
||||||
subscribeUi(viewModel)
|
subscribeUi(viewModel)
|
||||||
updateUI()
|
updateUI()
|
||||||
@ -124,143 +124,156 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
|
|
||||||
private fun updateUI() {
|
private fun updateUI() {
|
||||||
uiJob?.cancel()
|
uiJob?.cancel()
|
||||||
|
if (preview != null) {
|
||||||
|
preview.clearAnimation()
|
||||||
|
time_container.clearAnimation()
|
||||||
|
|
||||||
if (Preferences.showPreview) {
|
if (Preferences.showPreview) {
|
||||||
preview.setCardBackgroundColor(
|
preview.setCardBackgroundColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
if (ColorHelper.getFontColor()
|
if (ColorHelper.getFontColor()
|
||||||
.isColorDark()
|
.isColorDark()
|
||||||
) android.R.color.white else R.color.colorAccent
|
) android.R.color.white else R.color.colorAccent
|
||||||
)
|
|
||||||
)
|
|
||||||
widget_shape_background.setImageDrawable(BitmapHelper.getTintedDrawable(requireContext(), R.drawable.card_background, ColorHelper.getBackgroundColor()))
|
|
||||||
uiJob = viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
delay(200)
|
|
||||||
val generatedView = MainWidget.generateWidgetView(requireContext())
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
generatedView.measure(0, 0)
|
|
||||||
preview.measure(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val bitmap = BitmapHelper.getBitmapFromView(
|
|
||||||
generatedView,
|
|
||||||
if (preview.width > 0) preview.width else generatedView.measuredWidth,
|
|
||||||
generatedView.measuredHeight
|
|
||||||
)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
// Clock
|
|
||||||
time.setTextColor(ColorHelper.getClockFontColor())
|
|
||||||
time_am_pm.setTextColor(ColorHelper.getClockFontColor())
|
|
||||||
time.setTextSize(
|
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
|
||||||
Preferences.clockTextSize.toPixel(requireContext())
|
|
||||||
)
|
)
|
||||||
time_am_pm.setTextSize(
|
)
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
widget_shape_background?.setImageDrawable(
|
||||||
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
|
BitmapHelper.getTintedDrawable(
|
||||||
|
requireContext(),
|
||||||
|
R.drawable.card_background,
|
||||||
|
ColorHelper.getBackgroundColor()
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
uiJob = viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
val generatedView = MainWidget.generateWidgetView(requireContext())
|
||||||
|
|
||||||
// Clock bottom margin
|
withContext(Dispatchers.Main) {
|
||||||
clock_bottom_margin_none.isVisible =
|
generatedView.measure(0, 0)
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
|
preview.measure(0, 0)
|
||||||
clock_bottom_margin_small.isVisible =
|
}
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
|
|
||||||
clock_bottom_margin_medium.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
|
|
||||||
clock_bottom_margin_large.isVisible =
|
|
||||||
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
|
|
||||||
|
|
||||||
if ((Preferences.showClock && !time_container.isVisible) || (!Preferences.showClock && time_container.isVisible)) {
|
val bitmap = BitmapHelper.getBitmapFromView(
|
||||||
if (Preferences.showClock) {
|
generatedView,
|
||||||
|
if (preview.width > 0) preview.width else generatedView.measuredWidth,
|
||||||
|
generatedView.measuredHeight
|
||||||
|
)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
// Clock
|
||||||
|
time.setTextColor(ColorHelper.getClockFontColor())
|
||||||
|
time_am_pm.setTextColor(ColorHelper.getClockFontColor())
|
||||||
|
time.setTextSize(
|
||||||
|
TypedValue.COMPLEX_UNIT_SP,
|
||||||
|
Preferences.clockTextSize.toPixel(requireContext())
|
||||||
|
)
|
||||||
|
time_am_pm.setTextSize(
|
||||||
|
TypedValue.COMPLEX_UNIT_SP,
|
||||||
|
Preferences.clockTextSize.toPixel(requireContext()) / 5 * 2
|
||||||
|
)
|
||||||
|
time_am_pm.isVisible = Preferences.showAMPMIndicator
|
||||||
|
|
||||||
|
// Clock bottom margin
|
||||||
|
clock_bottom_margin_none.isVisible =
|
||||||
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.NONE.value
|
||||||
|
clock_bottom_margin_small.isVisible =
|
||||||
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.SMALL.value
|
||||||
|
clock_bottom_margin_medium.isVisible =
|
||||||
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.MEDIUM.value
|
||||||
|
clock_bottom_margin_large.isVisible =
|
||||||
|
Preferences.showClock && Preferences.clockBottomMargin == Constants.ClockBottomMargin.LARGE.value
|
||||||
|
|
||||||
|
if ((Preferences.showClock && !time_container.isVisible) || (!Preferences.showClock && time_container.isVisible)) {
|
||||||
|
if (Preferences.showClock) {
|
||||||
|
time_container.layoutParams = time_container.layoutParams.apply {
|
||||||
|
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
}
|
||||||
|
time_container.measure(0, 0)
|
||||||
|
}
|
||||||
|
val initialHeight = time_container.measuredHeight
|
||||||
|
ValueAnimator.ofFloat(
|
||||||
|
if (Preferences.showClock) 0f else 1f,
|
||||||
|
if (Preferences.showClock) 1f else 0f
|
||||||
|
).apply {
|
||||||
|
duration = 500L
|
||||||
|
addUpdateListener {
|
||||||
|
val animatedValue = animatedValue as Float
|
||||||
|
time_container.layoutParams =
|
||||||
|
time_container.layoutParams.apply {
|
||||||
|
height = (initialHeight * animatedValue).toInt()
|
||||||
|
}
|
||||||
|
time.alpha = animatedValue
|
||||||
|
}
|
||||||
|
addListener(
|
||||||
|
onStart = {
|
||||||
|
if (Preferences.showClock) {
|
||||||
|
time_container.isVisible = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEnd = {
|
||||||
|
if (!Preferences.showClock) {
|
||||||
|
time_container.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.start()
|
||||||
|
|
||||||
|
ValueAnimator.ofInt(
|
||||||
|
preview.height,
|
||||||
|
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
||||||
|
requireContext()
|
||||||
|
) else 0
|
||||||
|
).apply {
|
||||||
|
duration = 500L
|
||||||
|
addUpdateListener {
|
||||||
|
val animatedValue = animatedValue as Int
|
||||||
|
val layoutParams = preview.layoutParams
|
||||||
|
layoutParams.height = animatedValue
|
||||||
|
preview.layoutParams = layoutParams
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
} else {
|
||||||
time_container.layoutParams = time_container.layoutParams.apply {
|
time_container.layoutParams = time_container.layoutParams.apply {
|
||||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
||||||
}
|
}
|
||||||
time_container.measure(0, 0)
|
time_container.measure(0, 0)
|
||||||
}
|
}
|
||||||
val initialHeight = time_container.measuredHeight
|
|
||||||
ValueAnimator.ofFloat(
|
|
||||||
if (Preferences.showClock) 0f else 1f,
|
|
||||||
if (Preferences.showClock) 1f else 0f
|
|
||||||
).apply {
|
|
||||||
duration = 500L
|
|
||||||
addUpdateListener {
|
|
||||||
val animatedValue = animatedValue as Float
|
|
||||||
time_container.layoutParams = time_container.layoutParams.apply {
|
|
||||||
height = (initialHeight * animatedValue).toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addListener(
|
|
||||||
onStart = {
|
|
||||||
if (Preferences.showClock) {
|
|
||||||
time_container.isVisible = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onEnd = {
|
|
||||||
if (!Preferences.showClock) {
|
|
||||||
time_container.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.start()
|
|
||||||
|
|
||||||
ValueAnimator.ofInt(
|
if (preview.height == 0) {
|
||||||
preview.height,
|
ValueAnimator.ofInt(
|
||||||
160.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
preview.height,
|
||||||
requireContext()
|
PREVIEW_BASE_HEIGHT.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
||||||
) else 0
|
requireContext()
|
||||||
).apply {
|
) else 0
|
||||||
duration = 500L
|
).apply {
|
||||||
addUpdateListener {
|
duration = 300L
|
||||||
val animatedValue = animatedValue as Int
|
addUpdateListener {
|
||||||
val layoutParams = preview.layoutParams
|
val animatedValue = animatedValue as Int
|
||||||
layoutParams.height = animatedValue
|
val layoutParams = preview.layoutParams
|
||||||
preview.layoutParams = layoutParams
|
layoutParams.height = animatedValue
|
||||||
}
|
preview.layoutParams = layoutParams
|
||||||
}.start()
|
}
|
||||||
} else {
|
}.start()
|
||||||
time_container.layoutParams = time_container.layoutParams.apply {
|
|
||||||
height = RelativeLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
}
|
}
|
||||||
time_container.measure(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preview.height == 0) {
|
widget_loader.animate().scaleX(0f).scaleY(0f).alpha(0f).setDuration(200L)
|
||||||
ValueAnimator.ofInt(
|
.start()
|
||||||
preview.height,
|
bitmap_container.setImageBitmap(bitmap)
|
||||||
160.toPixel(requireContext()) + if (Preferences.showClock) 100.toPixel(
|
widget.animate().alpha(1f).start()
|
||||||
requireContext()
|
|
||||||
) else 0
|
|
||||||
).apply {
|
|
||||||
duration = 300L
|
|
||||||
addUpdateListener {
|
|
||||||
val animatedValue = animatedValue as Int
|
|
||||||
val layoutParams = preview.layoutParams
|
|
||||||
layoutParams.height = animatedValue
|
|
||||||
preview.layoutParams = layoutParams
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap_container.setImageBitmap(bitmap)
|
|
||||||
widget_loader.animate().scaleX(0f).scaleY(0f).start()
|
|
||||||
widget.animate().alpha(1f).start()
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ValueAnimator.ofInt(
|
||||||
|
preview.height,
|
||||||
|
0
|
||||||
|
).apply {
|
||||||
|
duration = 300L
|
||||||
|
addUpdateListener {
|
||||||
|
val animatedValue = animatedValue as Int
|
||||||
|
val layoutParams = preview.layoutParams
|
||||||
|
layoutParams.height = animatedValue
|
||||||
|
preview.layoutParams = layoutParams
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ValueAnimator.ofInt(
|
|
||||||
preview.height,
|
|
||||||
0
|
|
||||||
).apply {
|
|
||||||
duration = 300L
|
|
||||||
addUpdateListener {
|
|
||||||
val animatedValue = animatedValue as Int
|
|
||||||
val layoutParams = preview.layoutParams
|
|
||||||
layoutParams.height = animatedValue
|
|
||||||
preview.layoutParams = layoutParams
|
|
||||||
}
|
|
||||||
}.start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showErrorBadge()
|
showErrorBadge()
|
||||||
@ -277,8 +290,16 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
val metrics = DisplayMetrics()
|
val metrics = DisplayMetrics()
|
||||||
act.windowManager.defaultDisplay.getMetrics(metrics)
|
act.windowManager.defaultDisplay.getMetrics(metrics)
|
||||||
|
|
||||||
height = metrics.heightPixels
|
var newHeight = metrics.heightPixels
|
||||||
width = (wallpaper?.intrinsicWidth ?: 1) * metrics.heightPixels / (wallpaper?.intrinsicWidth ?: 1)
|
var newWidth = (wallpaper?.intrinsicWidth ?: 1) * metrics.heightPixels / (wallpaper?.intrinsicHeight ?: 1)
|
||||||
|
|
||||||
|
if (newWidth < metrics.widthPixels) {
|
||||||
|
newWidth = metrics.widthPixels
|
||||||
|
newHeight = (wallpaper?.intrinsicHeight ?: 1) * metrics.widthPixels / (wallpaper?.intrinsicWidth ?: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
height = newHeight
|
||||||
|
width = newWidth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -313,16 +334,12 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
}?.isVisible = Preferences.showMusic && !NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)
|
}?.isVisible = Preferences.showMusic && !NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
|
|
||||||
updateUI()
|
|
||||||
MainWidget.updateWidget(requireContext())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
Preferences.preferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
EventBus.getDefault().register(this)
|
EventBus.getDefault().register(this)
|
||||||
showErrorBadge()
|
showErrorBadge()
|
||||||
|
updateUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
@ -331,10 +348,29 @@ class MainFragment : Fragment(), SharedPreferences.OnSharedPreferenceChangeList
|
|||||||
super.onPause()
|
super.onPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var delayJob: Job? = null
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(preferences: SharedPreferences, p1: String) {
|
||||||
|
delayJob?.cancel()
|
||||||
|
delayJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
delay(200)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
updateUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MainWidget.updateWidget(requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
class UpdateUiMessageEvent
|
class UpdateUiMessageEvent
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
|
fun onMessageEvent(ignore: UpdateUiMessageEvent?) {
|
||||||
updateUI()
|
delayJob?.cancel()
|
||||||
|
delayJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
delay(200)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
updateUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import android.Manifest
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -14,7 +15,6 @@ import androidx.lifecycle.Observer
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
import com.google.android.material.transition.MaterialContainerTransform
|
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import com.karumi.dexter.Dexter
|
import com.karumi.dexter.Dexter
|
||||||
import com.karumi.dexter.MultiplePermissionsReport
|
import com.karumi.dexter.MultiplePermissionsReport
|
||||||
@ -24,7 +24,7 @@ import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
|||||||
import com.tommasoberlose.anotherwidget.BuildConfig
|
import com.tommasoberlose.anotherwidget.BuildConfig
|
||||||
import com.tommasoberlose.anotherwidget.R
|
import com.tommasoberlose.anotherwidget.R
|
||||||
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
|
||||||
import com.tommasoberlose.anotherwidget.databinding.FragmentAdvancedSettingsBinding
|
import com.tommasoberlose.anotherwidget.databinding.FragmentSettingsBinding
|
||||||
import com.tommasoberlose.anotherwidget.global.Preferences
|
import com.tommasoberlose.anotherwidget.global.Preferences
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
|
||||||
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.SupportDevActivity
|
||||||
@ -35,7 +35,7 @@ import com.tommasoberlose.anotherwidget.helpers.WeatherHelper
|
|||||||
import com.tommasoberlose.anotherwidget.ui.activities.IntegrationsActivity
|
import com.tommasoberlose.anotherwidget.ui.activities.IntegrationsActivity
|
||||||
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
import com.tommasoberlose.anotherwidget.utils.checkGrantedPermission
|
||||||
import com.tommasoberlose.anotherwidget.utils.openURI
|
import com.tommasoberlose.anotherwidget.utils.openURI
|
||||||
import kotlinx.android.synthetic.main.fragment_advanced_settings.*
|
import kotlinx.android.synthetic.main.fragment_settings.*
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ class SettingsFragment : Fragment() {
|
|||||||
): View {
|
): View {
|
||||||
|
|
||||||
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
viewModel = ViewModelProvider(activity as MainActivity).get(MainViewModel::class.java)
|
||||||
val binding = DataBindingUtil.inflate<FragmentAdvancedSettingsBinding>(inflater, R.layout.fragment_advanced_settings, container, false)
|
val binding = DataBindingUtil.inflate<FragmentSettingsBinding>(inflater, R.layout.fragment_settings, container, false)
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
@ -168,6 +168,10 @@ class WeatherTabFragment : Fragment() {
|
|||||||
Preferences.showWeather = !Preferences.showWeather
|
Preferences.showWeather = !Preferences.showWeather
|
||||||
}
|
}
|
||||||
|
|
||||||
|
show_weather_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
|
||||||
|
Preferences.showWeather = enabled
|
||||||
|
}
|
||||||
|
|
||||||
action_weather_provider_api_key.setOnClickListener {
|
action_weather_provider_api_key.setOnClickListener {
|
||||||
if (Preferences.showWeather) {
|
if (Preferences.showWeather) {
|
||||||
startActivityForResult(
|
startActivityForResult(
|
||||||
|
@ -16,6 +16,7 @@ class MainViewModel : ViewModel() {
|
|||||||
val textShadow = Preferences.asLiveData(Preferences::textShadow)
|
val textShadow = Preferences.asLiveData(Preferences::textShadow)
|
||||||
val customFont = Preferences.asLiveData(Preferences::customFont)
|
val customFont = Preferences.asLiveData(Preferences::customFont)
|
||||||
val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation)
|
val secondRowInformation = Preferences.asLiveData(Preferences::secondRowInformation)
|
||||||
|
val showDividers = Preferences.asLiveData(Preferences::showDividers)
|
||||||
|
|
||||||
// Calendar Settings
|
// Calendar Settings
|
||||||
val showEvents = Preferences.asLiveData(Preferences::showEvents)
|
val showEvents = Preferences.asLiveData(Preferences::showEvents)
|
||||||
@ -32,9 +33,9 @@ class MainViewModel : ViewModel() {
|
|||||||
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
|
val clockTextSize = Preferences.asLiveData(Preferences::clockTextSize)
|
||||||
val clockTextColor = Preferences.asLiveData(Preferences::clockTextColor)
|
val clockTextColor = Preferences.asLiveData(Preferences::clockTextColor)
|
||||||
val clockTextAlpha = Preferences.asLiveData(Preferences::clockTextAlpha)
|
val clockTextAlpha = Preferences.asLiveData(Preferences::clockTextAlpha)
|
||||||
|
val showAMPMIndicator = Preferences.asLiveData(Preferences::showAMPMIndicator)
|
||||||
|
|
||||||
val clockAppName = Preferences.asLiveData(Preferences::clockAppName)
|
val clockAppName = Preferences.asLiveData(Preferences::clockAppName)
|
||||||
val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm)
|
|
||||||
val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
|
val dateFormat = Preferences.asLiveData(Preferences::dateFormat)
|
||||||
val clockBottomMargin = Preferences.asLiveData(Preferences::clockBottomMargin)
|
val clockBottomMargin = Preferences.asLiveData(Preferences::clockBottomMargin)
|
||||||
|
|
||||||
@ -52,9 +53,13 @@ class MainViewModel : ViewModel() {
|
|||||||
|
|
||||||
val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning)
|
val showWeatherWarning = Preferences.asLiveData(Preferences::showWeatherWarning)
|
||||||
|
|
||||||
// Music
|
// Glance
|
||||||
|
val showGlance = Preferences.asLiveData(Preferences::showGlance)
|
||||||
val showMusic = Preferences.asLiveData(Preferences::showMusic)
|
val showMusic = Preferences.asLiveData(Preferences::showMusic)
|
||||||
val mediaInfoFormat = Preferences.asLiveData(Preferences::mediaInfoFormat)
|
val showNextAlarm = Preferences.asLiveData(Preferences::showNextAlarm)
|
||||||
|
val showBatteryCharging = Preferences.asLiveData(Preferences::showBatteryCharging)
|
||||||
|
val showDailySteps = Preferences.asLiveData(Preferences::showDailySteps)
|
||||||
|
val customInfo = Preferences.asLiveData(Preferences::customNotes)
|
||||||
|
|
||||||
// Advanced Settings
|
// Advanced Settings
|
||||||
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
|
val darkThemePreference = Preferences.asLiveData(Preferences::darkThemePreference)
|
||||||
|
@ -12,7 +12,6 @@ import android.graphics.Color
|
|||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.util.Log
|
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
@ -261,14 +260,57 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
|
|
||||||
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
|
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
|
||||||
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
||||||
} else if (MediaPlayerHelper.isSomeonePlaying(context)) {
|
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||||
val musicIntent = PendingIntent.getActivity(
|
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders()) {
|
||||||
context,
|
when (provider) {
|
||||||
widgetID,
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
IntentHelper.getMusicIntent(context),
|
if (MediaPlayerHelper.isSomeonePlaying(context)) {
|
||||||
0
|
val musicIntent = PendingIntent.getActivity(
|
||||||
)
|
context,
|
||||||
views.setOnClickPendingIntent(R.id.second_row_rect, musicIntent)
|
widgetID,
|
||||||
|
IntentHelper.getMusicIntent(context),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
views.setOnClickPendingIntent(R.id.second_row_rect, musicIntent)
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
|
if (Preferences.showNextAlarm && nextAlarm != "") {
|
||||||
|
val alarmIntent = PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
widgetID,
|
||||||
|
IntentHelper.getClockIntent(context),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
views.setOnClickPendingIntent(R.id.second_row_rect, alarmIntent)
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
|
if (Preferences.isBatteryLevelLow) {
|
||||||
|
val alarmIntent = PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
widgetID,
|
||||||
|
IntentHelper.getClockIntent(context),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
views.setOnClickPendingIntent(R.id.second_row_rect, alarmIntent)
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
|
if (Preferences.customNotes.isNotEmpty()) {
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
|
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
views.setImageViewBitmap(
|
views.setImageViewBitmap(
|
||||||
R.id.next_event_rect,
|
R.id.next_event_rect,
|
||||||
@ -279,31 +321,8 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
R.id.second_row_rect,
|
R.id.second_row_rect,
|
||||||
BitmapHelper.getBitmapFromView(v.second_row, draw = false)
|
BitmapHelper.getBitmapFromView(v.second_row, draw = false)
|
||||||
)
|
)
|
||||||
|
|
||||||
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
|
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
|
||||||
|
|
||||||
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
|
|
||||||
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
|
||||||
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent)
|
|
||||||
} else if (Preferences.showNextAlarm && nextAlarm != "") {
|
|
||||||
val alarmIntent = PendingIntent.getActivity(
|
|
||||||
context,
|
|
||||||
widgetID,
|
|
||||||
IntentHelper.getClockIntent(context),
|
|
||||||
0
|
|
||||||
)
|
|
||||||
views.setOnClickPendingIntent(R.id.second_row_rect, alarmIntent)
|
|
||||||
|
|
||||||
views.setImageViewBitmap(
|
|
||||||
R.id.next_event_rect,
|
|
||||||
BitmapHelper.getBitmapFromView(v.next_event, draw = false)
|
|
||||||
)
|
|
||||||
|
|
||||||
views.setImageViewBitmap(
|
|
||||||
R.id.second_row_rect,
|
|
||||||
BitmapHelper.getBitmapFromView(v.second_row, draw = false)
|
|
||||||
)
|
|
||||||
views.setViewVisibility(R.id.second_row_rect, View.VISIBLE)
|
|
||||||
|
|
||||||
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
|
views.setViewVisibility(R.id.empty_layout_rect, View.GONE)
|
||||||
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
views.setViewVisibility(R.id.calendar_layout_rect, View.VISIBLE)
|
||||||
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent)
|
views.setOnClickPendingIntent(R.id.next_event_rect, calPIntent)
|
||||||
@ -346,7 +365,7 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
BitmapHelper.getBitmapFromView(v.calendar_weather, draw = false)
|
BitmapHelper.getBitmapFromView(v.calendar_weather, draw = false)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WidgetHelper.showSpecialWeather(context)) {
|
if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||||
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
|
views.setViewVisibility(R.id.calendar_weather_rect, View.GONE)
|
||||||
} else {
|
} else {
|
||||||
views.setViewVisibility(R.id.special_weather_rect, View.GONE)
|
views.setViewVisibility(R.id.special_weather_rect, View.GONE)
|
||||||
@ -394,7 +413,7 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
views.setOnClickPendingIntent(R.id.time, clockPIntent)
|
views.setOnClickPendingIntent(R.id.time, clockPIntent)
|
||||||
views.setOnClickPendingIntent(R.id.time_am_pm, clockPIntent)
|
views.setOnClickPendingIntent(R.id.time_am_pm, clockPIntent)
|
||||||
views.setViewVisibility(R.id.time, View.VISIBLE)
|
views.setViewVisibility(R.id.time, View.VISIBLE)
|
||||||
views.setViewVisibility(R.id.time_am_pm, View.VISIBLE)
|
views.setViewVisibility(R.id.time_am_pm, if (Preferences.showAMPMIndicator) View.VISIBLE else View.GONE)
|
||||||
|
|
||||||
views.setViewVisibility(
|
views.setViewVisibility(
|
||||||
R.id.clock_bottom_margin_none,
|
R.id.clock_bottom_margin_none,
|
||||||
@ -499,26 +518,69 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
|
|
||||||
v.empty_layout.visibility = View.GONE
|
v.empty_layout.visibility = View.GONE
|
||||||
v.calendar_layout.visibility = View.VISIBLE
|
v.calendar_layout.visibility = View.VISIBLE
|
||||||
} else if (MediaPlayerHelper.isSomeonePlaying(context)) {
|
} else if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||||
v.second_row_icon.setImageDrawable(
|
v.second_row_icon.isVisible = true
|
||||||
ContextCompat.getDrawable(
|
loop@ for (provider:Constants.GlanceProviderId in GlanceProviderHelper.getGlanceProviders()) {
|
||||||
context,
|
when (provider) {
|
||||||
R.drawable.round_music_note
|
Constants.GlanceProviderId.PLAYING_SONG -> {
|
||||||
)
|
if (MediaPlayerHelper.isSomeonePlaying(context)) {
|
||||||
)
|
v.second_row_icon.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(
|
||||||
|
context,
|
||||||
|
R.drawable.round_music_note
|
||||||
|
)
|
||||||
|
)
|
||||||
|
v.next_event_date.text = MediaPlayerHelper.getMediaInfo()
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
|
||||||
|
if (Preferences.showNextAlarm && nextAlarm != "") {
|
||||||
|
v.second_row_icon.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(
|
||||||
|
context,
|
||||||
|
R.drawable.round_alarm
|
||||||
|
)
|
||||||
|
)
|
||||||
|
v.next_event_date.text = AlarmHelper.getNextAlarm(context)
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
|
||||||
|
if (Preferences.isBatteryLevelLow) {
|
||||||
|
v.second_row_icon.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(
|
||||||
|
context,
|
||||||
|
R.drawable.round_battery_charging_full
|
||||||
|
)
|
||||||
|
)
|
||||||
|
v.next_event_date.text = context.getString(R.string.battery_low_warning)
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.CUSTOM_INFO -> {
|
||||||
|
if (Preferences.customNotes.isNotEmpty()) {
|
||||||
|
v.second_row_icon.isVisible = false
|
||||||
|
v.next_event_date.text = Preferences.customNotes
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
|
||||||
|
if (Preferences.showDailySteps && Preferences.googleFitSteps > 0) {
|
||||||
|
v.second_row_icon.setImageDrawable(
|
||||||
|
ContextCompat.getDrawable(
|
||||||
|
context,
|
||||||
|
R.drawable.round_directions_walk
|
||||||
|
)
|
||||||
|
)
|
||||||
|
v.next_event_date.text = "${Preferences.googleFitSteps}"
|
||||||
|
break@loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
v.next_event.text = DateHelper.getDateText(context, now)
|
v.next_event.text = DateHelper.getDateText(context, now)
|
||||||
v.next_event_date.text = MediaPlayerHelper.getMediaInfo()
|
|
||||||
v.empty_layout.visibility = View.GONE
|
|
||||||
v.calendar_layout.visibility = View.VISIBLE
|
|
||||||
} else if (Preferences.showNextAlarm && nextAlarm != "") {
|
|
||||||
v.second_row_icon.setImageDrawable(
|
|
||||||
ContextCompat.getDrawable(
|
|
||||||
context,
|
|
||||||
R.drawable.round_alarm
|
|
||||||
)
|
|
||||||
)
|
|
||||||
v.next_event.text = DateHelper.getDateText(context, now)
|
|
||||||
v.next_event_date.text = AlarmHelper.getNextAlarm(context)
|
|
||||||
v.empty_layout.visibility = View.GONE
|
v.empty_layout.visibility = View.GONE
|
||||||
v.calendar_layout.visibility = View.VISIBLE
|
v.calendar_layout.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
@ -626,7 +688,7 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
v.calendar_temp.text = currentTemp
|
v.calendar_temp.text = currentTemp
|
||||||
v.special_temp.text = currentTemp
|
v.special_temp.text = currentTemp
|
||||||
|
|
||||||
if (WidgetHelper.showSpecialWeather(context)) {
|
if (GlanceProviderHelper.showGlanceProviders(context)) {
|
||||||
v.calendar_weather.visibility = View.GONE
|
v.calendar_weather.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
v.special_weather.visibility = View.GONE
|
v.special_weather.visibility = View.GONE
|
||||||
@ -637,6 +699,11 @@ class MainWidget : AppWidgetProvider() {
|
|||||||
v.special_weather.visibility = View.GONE
|
v.special_weather.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dividers
|
||||||
|
arrayOf(v.divider1, v.divider2, v.divider3).forEach {
|
||||||
|
it.isVisible = Preferences.showDividers
|
||||||
|
}
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
app/src/main/res/drawable-hdpi/round_all_inclusive.png
Normal file
After Width: | Height: | Size: 465 B |
BIN
app/src/main/res/drawable-hdpi/round_all_inclusive_black_18.png
Normal file
After Width: | Height: | Size: 399 B |
BIN
app/src/main/res/drawable-hdpi/round_all_inclusive_black_36.png
Normal file
After Width: | Height: | Size: 665 B |
BIN
app/src/main/res/drawable-hdpi/round_all_inclusive_black_48.png
Normal file
After Width: | Height: | Size: 867 B |
BIN
app/src/main/res/drawable-hdpi/round_battery_charging_full.png
Normal file
After Width: | Height: | Size: 426 B |
After Width: | Height: | Size: 238 B |
After Width: | Height: | Size: 263 B |
After Width: | Height: | Size: 355 B |
After Width: | Height: | Size: 186 B |
After Width: | Height: | Size: 184 B |
After Width: | Height: | Size: 241 B |
After Width: | Height: | Size: 248 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_4.png
Normal file
After Width: | Height: | Size: 616 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_4_black_18.png
Normal file
After Width: | Height: | Size: 324 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_4_black_24.png
Normal file
After Width: | Height: | Size: 372 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_4_black_36.png
Normal file
After Width: | Height: | Size: 517 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_5.png
Normal file
After Width: | Height: | Size: 361 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_5_black_18.png
Normal file
After Width: | Height: | Size: 333 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_5_black_36.png
Normal file
After Width: | Height: | Size: 509 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_5_black_48.png
Normal file
After Width: | Height: | Size: 642 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_7.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_7_black_24.png
Normal file
After Width: | Height: | Size: 441 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_7_black_36.png
Normal file
After Width: | Height: | Size: 628 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_7_black_48.png
Normal file
After Width: | Height: | Size: 802 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_low.png
Normal file
After Width: | Height: | Size: 399 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_low_black_18.png
Normal file
After Width: | Height: | Size: 362 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_low_black_36.png
Normal file
After Width: | Height: | Size: 541 B |
BIN
app/src/main/res/drawable-hdpi/round_brightness_low_black_48.png
Normal file
After Width: | Height: | Size: 689 B |
BIN
app/src/main/res/drawable-hdpi/round_category.png
Normal file
After Width: | Height: | Size: 345 B |
BIN
app/src/main/res/drawable-hdpi/round_category_black_18.png
Normal file
After Width: | Height: | Size: 292 B |
BIN
app/src/main/res/drawable-hdpi/round_category_black_36.png
Normal file
After Width: | Height: | Size: 469 B |
BIN
app/src/main/res/drawable-hdpi/round_category_black_48.png
Normal file
After Width: | Height: | Size: 590 B |
BIN
app/src/main/res/drawable-hdpi/round_collections_bookmark.png
Normal file
After Width: | Height: | Size: 231 B |
After Width: | Height: | Size: 241 B |
After Width: | Height: | Size: 335 B |
After Width: | Height: | Size: 409 B |
BIN
app/src/main/res/drawable-hdpi/round_directions_walk.png
Normal file
After Width: | Height: | Size: 705 B |
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 407 B |
After Width: | Height: | Size: 561 B |
BIN
app/src/main/res/drawable-hdpi/round_drag_handle.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
app/src/main/res/drawable-hdpi/round_drag_handle_black_18.png
Normal file
After Width: | Height: | Size: 138 B |
BIN
app/src/main/res/drawable-hdpi/round_drag_handle_black_24.png
Normal file
After Width: | Height: | Size: 143 B |
BIN
app/src/main/res/drawable-hdpi/round_drag_handle_black_36.png
Normal file
After Width: | Height: | Size: 162 B |
BIN
app/src/main/res/drawable-hdpi/round_drag_indicator_black_18.png
Normal file
After Width: | Height: | Size: 296 B |
BIN
app/src/main/res/drawable-hdpi/round_drag_indicator_black_24.png
Normal file
After Width: | Height: | Size: 229 B |
BIN
app/src/main/res/drawable-hdpi/round_drag_indicator_black_36.png
Normal file
After Width: | Height: | Size: 414 B |
BIN
app/src/main/res/drawable-hdpi/round_drag_indicator_black_48.png
Normal file
After Width: | Height: | Size: 371 B |
BIN
app/src/main/res/drawable-hdpi/round_dynamic_feed.png
Normal file
After Width: | Height: | Size: 249 B |
BIN
app/src/main/res/drawable-hdpi/round_dynamic_feed_black_18.png
Normal file
After Width: | Height: | Size: 258 B |
BIN
app/src/main/res/drawable-hdpi/round_dynamic_feed_black_36.png
Normal file
After Width: | Height: | Size: 325 B |
BIN
app/src/main/res/drawable-hdpi/round_dynamic_feed_black_48.png
Normal file
After Width: | Height: | Size: 363 B |
BIN
app/src/main/res/drawable-hdpi/round_flip_to_front_black_18.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
app/src/main/res/drawable-hdpi/round_flip_to_front_black_24.png
Normal file
After Width: | Height: | Size: 250 B |
BIN
app/src/main/res/drawable-hdpi/round_flip_to_front_black_36.png
Normal file
After Width: | Height: | Size: 315 B |
BIN
app/src/main/res/drawable-hdpi/round_flip_to_front_black_48.png
Normal file
After Width: | Height: | Size: 356 B |
BIN
app/src/main/res/drawable-hdpi/round_format_quote.png
Normal file
After Width: | Height: | Size: 275 B |
BIN
app/src/main/res/drawable-hdpi/round_format_quote_black_18.png
Normal file
After Width: | Height: | Size: 227 B |
BIN
app/src/main/res/drawable-hdpi/round_format_quote_black_24.png
Normal file
After Width: | Height: | Size: 196 B |
BIN
app/src/main/res/drawable-hdpi/round_format_quote_black_36.png
Normal file
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 164 B |
After Width: | Height: | Size: 140 B |
After Width: | Height: | Size: 196 B |
After Width: | Height: | Size: 215 B |
BIN
app/src/main/res/drawable-hdpi/round_hourglass_empty.png
Normal file
After Width: | Height: | Size: 282 B |
After Width: | Height: | Size: 301 B |
After Width: | Height: | Size: 389 B |
After Width: | Height: | Size: 485 B |
BIN
app/src/main/res/drawable-hdpi/round_landscape.png
Normal file
After Width: | Height: | Size: 220 B |