fixed: removed new_piped_extractor from android gradle dependence
3
android/.gitignore
vendored
@ -5,9 +5,10 @@ gradle-wrapper.jar
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
.cxx/
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||
# See https://flutter.dev/to/reference-keystore
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
|
@ -1,139 +0,0 @@
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
id "kotlin-android"
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
}
|
||||
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
def composeVersion = "1.4.8"
|
||||
|
||||
android {
|
||||
namespace "oss.krtirtho.spotube"
|
||||
|
||||
compileSdkVersion 35
|
||||
|
||||
ndkVersion = "27.0.12077973"
|
||||
|
||||
compileOptions {
|
||||
coreLibraryDesugaringEnabled true
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion "$composeVersion" // Correlates with org.jetbrains.kotlin.android plugin in settings.gradle
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "oss.krtirtho.spotube"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 35
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
multiDexEnabled true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
debug {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "default"
|
||||
|
||||
productFlavors {
|
||||
nightly {
|
||||
dimension "default"
|
||||
resValue "string", "app_name_en", "Spotube Nightly"
|
||||
applicationIdSuffix ".nightly"
|
||||
versionNameSuffix "-nightly"
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
dev {
|
||||
dimension "default"
|
||||
resValue "string", "app_name_en", "Spotube Dev"
|
||||
applicationIdSuffix ".dev"
|
||||
versionNameSuffix "-dev"
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
stable {
|
||||
dimension "default"
|
||||
resValue "string", "app_name_en", "Spotube"
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
resources.excludes += "DebugProbesKt.bin"
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
}
|
||||
|
||||
def glanceVersion = "1.1.1"
|
||||
dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
|
||||
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
|
||||
// other deps so just ignore
|
||||
implementation 'com.android.support:multidex:2.0.1'
|
||||
|
||||
implementation "androidx.glance:glance-appwidget:$glanceVersion"
|
||||
implementation "androidx.glance:glance-appwidget-preview:$glanceVersion"
|
||||
implementation "androidx.glance:glance-preview:$glanceVersion"
|
||||
implementation "androidx.glance:glance-material3:$glanceVersion"
|
||||
implementation "androidx.glance:glance-material:$glanceVersion"
|
||||
implementation "androidx.work:work-runtime-ktx:2.8.1"
|
||||
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3"
|
||||
implementation 'com.google.code.gson:gson:2.11.0'
|
||||
}
|
44
android/app/build.gradle.kts
Normal file
@ -0,0 +1,44 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.spotube"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "com.example.spotube"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
minSdk = flutter.minSdkVersion
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
21
android/app/proguard-rules.pro
vendored
@ -1,21 +0,0 @@
|
||||
-keep class androidx.lifecycle.DefaultLifecycleObserver
|
||||
|
||||
-keepnames class kotlinx.serialization.** { *; }
|
||||
-keepnames class oss.krtirtho.spotube.glance.models.** { *; }
|
||||
-keep @kotlinx.serialization.Serializable class *
|
||||
-keepclassmembers class ** {
|
||||
@kotlinx.serialization.* <fields>;
|
||||
}
|
||||
|
||||
## We don't need beans
|
||||
-dontwarn java.beans.BeanDescriptor
|
||||
-dontwarn java.beans.BeanInfo
|
||||
-dontwarn java.beans.IntrospectionException
|
||||
-dontwarn java.beans.Introspector
|
||||
-dontwarn java.beans.PropertyDescriptor
|
||||
|
||||
## Rules for NewPipeExtractor
|
||||
-keep class org.schabi.newpipe.extractor.timeago.patterns.** { *; }
|
||||
-keep class org.mozilla.javascript.** { *; }
|
||||
-keep class org.mozilla.classfile.ClassFileWriter
|
||||
-dontwarn org.mozilla.javascript.tools.**
|
@ -1,6 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Flutter needs it to communicate with the running application
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
@ -1,141 +1,45 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
|
||||
<queries>
|
||||
<!-- If your app opens https URLs -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:label="spotube"
|
||||
android:name="${applicationName}"
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name_en"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:usesCleartextTraffic="true">
|
||||
<!-- Enable Impeller -->
|
||||
<!-- <meta-data
|
||||
android:name="io.flutter.embedding.android.EnableImpeller"
|
||||
android:value="false" /> -->
|
||||
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name="com.ryanheise.audioservice.AudioServiceActivity"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!--
|
||||
Specifies an Android theme to apply to this Activity as soon as
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI.
|
||||
-->
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme" />
|
||||
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="open.spotify.com"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="text/*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Accepts URIs that begin with "spotify:// -->
|
||||
<data android:scheme="spotify" />
|
||||
<data android:scheme="spotube" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- AudioService Config -->
|
||||
<service
|
||||
android:name="com.ryanheise.audioservice.AudioService"
|
||||
android:exported="true"
|
||||
android:foregroundServiceType="mediaPlayback">
|
||||
<intent-filter>
|
||||
<action android:name="android.media.browse.MediaBrowserService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<receiver
|
||||
android:name="com.ryanheise.audioservice.MediaButtonReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!-- =================== -->
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.car.application"
|
||||
android:resource="@xml/automotive_app_desc" />
|
||||
|
||||
<!-- Home Widget config -->
|
||||
<receiver
|
||||
android:name=".glance.HomePlayerWidgetReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/home_player_widget_config" />
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="es.antonborri.home_widget.action.BACKGROUND" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
<!-- =================== -->
|
||||
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
android:value="2"/>
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
@ -1,25 +0,0 @@
|
||||
// Generated file.
|
||||
//
|
||||
// If you wish to remove Flutter's multidex support, delete this entire file.
|
||||
//
|
||||
// Modifications to this file should be done in a copy under a different name
|
||||
// as this file may be regenerated.
|
||||
|
||||
package io.flutter.app;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.multidex.MultiDex;
|
||||
|
||||
/**
|
||||
* Extension of {@link android.app.Application}, adding multidex support.
|
||||
*/
|
||||
public class FlutterMultiDexApplication extends Application {
|
||||
@Override
|
||||
@CallSuper
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
MultiDex.install(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.example.spotube
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity : FlutterActivity()
|
@ -1,6 +0,0 @@
|
||||
package oss.krtirtho.spotube
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity: FlutterActivity() {
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance
|
||||
|
||||
import HomeWidgetGlanceState
|
||||
import HomeWidgetGlanceStateDefinition
|
||||
import android.R
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Icon
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.glance.GlanceId
|
||||
import androidx.glance.GlanceModifier
|
||||
import androidx.glance.GlanceTheme
|
||||
import androidx.glance.Image
|
||||
import androidx.glance.ImageProvider
|
||||
import androidx.glance.LocalSize
|
||||
import androidx.glance.action.ActionParameters
|
||||
import androidx.glance.action.actionParametersOf
|
||||
import androidx.glance.action.clickable
|
||||
import androidx.glance.background
|
||||
import androidx.glance.appwidget.GlanceAppWidget
|
||||
import androidx.glance.appwidget.SizeMode
|
||||
import androidx.glance.appwidget.action.ActionCallback
|
||||
import androidx.glance.appwidget.action.actionRunCallback
|
||||
import androidx.glance.appwidget.background
|
||||
import androidx.glance.appwidget.components.CircleIconButton
|
||||
import androidx.glance.appwidget.components.Scaffold
|
||||
import androidx.glance.appwidget.cornerRadius
|
||||
import androidx.glance.appwidget.provideContent
|
||||
import androidx.glance.background
|
||||
import androidx.glance.currentState
|
||||
import androidx.glance.layout.Alignment
|
||||
import androidx.glance.layout.Box
|
||||
import androidx.glance.layout.Column
|
||||
import androidx.glance.layout.ContentScale
|
||||
import androidx.glance.layout.Row
|
||||
import androidx.glance.layout.Spacer
|
||||
import androidx.glance.layout.fillMaxSize
|
||||
import androidx.glance.layout.fillMaxWidth
|
||||
import androidx.glance.layout.padding
|
||||
import androidx.glance.layout.size
|
||||
import androidx.glance.preview.ExperimentalGlancePreviewApi
|
||||
import androidx.glance.preview.Preview
|
||||
import androidx.glance.state.GlanceStateDefinition
|
||||
import com.google.gson.Gson
|
||||
import es.antonborri.home_widget.HomeWidgetBackgroundIntent
|
||||
import es.antonborri.home_widget.actionStartActivity
|
||||
import oss.krtirtho.spotube.MainActivity
|
||||
import oss.krtirtho.spotube.glance.models.Track
|
||||
import oss.krtirtho.spotube.glance.widgets.FlutterAssetImageProvider
|
||||
import oss.krtirtho.spotube.glance.widgets.TrackDetailsView
|
||||
import oss.krtirtho.spotube.glance.widgets.TrackProgress
|
||||
|
||||
val gson = Gson()
|
||||
val serverAddressKey = ActionParameters.Key<String>("serverAddress")
|
||||
|
||||
class Breakpoints {
|
||||
companion object {
|
||||
val SMALL_SQUARE = DpSize(100.dp, 100.dp)
|
||||
val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp)
|
||||
val BIG_SQUARE = DpSize(250.dp, 250.dp)
|
||||
}
|
||||
}
|
||||
|
||||
class HomePlayerWidget : GlanceAppWidget() {
|
||||
|
||||
override val sizeMode = SizeMode.Responsive(
|
||||
setOf(
|
||||
Breakpoints.SMALL_SQUARE,
|
||||
Breakpoints.HORIZONTAL_RECTANGLE,
|
||||
Breakpoints.BIG_SQUARE
|
||||
)
|
||||
)
|
||||
|
||||
override val stateDefinition: GlanceStateDefinition<*>?
|
||||
get() = HomeWidgetGlanceStateDefinition()
|
||||
|
||||
override suspend fun provideGlance(context: Context, id: GlanceId) {
|
||||
provideContent {
|
||||
GlanceContent(context, currentState())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalGlancePreviewApi::class)
|
||||
@Preview(widthDp = 100, heightDp = 100)
|
||||
@Composable
|
||||
private fun GlanceContent(context: Context, currentState: HomeWidgetGlanceState) {
|
||||
val prefs = currentState.preferences
|
||||
val size = LocalSize.current
|
||||
|
||||
val activeTrackStr = prefs.getString("activeTrack", null)
|
||||
|
||||
val isPlaying = prefs.getBoolean("isPlaying", false)
|
||||
val playbackServerAddress = prefs.getString("playbackServerAddress", null) ?: ""
|
||||
|
||||
var activeTrack: Track? = null
|
||||
if (activeTrackStr != null) {
|
||||
activeTrack = gson.fromJson(activeTrackStr, Track::class.java)
|
||||
}
|
||||
|
||||
|
||||
val playIcon = Icon.createWithResource(context, R.drawable.ic_media_play);
|
||||
val pauseIcon = Icon.createWithResource(context, R.drawable.ic_media_pause);
|
||||
val previousIcon = Icon.createWithResource(context, R.drawable.ic_media_previous);
|
||||
val nextIcon = Icon.createWithResource(context, R.drawable.ic_media_next);
|
||||
|
||||
GlanceTheme {
|
||||
Box(
|
||||
modifier = GlanceModifier
|
||||
.fillMaxSize()
|
||||
.cornerRadius(8.dp)
|
||||
.background(
|
||||
color = GlanceTheme.colors.surface.getColor(context)
|
||||
)
|
||||
.clickable {
|
||||
actionStartActivity<MainActivity>(context)
|
||||
}
|
||||
,
|
||||
) {
|
||||
Box(
|
||||
modifier = GlanceModifier
|
||||
.background(
|
||||
color =
|
||||
GlanceTheme.colors.surface.getColor(context)
|
||||
.copy(alpha = 0.5f),
|
||||
)
|
||||
.fillMaxSize(),
|
||||
) {}
|
||||
Column(
|
||||
modifier = GlanceModifier.padding(top = 10.dp, start = 10.dp, end = 10.dp)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.Vertical.CenterVertically) {
|
||||
TrackDetailsView(activeTrack)
|
||||
}
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
if (size != Breakpoints.SMALL_SQUARE) {
|
||||
TrackProgress(prefs)
|
||||
}
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
Row(
|
||||
modifier = GlanceModifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.Horizontal.CenterHorizontally
|
||||
) {
|
||||
CircleIconButton(
|
||||
imageProvider = ImageProvider(previousIcon),
|
||||
contentDescription = "Previous",
|
||||
onClick = actionRunCallback<PreviousAction>(
|
||||
parameters = actionParametersOf(serverAddressKey to playbackServerAddress)
|
||||
)
|
||||
)
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
CircleIconButton(
|
||||
imageProvider =
|
||||
if (isPlaying) ImageProvider(pauseIcon)
|
||||
else ImageProvider(playIcon),
|
||||
contentDescription = "Play/Pause",
|
||||
onClick = actionRunCallback<PlayPauseAction>(
|
||||
parameters = actionParametersOf(serverAddressKey to playbackServerAddress)
|
||||
)
|
||||
)
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
CircleIconButton(
|
||||
imageProvider = ImageProvider(nextIcon),
|
||||
contentDescription = "Previous",
|
||||
onClick = actionRunCallback<NextAction>(
|
||||
parameters = actionParametersOf(
|
||||
serverAddressKey to playbackServerAddress
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PlayPauseAction : InteractiveAction("toggle-playback")
|
||||
class NextAction : InteractiveAction("next")
|
||||
class PreviousAction : InteractiveAction("previous")
|
||||
|
||||
|
||||
abstract class InteractiveAction(val command: String) : ActionCallback {
|
||||
override suspend fun onAction(
|
||||
context: Context,
|
||||
glanceId: GlanceId,
|
||||
parameters: ActionParameters
|
||||
) {
|
||||
val serverAddress = parameters[serverAddressKey] ?: ""
|
||||
|
||||
Log.d("HomePlayerWidget", "Sending command $command to $serverAddress")
|
||||
|
||||
if (serverAddress == null || serverAddress.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(
|
||||
context,
|
||||
Uri.parse("spotube://playback/$command?serverAddress=$serverAddress")
|
||||
)
|
||||
backgroundIntent.send()
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance
|
||||
|
||||
import HomeWidgetGlanceWidgetReceiver
|
||||
|
||||
class HomePlayerWidgetReceiver : HomeWidgetGlanceWidgetReceiver<HomePlayerWidget>() {
|
||||
override val glanceAppWidget = HomePlayerWidget()
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance.models
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class AlbumSimple(
|
||||
@SerializedName("album_type")
|
||||
val albumType: AlbumType?,
|
||||
|
||||
@SerializedName("available_markets")
|
||||
val availableMarkets: List<Market>?,
|
||||
|
||||
val href: String?,
|
||||
val id: String?,
|
||||
val images: List<Image>?,
|
||||
val name: String?,
|
||||
|
||||
@SerializedName("release_date")
|
||||
val releaseDate: String?,
|
||||
|
||||
@SerializedName("release_date_precision")
|
||||
val releaseDatePrecision: DatePrecision?,
|
||||
|
||||
val type: String?,
|
||||
val uri: String?,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
enum class AlbumType {
|
||||
album,
|
||||
single,
|
||||
compilation
|
||||
}
|
||||
|
||||
enum class DatePrecision {
|
||||
year,
|
||||
month,
|
||||
day
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance.models
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Artist(
|
||||
val href: String?,
|
||||
val id: String?,
|
||||
val name: String?,
|
||||
val type: String?,
|
||||
val uri: String?,
|
||||
|
||||
val followers: Followers?,
|
||||
val genres: List<String>?,
|
||||
val images: List<Image>?,
|
||||
|
||||
@SerializedName("popularity")
|
||||
val popularity: Int?
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Followers(
|
||||
val total: Int?
|
||||
)
|
@ -1,10 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Image(
|
||||
val height: Int?,
|
||||
val width: Int?,
|
||||
val path: String,
|
||||
)
|
@ -1,37 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance.models
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
@Serializable
|
||||
data class Track(
|
||||
val album: AlbumSimple?, val artists: List<Artist>?,
|
||||
|
||||
@SerializedName("available_markets") val availableMarkets: List<Market>?,
|
||||
|
||||
@SerializedName("disc_number") val discNumber: Int?,
|
||||
|
||||
@SerializedName("duration_ms") val durationMs: Int,
|
||||
|
||||
val explicit: Boolean?, val href: String?, val id: String?,
|
||||
|
||||
@SerializedName("is_playable") val isPlayable: Boolean?,
|
||||
|
||||
val name: String?,
|
||||
|
||||
@SerializedName("popularity") val popularity: Int?,
|
||||
|
||||
@SerializedName("preview_url") val previewUrl: String?,
|
||||
|
||||
@SerializedName("track_number") val trackNumber: Int?,
|
||||
|
||||
val type: String?, val uri: String?
|
||||
) {
|
||||
val duration: kotlin.time.Duration
|
||||
get() = durationMs.toLong().milliseconds
|
||||
}
|
||||
|
||||
enum class Market {
|
||||
AD, AE, AF, AG, AI, AL, AM, AO, AQ, AR, AS, AT, AU, AW, AX, AZ, BA, BB, BD, BE, BF, BG, BH, BI, BJ, BL, BM, BN, BO, BQ, BR, BS, BT, BV, BW, BY, BZ, CA, CC, CD, CF, CG, CH, CI, CK, CL, CM, CN, CO, CR, CU, CV, CW, CX, CY, CZ, DE, DJ, DK, DM, DO, DZ, EC, EE, EG, EH, ER, ES, ET, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GP, GQ, GR, GS, GT, GU, GW, GY, HK, HM, HN, HR, HT, HU, ID, IE, IL, IM, IN, IO, IQ, IR, IS, IT, JE, JM, JO, JP, KE, KG, KH, KI, KM, KN, KP, KR, KW, KY, KZ, LA, LB, LC, LI, LK, LR, LS, LT, LU, LV, LY, MA, MC, MD, ME, MF, MG, MH, MK, ML, MM, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NI, NL, NO, NP, NR, NU, NZ, OM, PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PS, PT, PW, PY, QA, RE, RO, RS, RU, RW, SA, SB, SC, SD, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SO, SR, SS, ST, SV, SX, SY, SZ, TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TR, TT, TV, TW, TZ, UA, UG, UM, US, UY, UZ, VA, VC, VE, VG, VI, VN, VU, WF, WS, XK, YE, YT, ZA, ZM, ZW,
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance.widgets
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import android.util.Base64
|
||||
import androidx.glance.ImageProvider
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun Base64ImageProvider(base64: String): ImageProvider {
|
||||
var bytes = Base64.decode(base64, Base64.DEFAULT);
|
||||
|
||||
var bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size);
|
||||
|
||||
return ImageProvider(bitmap)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.glance.ImageProvider
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun FlutterAssetImageProvider(context: Context, path: String): ImageProvider {
|
||||
var inputStream = context.assets.open("flutter_assets/$path")
|
||||
|
||||
return ImageProvider(
|
||||
BitmapFactory.decodeStream(inputStream)
|
||||
)
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance.widgets
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.glance.GlanceModifier
|
||||
import androidx.glance.GlanceTheme
|
||||
import androidx.glance.Image
|
||||
import androidx.glance.ImageProvider
|
||||
import androidx.glance.LocalContext
|
||||
import androidx.glance.LocalSize
|
||||
import androidx.glance.appwidget.cornerRadius
|
||||
import androidx.glance.layout.Alignment
|
||||
import androidx.glance.layout.Row
|
||||
import androidx.glance.layout.Column
|
||||
import androidx.glance.layout.ContentScale
|
||||
import androidx.glance.layout.Spacer
|
||||
import androidx.glance.layout.size
|
||||
import androidx.glance.text.FontWeight
|
||||
import androidx.glance.text.Text
|
||||
import androidx.glance.text.TextStyle
|
||||
import oss.krtirtho.spotube.glance.Breakpoints
|
||||
import oss.krtirtho.spotube.glance.models.Track
|
||||
|
||||
@Composable
|
||||
fun TrackDetailsView(activeTrack: Track?) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val size = LocalSize.current
|
||||
|
||||
val artistStr = activeTrack?.artists?.map { it.name }?.joinToString(", ") ?: "<No Artist>"
|
||||
val imgLocalPath = activeTrack?.album?.images?.get(0)?.path;
|
||||
val title = activeTrack?.name ?: "<No Track>"
|
||||
|
||||
|
||||
Image(
|
||||
provider =
|
||||
if (imgLocalPath == null)
|
||||
ImageProvider(
|
||||
BitmapFactory.decodeResource(
|
||||
context.resources,
|
||||
android.R.drawable.ic_delete
|
||||
)
|
||||
)
|
||||
else ImageProvider(BitmapFactory.decodeFile(imgLocalPath)),
|
||||
contentDescription = "Album Art",
|
||||
modifier = GlanceModifier.cornerRadius(8.dp)
|
||||
.size(
|
||||
if (size.height < 200.dp) 50.dp
|
||||
else 100.dp
|
||||
),
|
||||
contentScale = ContentScale.Fit
|
||||
)
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
Column {
|
||||
Text(
|
||||
text = title,
|
||||
style = TextStyle(
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = GlanceTheme.colors.onBackground
|
||||
),
|
||||
)
|
||||
if (size != Breakpoints.SMALL_SQUARE) {
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
Text(
|
||||
text = artistStr,
|
||||
style = TextStyle(
|
||||
fontSize = 14.sp,
|
||||
color = GlanceTheme.colors.onBackground
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package oss.krtirtho.spotube.glance.widgets
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.glance.GlanceModifier
|
||||
import androidx.glance.GlanceTheme
|
||||
import androidx.glance.LocalSize
|
||||
import androidx.glance.appwidget.LinearProgressIndicator
|
||||
import androidx.glance.layout.Column
|
||||
import androidx.glance.layout.Row
|
||||
import androidx.glance.layout.Spacer
|
||||
import androidx.glance.layout.fillMaxWidth
|
||||
import androidx.glance.layout.size
|
||||
import androidx.glance.text.Text
|
||||
import androidx.glance.text.TextStyle
|
||||
import kotlin.math.max
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import oss.krtirtho.spotube.glance.Breakpoints
|
||||
|
||||
fun Duration.format(): String {
|
||||
return this.toComponents { hour, minutes, seconds, nanoseconds ->
|
||||
var paddedSeconds = seconds.toString().padStart(2, '0')
|
||||
var paddedMinutes = minutes.toString().padStart(2, '0')
|
||||
var paddedHour = hour.toString().padStart(2, '0')
|
||||
if (hour == 0L) {
|
||||
"$paddedMinutes:$paddedSeconds"
|
||||
} else {
|
||||
"$paddedHour:$paddedMinutes:$paddedSeconds"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TrackProgress(prefs: SharedPreferences) {
|
||||
val size = LocalSize.current
|
||||
val position = prefs.getInt("position", 0).seconds
|
||||
var duration = prefs.getInt("duration", 0).seconds
|
||||
|
||||
var progress = position.inWholeSeconds.toFloat() / max(duration.inWholeSeconds.toFloat(), 1.0f)
|
||||
|
||||
var textStyle =
|
||||
TextStyle(
|
||||
color = GlanceTheme.colors.onBackground,
|
||||
)
|
||||
|
||||
if (size == Breakpoints.HORIZONTAL_RECTANGLE) {
|
||||
Row(modifier = GlanceModifier.fillMaxWidth()) {
|
||||
Text(text = position.format(), style = textStyle)
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
LinearProgressIndicator(
|
||||
progress = progress,
|
||||
modifier = GlanceModifier.defaultWeight(),
|
||||
color = GlanceTheme.colors.primary,
|
||||
backgroundColor = GlanceTheme.colors.primaryContainer,
|
||||
)
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
Text(text = duration.format(), style = textStyle)
|
||||
}
|
||||
} else {
|
||||
Column(modifier = GlanceModifier.fillMaxWidth()) {
|
||||
LinearProgressIndicator(
|
||||
progress = progress,
|
||||
modifier = GlanceModifier.fillMaxWidth(),
|
||||
color = GlanceTheme.colors.primary,
|
||||
backgroundColor = GlanceTheme.colors.primaryContainer,
|
||||
)
|
||||
Spacer(modifier = GlanceModifier.size(6.dp))
|
||||
Row(modifier = GlanceModifier.fillMaxWidth()) {
|
||||
Text(text = position.format(), style = textStyle)
|
||||
Spacer(modifier = GlanceModifier.defaultWeight())
|
||||
Text(text = duration.format(), style = textStyle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 214 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 253 KiB |
Before Width: | Height: | Size: 3.1 MiB |
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="bottom" android:src="@drawable/branding"/>
|
||||
</item>
|
||||
<item android:drawable="?android:colorBackground"/>
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
|
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 214 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 253 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 3.1 MiB |
@ -1,27 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="762"
|
||||
android:viewportHeight="762">
|
||||
<path
|
||||
android:pathData="M309.08,370.99L309.08,479.87C309.08,486.36 314.33,491.6 320.83,491.6C327.31,491.6 332.58,486.36 332.58,479.87L332.58,370.99C332.58,364.51 327.31,359.26 320.83,359.26C314.33,359.26 309.08,364.51 309.08,370.99Z"
|
||||
android:strokeLineJoin="miter"
|
||||
android:strokeWidth="14"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="butt"/>
|
||||
<path
|
||||
android:pathData="M254.59,491.73L280.46,491.73L280.46,362.47C280.53,361.85 280.64,361.23 280.64,360.6C280.64,304.83 325.72,259.46 381.12,259.46C436.51,259.46 481.59,304.83 481.59,360.6C481.59,361.45 481.71,362.27 481.84,363.1L481.84,491.73L507.71,491.73C525.72,491.73 540.33,476.65 540.33,458.03L540.33,390.62C540.33,375.26 530.37,362.33 516.78,358.26C515.53,284.17 455.17,224.26 381.12,224.26C307.05,224.26 246.69,284.18 245.45,358.29C231.88,362.36 221.96,375.29 221.96,390.63L221.96,458.03C221.96,476.64 236.56,491.73 254.59,491.73Z"
|
||||
android:strokeLineJoin="miter"
|
||||
android:strokeWidth="20"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="butt"/>
|
||||
<path
|
||||
android:pathData="M431.08,370.99L431.08,479.87C431.08,486.36 436.33,491.6 442.83,491.6C449.31,491.6 454.58,486.36 454.58,479.87L454.58,370.99C454.58,364.51 449.31,359.26 442.83,359.26C436.33,359.26 431.08,364.51 431.08,370.99Z"
|
||||
android:strokeLineJoin="miter"
|
||||
android:strokeWidth="14"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="butt"/>
|
||||
</vector>
|
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="bottom" android:src="@drawable/branding"/>
|
||||
</item>
|
||||
<item android:drawable="@android:color/white"/>
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 544 B |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 1.4 KiB |
@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:windowSplashScreenBackground">#000000</item>
|
||||
<item name="android:windowSplashScreenBrandingImage">@drawable/android12branding</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
<item name="android:windowSplashScreenIconBackgroundColor">#000000</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
@ -3,12 +3,8 @@
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
|
@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:windowSplashScreenBackground">#000000</item>
|
||||
<item name="android:windowSplashScreenBrandingImage">@drawable/android12branding</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
<item name="android:windowSplashScreenIconBackgroundColor">#000000</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#242832</color>
|
||||
</resources>
|
@ -3,12 +3,8 @@
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
Flutter draws its first frame -->
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
|
@ -1,3 +0,0 @@
|
||||
<automotiveApp>
|
||||
<uses name="media" />
|
||||
</automotiveApp>
|
@ -1,7 +0,0 @@
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:initialLayout="@layout/glance_default_loading_layout"
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:updatePeriodMillis="10000">
|
||||
</appwidget-provider>
|
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 220 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 213 KiB |
Before Width: | Height: | Size: 3.1 MiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="bottom" android:src="@drawable/branding"/>
|
||||
</item>
|
||||
</layer-list>
|
Before Width: | Height: | Size: 12 KiB |