add proper colored popups like ios

This commit is contained in:
Kavish Devar
2024-12-06 19:57:21 +05:30
parent db8458be59
commit ebdb1609f3
27 changed files with 273 additions and 62 deletions

View File

@@ -37,6 +37,7 @@ android {
}
buildFeatures {
compose = true
viewBinding = true
}
}

View File

@@ -8,7 +8,6 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission
android:name="android.permission.BLUETOOTH_PRIVILEGED"
tools:ignore="ProtectedPermissions" />
@@ -29,6 +28,18 @@
android:theme="@style/Theme.ALN"
tools:ignore="UnusedAttribute"
tools:targetApi="31">
<receiver
android:name=".BatteryWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/battery_widget_info" />
</receiver>
<activity
android:name=".CustomDevice"
android:exported="true"
@@ -44,6 +55,7 @@
android:theme="@style/Theme.ALN">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
@@ -64,6 +76,7 @@
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<receiver
android:name=".BootReceiver"
android:enabled="true"

View File

@@ -0,0 +1,44 @@
package me.kavishdevar.aln
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.widget.RemoteViews
/**
* Implementation of App Widget functionality.
*/
class BatteryWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
}
}
internal fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val widgetText = context.getString(R.string.appwidget_text)
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.battery_widget)
views.setTextViewText(R.id.appwidget_text, widgetText)
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}

View File

@@ -9,6 +9,7 @@ import android.graphics.PixelFormat
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import android.view.animation.AccelerateInterpolator
@@ -17,25 +18,35 @@ import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.VideoView
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.lifecycle.setViewTreeLifecycleOwner
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.lang.Exception
@SuppressLint("InflateParams")
@SuppressLint("InflateParams", "ClickableViewAccessibility")
class Window (context: Context) {
private val mView: View
private val mParams: WindowManager.LayoutParams = WindowManager.LayoutParams(
(context.resources.displayMetrics.widthPixels * 0.95).toInt(),
WindowManager.LayoutParams.WRAP_CONTENT, // Display it on top of other application windows
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // Don't let it grab the input focus
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // Make the underlying application window visible
PixelFormat.TRANSLUCENT
)
@Suppress("DEPRECATION")
@SuppressLint("NewApi")
private val mParams: WindowManager.LayoutParams = WindowManager.LayoutParams().apply {
height = WindowManager.LayoutParams.WRAP_CONTENT
width = WindowManager.LayoutParams.MATCH_PARENT
type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
format = PixelFormat.TRANSLUCENT
gravity = Gravity.BOTTOM
dimAmount = 0.3f
flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_FULLSCREEN or
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_DIM_BEHIND or
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
}
private val mWindowManager: WindowManager
init {
val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
mView = layoutInflater.inflate(R.layout.popup_window, null)
@@ -56,7 +67,29 @@ class Window (context: Context) {
ll.setOnClickListener {
close()
}
ll.setViewTreeLifecycleOwner(mView.findViewTreeLifecycleOwner())
@Suppress("DEPRECATION")
mView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
mView.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
val touchY = event.rawY
val popupTop = mView.top
if (touchY < popupTop) {
close()
true
} else {
false
}
} else {
false
}
}
mWindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
}
@@ -91,49 +124,6 @@ class Window (context: Context) {
batteryCaseText.text = batteryStatus.find { it.component == BatteryComponent.CASE }?.let {
"\uDBC3\uDE6C ${it.level}%"
} ?: ""
// composeView.setContent {
// Row (
// modifier = Modifier
// .fillMaxWidth(),
// horizontalArrangement = Arrangement.Center,
// verticalAlignment = Alignment.CenterVertically
// ) {
// Row (
// modifier = Modifier
// .fillMaxWidth(0.5f),
// horizontalArrangement = Arrangement.SpaceBetween
// ){
// val left = batteryStatus.find { it.component == BatteryComponent.LEFT }
// val right = batteryStatus.find { it.component == BatteryComponent.RIGHT }
// if ((right?.status == BatteryStatus.CHARGING && left?.status == BatteryStatus.CHARGING) || (left?.status == BatteryStatus.NOT_CHARGING && right?.status == BatteryStatus.NOT_CHARGING))
// {
// BatteryIndicator(right.level.let { left.level.coerceAtMost(it) }, left.status == BatteryStatus.CHARGING)
// }
// else {
// Row {
// if (left?.status != BatteryStatus.DISCONNECTED) {
// Text(text = "\uDBC6\uDCE5", fontFamily = FontFamily(Font(R.font.sf_pro)))
// BatteryIndicator(left?.level ?: 0, left?.status == BatteryStatus.CHARGING)
// Spacer(modifier = Modifier.width(16.dp))
// }
// if (right?.status != BatteryStatus.DISCONNECTED) {
// Text(text = "\uDBC6\uDCE8", fontFamily = FontFamily(Font(R.font.sf_pro)))
// BatteryIndicator(right?.level ?: 0, right?.status == BatteryStatus.CHARGING)
// }
// }
// }
// }
// Row (
// modifier = Modifier
// .fillMaxWidth(),
// horizontalArrangement = Arrangement.Center
// ) {
// val case =
// batteryStatus.find { it.component == BatteryComponent.CASE }
// BatteryIndicator(case?.level ?: 0)
// }
// }
// }
// Slide-up animation
val displayMetrics = mView.context.resources.displayMetrics

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
Background for widgets to make the rounded corners based on the
appWidgetRadius attribute value
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?attr/appWidgetRadius" />
<solid android:color="?android:attr/colorBackground" />
</shape>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
Background for views inside widgets to make the rounded corners based on the
appWidgetInnerRadius attribute value
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?attr/appWidgetInnerRadius" />
<solid android:color="?android:attr/colorAccent" />
</shape>

View File

@@ -4,16 +4,16 @@
android:shape="rectangle" >
<solid
android:color="#000000" >
android:color="@color/popup_background" >
</solid>
<padding
android:bottom="64dp"
android:bottom="56dp"
android:top="16dp">
</padding>
<corners
android:radius="48dp">
android:radius="56dp">
</corners>
</shape>

View File

@@ -0,0 +1,19 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/Widget.ALN.AppWidget.Container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/Theme.ALN.AppWidgetContainer">
<TextView
android:id="@+id/appwidget_text"
style="@style/Widget.ALN.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_margin="8dp"
android:contentDescription="@string/appwidget_text"
android:text="@string/appwidget_text"
android:textSize="24sp"
android:textStyle="bold|italic" />
</RelativeLayout>

View File

@@ -25,7 +25,7 @@
android:fontFamily="@font/sf_pro"
android:gravity="center"
android:text="Kavish's AirPods Pro"
android:textColor="@color/white"
android:textColor="@color/popup_text"
android:textSize="28sp"
app:layout_constraintTop_toTopOf="parent"
@@ -72,7 +72,7 @@
android:layout_marginTop="16dp"
android:fontFamily="@font/sf_pro"
android:text=""
android:textColor="@color/white"
android:textColor="@color/popup_text"
android:textSize="20sp"
android:id="@+id/left_battery"
android:gravity="center"
@@ -88,7 +88,7 @@
android:gravity="center"
android:text=""
android:id="@+id/right_battery"
android:textColor="@color/white"
android:textColor="@color/popup_text"
android:textSize="20sp" />
</LinearLayout>
@@ -103,7 +103,7 @@
android:fontFamily="@font/sf_pro"
android:gravity="center"
android:text=""
android:textColor="@color/white"
android:textColor="@color/popup_text"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>

Binary file not shown.

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Having themes.xml for night-v31 because of the priority order of the resource qualifiers.
-->
<style name="Theme.ALN.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="appWidgetRadius">@android:dimen/system_app_widget_background_radius</item>
<item name="appWidgetInnerRadius">@android:dimen/system_app_widget_inner_radius</item>
</style>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="popup_background">#1C1B1E</color>
<color name="popup_text">@color/white</color>
</resources>

View File

@@ -0,0 +1,14 @@
<resources>
<style name="Widget.ALN.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_background</item>
</style>
<style name="Widget.ALN.AppWidget.InnerView" parent="android:Widget">
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_inner_view_background</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
</resources>

View File

@@ -0,0 +1,16 @@
<resources>
<style name="Widget.ALN.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_background</item>
<item name="android:clipToOutline">true</item>
</style>
<style name="Widget.ALN.AppWidget.InnerView" parent="android:Widget">
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_inner_view_background</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:clipToOutline">true</item>
</style>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Having themes.xml for v31 variant because @android:dimen/system_app_widget_background_radius
and @android:dimen/system_app_widget_internal_padding requires API level 31
-->
<style name="Theme.ALN.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="appWidgetRadius">@android:dimen/system_app_widget_background_radius</item>
<item name="appWidgetInnerRadius">@android:dimen/system_app_widget_inner_radius</item>
</style>
</resources>

View File

@@ -0,0 +1,7 @@
<resources>
<declare-styleable name="AppWidgetAttrs">
<attr name="appWidgetPadding" format="dimension" />
<attr name="appWidgetInnerRadius" format="dimension" />
<attr name="appWidgetRadius" format="dimension" />
</declare-styleable>
</resources>

View File

@@ -2,4 +2,10 @@
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="popup_background">#FFFFFF</color>
<color name="popup_text">@color/black</color>
<color name="light_blue_50">#FFE1F5FE</color>
<color name="light_blue_200">#FF81D4FA</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
<dimen name="widget_margin">0dp</dimen>
</resources>

View File

@@ -1,4 +1,7 @@
<resources>
<string name="app_name">ALN</string>
<string name="title_activity_custom_device">GATT Testing</string>
<string name="appwidget_text">EXAMPLE</string>
<string name="add_widget">Add widget</string>
<string name="app_widget_description">This is an app widget description</string>
</resources>

View File

@@ -0,0 +1,12 @@
<resources>
<style name="Widget.ALN.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:background">?android:attr/colorBackground</item>
</style>
<style name="Widget.ALN.AppWidget.InnerView" parent="android:Widget">
<item name="android:background">?android:attr/colorBackground</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
</resources>

View File

@@ -1,4 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.ALN" parent="android:Theme.Material.Light.NoActionBar" />
<style name="Theme.ALN.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
<!-- Radius of the outer bound of widgets to make the rounded corners -->
<item name="appWidgetRadius">16dp</item>
<!--
Radius of the inner view's bound of widgets to make the rounded corners.
It needs to be 8dp or less than the value of appWidgetRadius
-->
<item name="appWidgetInnerRadius">8dp</item>
</style>
<style name="Theme.ALN.AppWidgetContainer" parent="Theme.ALN.AppWidgetContainerParent">
<!-- Apply padding to avoid the content of the widget colliding with the rounded corners -->
<item name="appWidgetPadding">16dp</item>
</style>
</resources>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_widget_description"
android:initialKeyguardLayout="@layout/battery_widget"
android:initialLayout="@layout/battery_widget"
android:minWidth="40dp"
android:minHeight="40dp"
android:previewImage="@drawable/example_appwidget_preview"
android:previewLayout="@layout/battery_widget"
android:resizeMode="horizontal|vertical"
android:targetCellWidth="1"
android:targetCellHeight="1"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen|keyguard" />