Compare commits
No commits in common. "master" and "v1.0" have entirely different histories.
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "ExoPlayer"]
|
||||||
|
path = ExoPlayer
|
||||||
|
url = https://github.com/google/ExoPlayer/
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Tsumugi-app
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
|
<AndroidXmlCodeStyleSettings>
|
||||||
|
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
|
||||||
|
</AndroidXmlCodeStyleSettings>
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<bytecodeTargetLevel target="11" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
|
|
@ -1,19 +1,40 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="testRunner" value="GRADLE" />
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleJvm" value="Android Studio default JDK" />
|
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/av1" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/cast" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/cronet" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/ffmpeg" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/flac" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/gvr" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/ima" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/jobdispatcher" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/leanback" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/mediasession" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/okhttp" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/opus" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/rtmp" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/vp9" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/extensions/workmanager" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/library/all" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/library/core" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/library/dash" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/library/hls" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/library/smoothstreaming" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/library/ui" />
|
||||||
|
<option value="$PROJECT_DIR$/ExoPlayer/testutils" />
|
||||||
<option value="$PROJECT_DIR$/app" />
|
<option value="$PROJECT_DIR$/app" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
|
<option name="testRunner" value="PLATFORM" />
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RemoteRepositoriesConfiguration">
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="central" />
|
|
||||||
<option name="name" value="Maven Central repository" />
|
|
||||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="jboss.community" />
|
|
||||||
<option name="name" value="JBoss Community repository" />
|
|
||||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="BintrayJCenter" />
|
|
||||||
<option name="name" value="BintrayJCenter" />
|
|
||||||
<option name="url" value="https://jcenter.bintray.com/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="maven" />
|
|
||||||
<option name="name" value="maven" />
|
|
||||||
<option name="url" value="https://jitpack.io" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="Google" />
|
|
||||||
<option name="name" value="Google" />
|
|
||||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="MavenRepo" />
|
|
||||||
<option name="name" value="MavenRepo" />
|
|
||||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
|
||||||
</remote-repository>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RunConfigurationProducerService">
|
||||||
|
<option name="ignoredProducers">
|
||||||
|
<set>
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -2,5 +2,6 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/ExoPlayer" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 24a19264dbf35e326bbd7bb36c232eb180e1e26d
|
||||||
12
PRIVACY.md
|
|
@ -1,12 +0,0 @@
|
||||||
PRIVACY POLICY [ENGLISH]
|
|
||||||
|
|
||||||
This app does not gather nor upload any data from your device.
|
|
||||||
|
|
||||||
This app needs permission to read your phone state (android.permission.READ\_PHONE\_STATE) only and exclusively to cut down the volume of the radio when you receive a phone call. Please feel free to check the source code on GitHub at https://github.com/yattoz/webradio-app to assess this.
|
|
||||||
|
|
||||||
|
|
||||||
DECLARATION DE CONFIDENTIALITE [FRANCAIS]
|
|
||||||
|
|
||||||
Cette application ne récupère ni n'émet aucune donnée de votre appareil.
|
|
||||||
|
|
||||||
Cette application nécessite de lire l'état de votre téléphone (android.permission.READ\_PHONE\_STATE) uniquement et exclusivement pour couper le volume de la radio si vous recevez un appel téléphonique. Le code source est mis à votre disposition sur GitHub à l'adresse https://github.com/yattoz/webradio-app où vous pouvez vérifier ceci.
|
|
||||||
|
|
@ -16,21 +16,21 @@ configurations.all {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 32
|
compileSdkVersion 29
|
||||||
|
buildToolsVersion "29.0.2"
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_11
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_11
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "11"
|
jvmTarget = "1.8"
|
||||||
}
|
}
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "fr.riff_app.riff"
|
applicationId "fr.forum_thalie.tsumugi"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 32
|
targetSdkVersion 29
|
||||||
multiDexEnabled true
|
versionCode 100
|
||||||
versionCode 121
|
versionName "1.0.0"
|
||||||
versionName "1.2.1"
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
|
|
@ -48,9 +48,6 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
def multidex_version = "2.0.1"
|
|
||||||
implementation "androidx.multidex:multidex:$multidex_version"
|
|
||||||
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
/*
|
/*
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
|
|
@ -71,18 +68,15 @@ dependencies {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
implementation "androidx.media:media:1.5.0"
|
implementation "androidx.media:media:1.1.0"
|
||||||
|
//implementation 'com.google.android.exoplayer:exoplayer:2.11.1'
|
||||||
|
implementation project(':exoplayer-library') // uses local ExoPlayer clone, from dev-v2 branch (fixes ISO-8859-1 ICY metadata
|
||||||
|
|
||||||
//noinspection GradleDependency
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
|
||||||
implementation 'com.google.android.exoplayer:exoplayer:2.11.3'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0'
|
||||||
|
|
||||||
//implementation project(':exoplayer-library') // uses local ExoPlayer clone, from dev-v2 branch (fixes ISO-8859-1 ICY metadata
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
|
implementation 'androidx.preference:preference:1.1.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
|
|
||||||
|
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
|
||||||
implementation 'androidx.preference:preference-ktx:1.2.0'
|
|
||||||
|
|
||||||
// jsoup HTML parser library @ https://jsoup.org/
|
// jsoup HTML parser library @ https://jsoup.org/
|
||||||
// implementation 'org.jsoup:jsoup:1.12.1'
|
// implementation 'org.jsoup:jsoup:1.12.1'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
fun useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
assertEquals("fr.forum_thalie.tsumugi", appContext.packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
|
@ -1,14 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
android:viewportHeight="108">
|
|
||||||
<group android:scaleX="0.84375"
|
|
||||||
android:scaleY="0.84375">
|
|
||||||
<path
|
|
||||||
android:strokeWidth="1"
|
|
||||||
android:pathData="M-22.4,-18.02h249.46v189.63h-249.46z"
|
|
||||||
android:fillColor="#000000"
|
|
||||||
android:strokeColor="#ffffff"/>
|
|
||||||
</group>
|
|
||||||
</vector>
|
|
||||||
|
Before Width: | Height: | Size: 5.8 KiB |
|
|
@ -1,5 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="fr.riff_app.riff">
|
package="fr.forum_thalie.tsumugi">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
@ -10,11 +10,9 @@
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- needed for API 28 -->
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- needed for API 28 -->
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.SET_ALARM"/>
|
<uses-permission android:name="android.permission.SET_ALARM"/>
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|
@ -23,25 +21,27 @@
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme.Launcher"
|
android:theme="@style/AppTheme.Launcher"
|
||||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning"
|
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
|
||||||
android:name="androidx.multidex.MultiDexApplication">
|
|
||||||
<service
|
<service
|
||||||
android:name=".RadioService"
|
android:name=".RadioService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.media.browse.MediaBrowserService" />
|
<action android:name="android.media.browse.MediaBrowserService" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
<service android:name=".streamerNotificationService.StreamerMonitorService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true"/>
|
||||||
|
|
||||||
<receiver android:name=".BootBroadcastReceiver"
|
<receiver android:name=".BootBroadcastReceiver"
|
||||||
android:directBootAware="true"
|
android:directBootAware="true"
|
||||||
tools:targetApi="n"
|
tools:targetApi="n">
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
<action android:name="fr.riff_app.riff.PLAY_OR_FALLBACK" />
|
<action android:name="fr.forum_thalie.tsumugi.PLAY_OR_FALLBACK" />
|
||||||
<action android:name="fr.riff_app.riff.NOTIFY" /> <!-- this is for Snooze -->
|
<action android:name="fr.forum_thalie.tsumugi.NOTIFY" /> <!-- this is for Snooze -->
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
@ -49,9 +49,9 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="fullUser"
|
android:screenOrientation="fullSensor">
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
|
@ -63,10 +63,9 @@
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:parentActivityName=".MainActivity"
|
android:parentActivityName=".MainActivity"
|
||||||
android:screenOrientation="fullUser" />
|
android:screenOrientation="fullSensor" />
|
||||||
|
|
||||||
<receiver android:name="androidx.media.session.MediaButtonReceiver"
|
<receiver android:name="androidx.media.session.MediaButtonReceiver">
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
|
||||||
|
|
@ -1,78 +1,66 @@
|
||||||
{
|
{
|
||||||
"planning": [
|
"planning": [
|
||||||
{
|
{
|
||||||
"title": "La playlist Base Rock",
|
"title": "Musique Classique",
|
||||||
"periodicity": "1111111",
|
"periodicity": "1111111",
|
||||||
"hour_begin": "00:00",
|
"hour_begin": "6:00",
|
||||||
|
"hour_end": "7:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Jeux Vidéos Matin",
|
||||||
|
"periodicity": "1111100",
|
||||||
|
"hour_begin": "09:00",
|
||||||
|
"hour_end": "10:30"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Anime Matin",
|
||||||
|
"periodicity": "1111100",
|
||||||
|
"hour_begin": "10:30",
|
||||||
|
"hour_end": "12:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Jeux Vidéos Aprem'",
|
||||||
|
"periodicity": "1111111",
|
||||||
|
"hour_begin": "14:00",
|
||||||
|
"hour_end": "15:30"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Anime Aprem'",
|
||||||
|
"periodicity": "1111111",
|
||||||
|
"hour_begin": "15:30",
|
||||||
|
"hour_end": "17:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Jeux Vidéos Soirée",
|
||||||
|
"periodicity": "1111100",
|
||||||
|
"hour_begin": "19:00",
|
||||||
|
"hour_end": "20:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Anime Soirée",
|
||||||
|
"periodicity": "1111100",
|
||||||
|
"hour_begin": "20:00",
|
||||||
"hour_end": "21:00"
|
"hour_end": "21:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Only Covers",
|
"title": "Anime Nuit",
|
||||||
"periodicity": "1000000",
|
"periodicity": "1111111",
|
||||||
"hour_begin": "20:30",
|
"hour_begin": "00:00",
|
||||||
"hour_end": "00:00"
|
"hour_end": "01:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Only Indies",
|
"title": "Jeux Vidéos Nuit",
|
||||||
"periodicity": "0100000",
|
"periodicity": "1111111",
|
||||||
"hour_begin": "20:30",
|
"hour_begin": "01:00",
|
||||||
"hour_end": "00:00"
|
"hour_end": "02:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Only Acoustic",
|
"title": "Programmation nocturne",
|
||||||
"periodicity": "0010000",
|
"periodicity": "1111111",
|
||||||
"hour_begin": "20:30",
|
"hour_begin": "02:00",
|
||||||
"hour_end": "00:00"
|
"hour_end": "06:00"
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Only Sweden",
|
|
||||||
"periodicity": "0001000",
|
|
||||||
"hour_begin": "20:30",
|
|
||||||
"hour_end": "00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Only Lives",
|
|
||||||
"periodicity": "0000100",
|
|
||||||
"hour_begin": "20:30",
|
|
||||||
"hour_end": "00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Only Games",
|
|
||||||
"periodicity": "0000010",
|
|
||||||
"hour_begin": "21:00",
|
|
||||||
"hour_end": "23:15"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Beyond [Azraël]",
|
|
||||||
"periodicity": "0100000",
|
|
||||||
"hour_begin": "21:00",
|
|
||||||
"hour_end": "23:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Piste Rouge [Louise et Trotsky]",
|
|
||||||
"periodicity": "0010000",
|
|
||||||
"hour_begin": "21:00",
|
|
||||||
"hour_end": "23:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Katamariff [Herondil & co.]",
|
|
||||||
"periodicity": "0000100",
|
|
||||||
"hour_begin": "21:00",
|
|
||||||
"hour_end": "23:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Le 4/4 Jazz [Melomaniaque]",
|
|
||||||
"periodicity": "0000001",
|
|
||||||
"hour_begin": "21:00",
|
|
||||||
"hour_end": "22:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Beyond, la playlist",
|
|
||||||
"periodicity": "0000001",
|
|
||||||
"hour_begin": "22:10",
|
|
||||||
"hour_end": "00:00"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"regular_programme" : "Programmation habituelle",
|
"regular_programme" : "Programmation habituelle",
|
||||||
"timezone": "Europe/Paris"
|
"timezone": "GMT+1"
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 62 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
enum class Actions
|
enum class Actions
|
||||||
{
|
{
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
|
|
||||||
class Async(val handler: (Any?) -> Any?, val post: (Any?) -> Unit = {},
|
class Async(val handler: (Any?) -> Any?, val post: (Any?) -> Unit = {},
|
||||||
private val actionOnError: ActionOnError = ActionOnError.RESET, private val parameters: Any? = null) :
|
private val actionOnError: ActionOnError = ActionOnError.RESET, private val parameters: Any? = null) :
|
||||||
|
|
@ -13,7 +13,7 @@ class Async(val handler: (Any?) -> Any?, val post: (Any?) -> Unit = {},
|
||||||
execute()
|
execute()
|
||||||
} catch (e: Exception)
|
} catch (e: Exception)
|
||||||
{
|
{
|
||||||
//[REMOVE LOG CALLS]Log.d(tag,e.toString())
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag,e.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,14 +46,14 @@ class Async(val handler: (Any?) -> Any?, val post: (Any?) -> Unit = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "fallback for no network. Store reset : $storeReset")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "fallback for no network. Store reset : $storeReset")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doInBackground(vararg params: Any?): Any? {
|
override fun doInBackground(vararg params: Any?): Any? {
|
||||||
try {
|
try {
|
||||||
return handler(parameters)
|
return handler(parameters)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag,e.toString())
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag,e.toString())
|
||||||
onException(e)
|
onException(e)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|
@ -63,7 +63,7 @@ class Async(val handler: (Any?) -> Any?, val post: (Any?) -> Unit = {},
|
||||||
try {
|
try {
|
||||||
post(result)
|
post(result)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag,e.toString())
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag,e.toString())
|
||||||
onException(e)
|
onException(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
|
@ -21,7 +21,7 @@ abstract class BaseActivity : AppCompatActivity() {
|
||||||
val height = ((rootLayout?.height ?: 0))
|
val height = ((rootLayout?.height ?: 0))
|
||||||
val width = ((rootLayout?.width ?: 0))
|
val width = ((rootLayout?.width ?: 0))
|
||||||
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "$viewWidth, $viewHeight, $width, $height, ${viewHeight.toDouble()/viewWidth.toDouble()}, ${height.toDouble()/width.toDouble()}")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "$viewWidth, $viewHeight, $width, $height, ${viewHeight.toDouble()/viewWidth.toDouble()}, ${height.toDouble()/width.toDouble()}")
|
||||||
|
|
||||||
val broadcastManager = LocalBroadcastManager.getInstance(this@BaseActivity)
|
val broadcastManager = LocalBroadcastManager.getInstance(this@BaseActivity)
|
||||||
if(height <= viewHeight * 2 / 3 /*height.toDouble()/width.toDouble() < 1.20 */){
|
if(height <= viewHeight * 2 / 3 /*height.toDouble()/width.toDouble() < 1.20 */){
|
||||||
|
|
@ -49,14 +49,14 @@ abstract class BaseActivity : AppCompatActivity() {
|
||||||
// do things when keyboard is shown
|
// do things when keyboard is shown
|
||||||
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
|
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
|
||||||
bottomNavigationView.visibility = View.GONE
|
bottomNavigationView.visibility = View.GONE
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "bottomNav visibility set to GONE (height $keyboardHeight)")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "bottomNav visibility set to GONE (height $keyboardHeight)")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onHideKeyboard() {
|
private fun onHideKeyboard() {
|
||||||
// do things when keyboard is hidden
|
// do things when keyboard is hidden
|
||||||
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
|
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
|
||||||
bottomNavigationView.visibility = View.VISIBLE
|
bottomNavigationView.visibility = View.VISIBLE
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "bottomNav visibility set to VISIBLE")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "bottomNav visibility set to VISIBLE")
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun attachKeyboardListeners() {
|
protected fun attachKeyboardListeners() {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
|
|
@ -50,7 +50,6 @@ abstract class BaseNotification(private val notificationChannelId: String,
|
||||||
notificationManager.notify(notificationId, notification)
|
notificationManager.notify(notificationId, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
open fun create(c: Context) {
|
open fun create(c: Context) {
|
||||||
notificationManager = c.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
notificationManager = c.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
|
|
@ -59,7 +58,7 @@ abstract class BaseNotification(private val notificationChannelId: String,
|
||||||
// thanks to the launchMode specified in the Manifest : android:launchMode="singleTop"
|
// thanks to the launchMode specified in the Manifest : android:launchMode="singleTop"
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
c, 0,
|
c, 0,
|
||||||
notificationIntent, PendingIntent.FLAG_IMMUTABLE
|
notificationIntent, 0
|
||||||
)
|
)
|
||||||
var channelID = ""
|
var channelID = ""
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
|
@ -6,14 +6,13 @@ import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import fr.riff_app.riff.alarm.RadioAlarm
|
import fr.forum_thalie.tsumugi.alarm.RadioAlarm
|
||||||
import fr.riff_app.riff.planning.Planning
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
|
||||||
|
|
||||||
class BootBroadcastReceiver : BroadcastReceiver(){
|
class BootBroadcastReceiver : BroadcastReceiver(){
|
||||||
|
|
||||||
override fun onReceive(context: Context, arg1: Intent) {
|
override fun onReceive(context: Context, arg1: Intent) {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "Broadcast Receiver received $arg1")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "Broadcast Receiver received $arg1")
|
||||||
// define preferenceStore for places of the program that needs to access Preferences without a context
|
// define preferenceStore for places of the program that needs to access Preferences without a context
|
||||||
preferenceStore = PreferenceManager.getDefaultSharedPreferences(context)
|
preferenceStore = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
|
|
@ -23,11 +22,7 @@ class BootBroadcastReceiver : BroadcastReceiver(){
|
||||||
|
|
||||||
if (arg1.getStringExtra("action") == "$tag.${Actions.PLAY_OR_FALLBACK.name}" )
|
if (arg1.getStringExtra("action") == "$tag.${Actions.PLAY_OR_FALLBACK.name}" )
|
||||||
{
|
{
|
||||||
|
|
||||||
RadioAlarm.instance.setNextAlarm(context) // schedule next alarm
|
RadioAlarm.instance.setNextAlarm(context) // schedule next alarm
|
||||||
Planning.instance.parseUrl(context = context)
|
|
||||||
if (!PlayerStore.instance.isInitialized)
|
|
||||||
PlayerStore.instance.initApi()
|
|
||||||
if (PlayerStore.instance.streamerName.value.isNullOrBlank())
|
if (PlayerStore.instance.streamerName.value.isNullOrBlank())
|
||||||
PlayerStore.instance.initPicture(context)
|
PlayerStore.instance.initPicture(context)
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
|
@ -11,13 +11,12 @@ import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
|
|
||||||
import java.util.Timer
|
import java.util.Timer
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import fr.forum_thalie.tsumugi.alarm.RadioAlarm
|
||||||
import fr.riff_app.riff.alarm.RadioAlarm
|
import fr.forum_thalie.tsumugi.planning.Planning
|
||||||
import fr.riff_app.riff.planning.Planning
|
|
||||||
|
|
||||||
|
|
||||||
/* Log to file import
|
/* Log to file import
|
||||||
|
|
@ -87,14 +86,6 @@ class MainActivity : BaseActivity() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
R.id.action_refresh -> {
|
|
||||||
PlayerStore.instance.queue.clear()
|
|
||||||
//PlayerStore.instance.lp.clear()
|
|
||||||
PlayerStore.instance.initApi()
|
|
||||||
val s = Snackbar.make(findViewById(R.id.nav_host_container), getString(R.string.refreshing) as CharSequence, Snackbar.LENGTH_LONG)
|
|
||||||
s.show()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
R.id.action_settings -> {
|
R.id.action_settings -> {
|
||||||
val i = Intent(this, ParametersActivity::class.java)
|
val i = Intent(this, ParametersActivity::class.java)
|
||||||
startActivity(i)
|
startActivity(i)
|
||||||
|
|
@ -117,7 +108,7 @@ class MainActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
||||||
super.onRestoreInstanceState(savedInstanceState ?: Bundle())
|
super.onRestoreInstanceState(savedInstanceState ?: Bundle())
|
||||||
// Now that BottomNavigationBar has restored its instance state
|
// Now that BottomNavigationBar has restored its instance state
|
||||||
// and its selectedItemId, we can proceed with setting up the
|
// and its selectedItemId, we can proceed with setting up the
|
||||||
|
|
@ -138,16 +129,10 @@ class MainActivity : BaseActivity() {
|
||||||
colorGreenListCompat = (ResourcesCompat.getColorStateList(resources, R.color.button_green_compat, null))
|
colorGreenListCompat = (ResourcesCompat.getColorStateList(resources, R.color.button_green_compat, null))
|
||||||
colorAccent = (ResourcesCompat.getColor(resources, R.color.colorAccent, null))
|
colorAccent = (ResourcesCompat.getColor(resources, R.color.colorAccent, null))
|
||||||
|
|
||||||
// fetch program
|
|
||||||
Planning.instance.parseUrl(/* getString(R.string.planning_url) */ context = this)
|
|
||||||
|
|
||||||
PlayerStore.instance.initUrl(this)
|
|
||||||
PlayerStore.instance.initApi()
|
|
||||||
|
|
||||||
// Post-UI Launch
|
// Post-UI Launch
|
||||||
if (PlayerStore.instance.isInitialized)
|
if (PlayerStore.instance.isInitialized)
|
||||||
{
|
{
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "skipped initialization")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "skipped initialization")
|
||||||
} else {
|
} else {
|
||||||
// if the service is not started, start it in STOP mode.
|
// if the service is not started, start it in STOP mode.
|
||||||
// It's not a dummy action : with STOP mode, the player does not buffer audio (and does not use data connection without the user's consent).
|
// It's not a dummy action : with STOP mode, the player does not buffer audio (and does not use data connection without the user's consent).
|
||||||
|
|
@ -175,6 +160,9 @@ class MainActivity : BaseActivity() {
|
||||||
isTimerStarted = true
|
isTimerStarted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetch program
|
||||||
|
Planning.instance.parseUrl(/* getString(R.string.planning_url) */ context = this)
|
||||||
|
|
||||||
// initialize the UI
|
// initialize the UI
|
||||||
setTheme(R.style.AppTheme)
|
setTheme(R.style.AppTheme)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
@ -205,7 +193,7 @@ class MainActivity : BaseActivity() {
|
||||||
val i = Intent(this, RadioService::class.java)
|
val i = Intent(this, RadioService::class.java)
|
||||||
i.putExtra("action", a.name)
|
i.putExtra("action", a.name)
|
||||||
i.putExtra("value", v)
|
i.putExtra("value", v)
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "Sending intent ${a.name}")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "Sending intent ${a.name}")
|
||||||
startService(i)
|
startService(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -250,7 +238,7 @@ class MainActivity : BaseActivity() {
|
||||||
// File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + "/MyPersonalAppFolder")
|
// File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + "/MyPersonalAppFolder")
|
||||||
val logDirectory = File("$appDirectory/log")
|
val logDirectory = File("$appDirectory/log")
|
||||||
val logFile = File(logDirectory, "logcat" + System.currentTimeMillis() + ".txt")
|
val logFile = File(logDirectory, "logcat" + System.currentTimeMillis() + ".txt")
|
||||||
//[REMOVE LOG CALLS]Log.d(
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(
|
||||||
tag,
|
tag,
|
||||||
"appDirectory : $appDirectory, logDirectory : $logDirectory, logFile : $logFile"
|
"appDirectory : $appDirectory, logDirectory : $logDirectory, logFile : $logFile"
|
||||||
)
|
)
|
||||||
|
|
@ -258,20 +246,20 @@ class MainActivity : BaseActivity() {
|
||||||
// create app folder
|
// create app folder
|
||||||
if (!appDirectory.exists()) {
|
if (!appDirectory.exists()) {
|
||||||
appDirectory.mkdir()
|
appDirectory.mkdir()
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "$appDirectory created")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "$appDirectory created")
|
||||||
}
|
}
|
||||||
|
|
||||||
// create log folder
|
// create log folder
|
||||||
if (!logDirectory.exists()) {
|
if (!logDirectory.exists()) {
|
||||||
logDirectory.mkdir()
|
logDirectory.mkdir()
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "$logDirectory created")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "$logDirectory created")
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the previous logcat and then write the new one to the file
|
// clear the previous logcat and then write the new one to the file
|
||||||
try {
|
try {
|
||||||
Runtime.getRuntime().exec("logcat -c")
|
Runtime.getRuntime().exec("logcat -c")
|
||||||
Runtime.getRuntime().exec("logcat -v time -f $logFile *:E $tag:V ")
|
Runtime.getRuntime().exec("logcat -v time -f $logFile *:E $tag:V ")
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "logcat started")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "logcat started")
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
|
||||||
import android.support.v4.media.session.MediaSessionCompat
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
import android.support.v4.media.session.PlaybackStateCompat
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
|
|
||||||
class NowPlayingNotification(
|
class NowPlayingNotification(
|
||||||
notificationChannelId: String,
|
notificationChannelId: String,
|
||||||
|
|
@ -36,19 +34,18 @@ class NowPlayingNotification(
|
||||||
// got it right
|
// got it right
|
||||||
val delIntent = Intent(c, RadioService::class.java)
|
val delIntent = Intent(c, RadioService::class.java)
|
||||||
delIntent.putExtra("action", Actions.KILL.name)
|
delIntent.putExtra("action", Actions.KILL.name)
|
||||||
val deleteIntent = PendingIntent.getService(c, 0, delIntent, PendingIntent.FLAG_NO_CREATE + PendingIntent.FLAG_IMMUTABLE)
|
val deleteIntent = PendingIntent.getService(c, 0, delIntent, PendingIntent.FLAG_NO_CREATE)
|
||||||
builder.setDeleteIntent(deleteIntent)
|
builder.setDeleteIntent(deleteIntent)
|
||||||
|
|
||||||
mediaStyle = androidx.media.app.NotificationCompat.DecoratedMediaCustomViewStyle().also {
|
mediaStyle = androidx.media.app.NotificationCompat.DecoratedMediaCustomViewStyle().also {
|
||||||
it.setMediaSession(m.sessionToken)
|
it.setMediaSession(m.sessionToken)
|
||||||
it.setShowActionsInCompactView(0, 1) // index 0 = show actions 0 and 1 (show action #0 (play/pause))
|
it.setShowActionsInCompactView(0) // index 0 = show actions 0 and 1 (show action #0 (play/pause))
|
||||||
it.setCancelButtonIntent(deleteIntent)
|
it.setCancelButtonIntent(deleteIntent)
|
||||||
}
|
}
|
||||||
builder.setStyle(mediaStyle)
|
builder.setStyle(mediaStyle)
|
||||||
update(c)
|
update(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
fun update(c: Context, isUpdatingNotificationButton: Boolean = false, isRinging: Boolean = false) {
|
fun update(c: Context, isUpdatingNotificationButton: Boolean = false, isRinging: Boolean = false) {
|
||||||
|
|
||||||
if (isUpdatingNotificationButton)
|
if (isUpdatingNotificationButton)
|
||||||
|
|
@ -75,18 +72,18 @@ class NowPlayingNotification(
|
||||||
|
|
||||||
playPauseAction = if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_PLAYING) {
|
playPauseAction = if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_PLAYING) {
|
||||||
intent.putExtra("action", Actions.PAUSE.name)
|
intent.putExtra("action", Actions.PAUSE.name)
|
||||||
val pendingButtonIntent = PendingIntent.getService(c, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE)
|
val pendingButtonIntent = PendingIntent.getService(c, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
NotificationCompat.Action.Builder(R.drawable.ic_pause, "Pause", pendingButtonIntent).build()
|
NotificationCompat.Action.Builder(R.drawable.ic_pause, "Pause", pendingButtonIntent).build()
|
||||||
} else {
|
} else {
|
||||||
intent.putExtra("action", Actions.PLAY.name)
|
intent.putExtra("action", Actions.PLAY.name)
|
||||||
val pendingButtonIntent = PendingIntent.getService(c, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE)
|
val pendingButtonIntent = PendingIntent.getService(c, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
NotificationCompat.Action.Builder(R.drawable.ic_play,"Play", pendingButtonIntent).build()
|
NotificationCompat.Action.Builder(R.drawable.ic_play,"Play", pendingButtonIntent).build()
|
||||||
}
|
}
|
||||||
builder.addAction(playPauseAction)
|
builder.addAction(playPauseAction)
|
||||||
val intent2 = Intent(c, RadioService::class.java)
|
val intent2 = Intent(c, RadioService::class.java)
|
||||||
intent2.putExtra("action", Actions.KILL.name)
|
intent2.putExtra("action", Actions.KILL.name)
|
||||||
val pendingButtonIntent = PendingIntent.getService(c, 2, intent2, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE)
|
val pendingButtonIntent = PendingIntent.getService(c, 2, intent2, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
val stopAction = NotificationCompat.Action.Builder(R.drawable.ic_close,"Stop", pendingButtonIntent).build()
|
val stopAction = NotificationCompat.Action.Builder(R.drawable.ic_stop,"Stop", pendingButtonIntent).build()
|
||||||
builder.addAction(stopAction)
|
builder.addAction(stopAction)
|
||||||
|
|
||||||
if (isRinging) {
|
if (isRinging) {
|
||||||
|
|
@ -95,7 +92,7 @@ class NowPlayingNotification(
|
||||||
|
|
||||||
val snoozeIntent = Intent(c, RadioService::class.java)
|
val snoozeIntent = Intent(c, RadioService::class.java)
|
||||||
snoozeIntent.putExtra("action", Actions.SNOOZE.name)
|
snoozeIntent.putExtra("action", Actions.SNOOZE.name)
|
||||||
val pendingSnoozeIntent = PendingIntent.getService(c, 5, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE)
|
val pendingSnoozeIntent = PendingIntent.getService(c, 5, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
val snoozeAction = NotificationCompat.Action.Builder(R.drawable.ic_alarm, "Snooze ($snoozeMinutes min.)", pendingSnoozeIntent ).build()
|
val snoozeAction = NotificationCompat.Action.Builder(R.drawable.ic_alarm, "Snooze ($snoozeMinutes min.)", pendingSnoozeIntent ).build()
|
||||||
if (snoozeMinutes > 0)
|
if (snoozeMinutes > 0)
|
||||||
builder.addAction(snoozeAction)
|
builder.addAction(snoozeAction)
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import fr.forum_thalie.tsumugi.preferences.*
|
||||||
import fr.riff_app.riff.preferences.*
|
|
||||||
|
|
||||||
|
|
||||||
class ParametersActivity : BaseActivity() {
|
class ParametersActivity : BaseActivity() {
|
||||||
|
|
@ -39,15 +38,4 @@ class ParametersActivity : BaseActivity() {
|
||||||
.replace(R.id.parameters_host_container, fragmentToLoad)
|
.replace(R.id.parameters_host_container, fragmentToLoad)
|
||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the Up button function as back instead of always bringing us to the main activity
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
return when (item.itemId) {
|
|
||||||
android.R.id.home -> {
|
|
||||||
onBackPressed()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
|
|
@ -32,10 +32,10 @@ import androidx.media.AudioManagerCompat
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.exoplayer2.*
|
import com.google.android.exoplayer2.*
|
||||||
import com.google.android.exoplayer2.metadata.icy.*
|
import com.google.android.exoplayer2.metadata.icy.*
|
||||||
import fr.riff_app.riff.alarm.RadioAlarm
|
import fr.forum_thalie.tsumugi.alarm.RadioAlarm
|
||||||
import fr.riff_app.riff.alarm.RadioSleeper
|
import fr.forum_thalie.tsumugi.alarm.RadioSleeper
|
||||||
import fr.riff_app.riff.planning.Planning
|
import fr.forum_thalie.tsumugi.planning.Planning
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.exp
|
import kotlin.math.exp
|
||||||
import kotlin.math.ln
|
import kotlin.math.ln
|
||||||
|
|
@ -68,14 +68,14 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
// This *should* work in any case...
|
// This *should* work in any case...
|
||||||
when (intent.getIntExtra("state", -1)) {
|
when (intent.getIntExtra("state", -1)) {
|
||||||
0 -> {
|
0 -> {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "Headset is unplugged")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "Headset is unplugged")
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "Headset is plugged")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "Headset is plugged")
|
||||||
headsetPluggedIn = true && PreferenceManager.getDefaultSharedPreferences(context).getBoolean("autoStartOnPlug", false)
|
headsetPluggedIn = true
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "I have no idea what the headset state is")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "I have no idea what the headset state is")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
@ -91,7 +91,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "Can't get state?")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "Can't get state?")
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
@ -124,32 +124,10 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
|
|
||||||
private val titleObserver = Observer<String> {
|
private val titleObserver = Observer<String> {
|
||||||
// We're checking if a new song arrives. If so, we put the currentSong in Lp and update the backup.
|
// We're checking if a new song arrives. If so, we put the currentSong in Lp and update the backup.
|
||||||
|
|
||||||
if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_PLAYING)
|
|
||||||
{
|
|
||||||
//[REMOVE LOG CALLS]Log.d((tag, radioTag + "SONG CHANGED AND PLAYING")
|
|
||||||
// we activate latency compensation only if it's been at least 2 songs...
|
|
||||||
when {
|
|
||||||
PlayerStore.instance.isStreamDown -> {
|
|
||||||
// if we reach here, it means that the observer has been called by a new song and that the stream was down previously.
|
|
||||||
// so the stream is now back to normal.
|
|
||||||
PlayerStore.instance.isStreamDown = false
|
|
||||||
PlayerStore.instance.initApi()
|
|
||||||
}
|
|
||||||
PlayerStore.instance.currentSong.title.value == noConnectionValue -> {
|
|
||||||
PlayerStore.instance.isStreamDown = true
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
PlayerStore.instance.fetchApi(/* numberOfSongs >= 2 */)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PlayerStore.instance.currentSong != PlayerStore.instance.currentSongBackup
|
if (PlayerStore.instance.currentSong != PlayerStore.instance.currentSongBackup
|
||||||
&& it != noConnectionValue)
|
&& it != noConnectionValue)
|
||||||
{
|
{
|
||||||
PlayerStore.instance.updateLp()
|
PlayerStore.instance.updateLp()
|
||||||
PlayerStore.instance.updateQueue()
|
|
||||||
}
|
}
|
||||||
nowPlayingNotification.update(this)
|
nowPlayingNotification.update(this)
|
||||||
Planning.instance.checkProgramme()
|
Planning.instance.checkProgramme()
|
||||||
|
|
@ -185,16 +163,9 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
|
|
||||||
preferenceStore = PreferenceManager.getDefaultSharedPreferences(this)
|
preferenceStore = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
// start ticker for when the player is stopped
|
|
||||||
val periodString = PreferenceManager.getDefaultSharedPreferences(this).getString("fetchPeriod", "10") ?: "10"
|
|
||||||
val period: Long = Integer.parseInt(periodString).toLong()
|
|
||||||
if (period > 0)
|
|
||||||
apiTicker.schedule(ApiFetchTick(), 0, period * 1000)
|
|
||||||
|
|
||||||
// Define managers
|
// Define managers
|
||||||
telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
||||||
// telephonyManager?.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
|
telephonyManager?.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
|
||||||
|
|
||||||
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
|
||||||
//define the audioFocusRequest
|
//define the audioFocusRequest
|
||||||
|
|
@ -234,7 +205,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
startForeground(radioServiceId, nowPlayingNotification.notification)
|
startForeground(radioServiceId, nowPlayingNotification.notification)
|
||||||
|
|
||||||
PlayerStore.instance.isServiceStarted.value = true
|
PlayerStore.instance.isServiceStarted.value = true
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "created")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "created")
|
||||||
}
|
}
|
||||||
|
|
||||||
private val handler = Handler()
|
private val handler = Handler()
|
||||||
|
|
@ -275,7 +246,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
Actions.CANCEL_FADE_OUT.name -> { handler.removeCallbacks(lowerVolumeRunnable) }
|
Actions.CANCEL_FADE_OUT.name -> { handler.removeCallbacks(lowerVolumeRunnable) }
|
||||||
Actions.SNOOZE.name -> { RadioAlarm.instance.snooze(this) }
|
Actions.SNOOZE.name -> { RadioAlarm.instance.snooze(this) }
|
||||||
}
|
}
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "intent received : " + intent.getStringExtra("action"))
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "intent received : " + intent.getStringExtra("action"))
|
||||||
super.onStartCommand(intent, flags, startId)
|
super.onStartCommand(intent, flags, startId)
|
||||||
// The service must be re-created if it is destroyed by the system. This allows the user to keep actions like Bluetooth and headphones plug available.
|
// The service must be re-created if it is destroyed by the system. This allows the user to keep actions like Bluetooth and headphones plug available.
|
||||||
return START_STICKY
|
return START_STICKY
|
||||||
|
|
@ -287,7 +258,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
super.onTaskRemoved(rootIntent)
|
super.onTaskRemoved(rootIntent)
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "task removed")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "task removed")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
|
@ -319,7 +290,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
apiTicker.cancel() // stops the timer.
|
apiTicker.cancel() // stops the timer.
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "destroyed")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "destroyed")
|
||||||
// if the service is destroyed, the application had become useless.
|
// if the service is destroyed, the application had become useless.
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
|
@ -390,10 +361,10 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
for (i in 0 until it.length()) {
|
for (i in 0 until it.length()) {
|
||||||
val entry = it.get(i)
|
val entry = it.get(i)
|
||||||
if (entry is IcyHeaders) {
|
if (entry is IcyHeaders) {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "onMetadata: IcyHeaders $entry")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "onMetadata: IcyHeaders $entry")
|
||||||
}
|
}
|
||||||
if (entry is IcyInfo) {
|
if (entry is IcyInfo) {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "onMetadata: Title ----> ${entry.title}")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "onMetadata: Title ----> ${entry.title}")
|
||||||
// Note : Kotlin supports UTF-8 by default.
|
// Note : Kotlin supports UTF-8 by default.
|
||||||
numberOfSongs++
|
numberOfSongs++
|
||||||
val data = entry.title!!
|
val data = entry.title!!
|
||||||
|
|
@ -428,7 +399,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
)
|
)
|
||||||
// This is the MediaSource representing the media to be played.
|
// This is the MediaSource representing the media to be played.
|
||||||
radioMediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
|
radioMediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||||
.createMediaSource(Uri.parse(getString(R.string.STREAM_URL_RIFF)))
|
.createMediaSource(Uri.parse(getString(R.string.STREAM_URL_TSUMUGI)))
|
||||||
|
|
||||||
fallbackMediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
|
fallbackMediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
|
||||||
.createMediaSource(Uri.parse("file:///android_asset/the_stream_is_down.mp3"))
|
.createMediaSource(Uri.parse("file:///android_asset/the_stream_is_down.mp3"))
|
||||||
|
|
@ -455,13 +426,12 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
// this function is playing the stream if available, or a default sound if there's a problem.
|
// this function is playing the stream if available, or a default sound if there's a problem.
|
||||||
private fun beginPlayingOrFallback()
|
private fun beginPlayingOrFallback()
|
||||||
{
|
{
|
||||||
PlayerStore.instance.volume.value = PreferenceManager.getDefaultSharedPreferences(this).getInt("alarmVolume", 100)
|
PlayerStore.instance.volume.value = 100 // we set the max volume for exoPlayer to be sure it rings correctly.
|
||||||
// we set the max volume for exoPlayer to be sure it rings correctly.
|
|
||||||
beginPlaying(isRinging = true, isFallback = false)
|
beginPlaying(isRinging = true, isFallback = false)
|
||||||
val wait: (Any?) -> Any = {
|
val wait: (Any?) -> Any = {
|
||||||
/*
|
/*
|
||||||
Here we lower the isAlarmStopped flag and we wait for 17s. (seems like 12 could be a bit too short since I increased the buffer!!)
|
Here we lower the isAlarmStopped flag and we wait for 17s. (seems like 12 could be a bit too short since I increased the buffer!!)
|
||||||
If the user stops the alarm (by calling an intent), the isAlarmStopped flag will be raised.
|
If the player stops the alarm (by calling an intent), the isAlarmStopped flag will be raised.
|
||||||
*/
|
*/
|
||||||
isAlarmStopped = false // reset the flag
|
isAlarmStopped = false // reset the flag
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -469,7 +439,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
{
|
{
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
i++
|
i++
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "$i, isAlarmStopped=$isAlarmStopped")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "$i, isAlarmStopped=$isAlarmStopped")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val post: (Any?) -> Unit = {
|
val post: (Any?) -> Unit = {
|
||||||
|
|
@ -500,7 +470,6 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
.setUsage(C.USAGE_ALARM)
|
.setUsage(C.USAGE_ALARM)
|
||||||
.build()
|
.build()
|
||||||
} else {
|
} else {
|
||||||
isAlarmStopped = true // if we're not ringing and it tries playing, it means the user opened the app somehow
|
|
||||||
audioAttributes.setUsage(AudioAttributesCompat.USAGE_MEDIA)
|
audioAttributes.setUsage(AudioAttributesCompat.USAGE_MEDIA)
|
||||||
audioFocusRequestBuilder.setAudioAttributes(audioAttributes.build())
|
audioFocusRequestBuilder.setAudioAttributes(audioAttributes.build())
|
||||||
audioFocusRequest = audioFocusRequestBuilder.build()
|
audioFocusRequest = audioFocusRequestBuilder.build()
|
||||||
|
|
@ -515,11 +484,9 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (mediaSession.controller.playbackState.state == PlaybackStateCompat.STATE_PLAYING && !isRinging && isAlarmStopped)
|
|
||||||
{
|
|
||||||
return //nothing to do here
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (mediaSession.controller.playbackState.state == PlaybackStateCompat.STATE_PLAYING && !isRinging)
|
||||||
|
return // nothing to do here
|
||||||
PlayerStore.instance.playbackState.value = PlaybackStateCompat.STATE_PLAYING
|
PlayerStore.instance.playbackState.value = PlaybackStateCompat.STATE_PLAYING
|
||||||
|
|
||||||
// Reinitialize media player. Otherwise the playback doesn't resume when beginPlaying. Dunno why.
|
// Reinitialize media player. Otherwise the playback doesn't resume when beginPlaying. Dunno why.
|
||||||
|
|
@ -545,8 +512,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
SystemClock.elapsedRealtime()
|
SystemClock.elapsedRealtime()
|
||||||
)
|
)
|
||||||
mediaSession.setPlaybackState(playbackStateBuilder.build())
|
mediaSession.setPlaybackState(playbackStateBuilder.build())
|
||||||
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "begin playing")
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "begin playing")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pausePlaying()
|
private fun pausePlaying()
|
||||||
|
|
@ -559,6 +525,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
{
|
{
|
||||||
if (mediaSession.controller.playbackState.state == PlaybackStateCompat.STATE_STOPPED)
|
if (mediaSession.controller.playbackState.state == PlaybackStateCompat.STATE_STOPPED)
|
||||||
return // nothing to do here
|
return // nothing to do here
|
||||||
|
|
||||||
if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_PLAYING)
|
if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_PLAYING)
|
||||||
isAlarmStopped = true
|
isAlarmStopped = true
|
||||||
|
|
||||||
|
|
@ -574,7 +541,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
1.0f,
|
1.0f,
|
||||||
SystemClock.elapsedRealtime()
|
SystemClock.elapsedRealtime()
|
||||||
)
|
)
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "stopped")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "stopped")
|
||||||
|
|
||||||
mediaSession.setPlaybackState(playbackStateBuilder.build())
|
mediaSession.setPlaybackState(playbackStateBuilder.build())
|
||||||
}
|
}
|
||||||
|
|
@ -662,7 +629,7 @@ class RadioService : MediaBrowserServiceCompat() {
|
||||||
Player.STATE_ENDED -> state = "Player.STATE_ENDED"
|
Player.STATE_ENDED -> state = "Player.STATE_ENDED"
|
||||||
Player.STATE_READY -> state = "Player.STATE_READY"
|
Player.STATE_READY -> state = "Player.STATE_READY"
|
||||||
}
|
}
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, radioTag + "Player changed state: ${state}. numberOfSongs reset.")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, radioTag + "Player changed state: ${state}. numberOfSongs reset.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class Tick : TimerTask() {
|
||||||
|
override fun run() {
|
||||||
|
PlayerStore.instance.currentTime.postValue(PlayerStore.instance.currentTime.value!! + 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package fr.riff_app.riff
|
package fr.forum_thalie.tsumugi
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
const val tag = "fr.riff_app.riff"
|
const val tag = "fr.forum_thalie.tsumugi"
|
||||||
const val noConnectionValue = "—"
|
const val noConnectionValue = "—"
|
||||||
const val streamDownValue = "Riff est HS !" // we don't want this value to be displaed in the "last played" screen.
|
const val streamDownValue = "Tsumugi est HS !" // we don't want this value to be displaed in the "last played" screen.
|
||||||
val weekdaysArray : Array<String> = arrayOf( "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche")
|
val weekdaysArray : Array<String> = arrayOf( "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche")
|
||||||
const val newsDateTimePattern = "EEE, d MMM yyyy HH:mm:ss Z"
|
const val newsDateTimePattern = "EEE, d MMM yyyy HH:mm:ss Z"
|
||||||
const val newsDisplayDatePattern = "dd MMM yyyy"
|
const val newsDisplayDatePattern = "dd MMM yyyy"
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
package fr.riff_app.riff.alarm
|
package fr.forum_thalie.tsumugi.alarm
|
||||||
|
|
||||||
import android.app.AlarmManager
|
import android.app.AlarmManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.core.app.AlarmManagerCompat
|
import androidx.core.app.AlarmManagerCompat
|
||||||
import fr.riff_app.riff.BootBroadcastReceiver
|
import fr.forum_thalie.tsumugi.BootBroadcastReceiver
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import fr.riff_app.riff.*
|
import fr.forum_thalie.tsumugi.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
@ -29,31 +27,13 @@ class RadioAlarm {
|
||||||
{
|
{
|
||||||
alarmIntent = Intent(c, BootBroadcastReceiver::class.java).let { intent ->
|
alarmIntent = Intent(c, BootBroadcastReceiver::class.java).let { intent ->
|
||||||
intent.putExtra("action", "$tag.${Actions.PLAY_OR_FALLBACK.name}")
|
intent.putExtra("action", "$tag.${Actions.PLAY_OR_FALLBACK.name}")
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
PendingIntent.getBroadcast(c, 0, intent, 0)
|
||||||
PendingIntent.getBroadcast(
|
|
||||||
c,
|
|
||||||
0,
|
|
||||||
intent,
|
|
||||||
PendingIntent.FLAG_IMMUTABLE
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
PendingIntent.getBroadcast(
|
|
||||||
c,
|
|
||||||
0,
|
|
||||||
intent,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
showIntent = Intent(c, ParametersActivity::class.java).let { intent ->
|
showIntent = Intent(c, ParametersActivity::class.java).let { intent ->
|
||||||
intent.putExtra("action", "alarm")
|
intent.putExtra("action", "alarm")
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
PendingIntent.getActivity(c, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
|
||||||
} else {
|
|
||||||
PendingIntent.getActivity(c, 0, intent, 0)
|
PendingIntent.getActivity(c, 0, intent, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun cancelAlarm(c: Context)
|
fun cancelAlarm(c: Context)
|
||||||
|
|
@ -63,7 +43,6 @@ class RadioAlarm {
|
||||||
alarmManager.cancel(alarmIntent)
|
alarmManager.cancel(alarmIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
fun setNextAlarm(c: Context, isForce: Boolean = false, forceTime: Int? = null, forceDays: Set<String>? = null)
|
fun setNextAlarm(c: Context, isForce: Boolean = false, forceTime: Int? = null, forceDays: Set<String>? = null)
|
||||||
{
|
{
|
||||||
defineIntents(c)
|
defineIntents(c)
|
||||||
|
|
@ -75,7 +54,7 @@ class RadioAlarm {
|
||||||
|
|
||||||
val showIntent = Intent(c, ParametersActivity::class.java).let { intent ->
|
val showIntent = Intent(c, ParametersActivity::class.java).let { intent ->
|
||||||
intent.putExtra("action", ActionOpenParam.ALARM.name)
|
intent.putExtra("action", ActionOpenParam.ALARM.name)
|
||||||
PendingIntent.getActivity(c, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getActivity(c, 0, intent, 0)
|
||||||
}
|
}
|
||||||
val time = findNextAlarmTime(c, forceTime, forceDays)
|
val time = findNextAlarmTime(c, forceTime, forceDays)
|
||||||
if (time > 0)
|
if (time > 0)
|
||||||
|
|
@ -118,7 +97,7 @@ class RadioAlarm {
|
||||||
calendar.isLenient = true
|
calendar.isLenient = true
|
||||||
calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH) + i, hourOfDay, minute)
|
calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH) + i, hourOfDay, minute)
|
||||||
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, calendar.toString())
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, calendar.toString())
|
||||||
|
|
||||||
|
|
||||||
return calendar.timeInMillis
|
return calendar.timeInMillis
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
package fr.riff_app.riff.alarm
|
package fr.forum_thalie.tsumugi.alarm
|
||||||
|
|
||||||
import android.app.AlarmManager
|
import android.app.AlarmManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.core.app.AlarmManagerCompat
|
import androidx.core.app.AlarmManagerCompat
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import fr.riff_app.riff.*
|
import fr.forum_thalie.tsumugi.*
|
||||||
|
|
||||||
class RadioSleeper {
|
class RadioSleeper {
|
||||||
|
|
||||||
|
|
@ -32,20 +30,18 @@ class RadioSleeper {
|
||||||
private lateinit var sleepIntent: PendingIntent
|
private lateinit var sleepIntent: PendingIntent
|
||||||
private lateinit var fadeOutIntent: PendingIntent
|
private lateinit var fadeOutIntent: PendingIntent
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
private fun defineIntents(c: Context)
|
private fun defineIntents(c: Context)
|
||||||
{
|
{
|
||||||
sleepIntent = Intent(c, RadioService::class.java).let { intent ->
|
sleepIntent = Intent(c, RadioService::class.java).let { intent ->
|
||||||
intent.putExtra("action", Actions.KILL.name)
|
intent.putExtra("action", Actions.KILL.name)
|
||||||
PendingIntent.getService(c, 99, intent, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getService(c, 99, intent, 0)
|
||||||
}
|
}
|
||||||
fadeOutIntent = Intent(c, RadioService::class.java).let { intent ->
|
fadeOutIntent = Intent(c, RadioService::class.java).let { intent ->
|
||||||
intent.putExtra("action", Actions.FADE_OUT.name)
|
intent.putExtra("action", Actions.FADE_OUT.name)
|
||||||
PendingIntent.getService(c, 98, intent, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getService(c, 98, intent, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
fun setSleep(c: Context, isForce: Boolean = false, forceDuration: Long? = null)
|
fun setSleep(c: Context, isForce: Boolean = false, forceDuration: Long? = null)
|
||||||
{
|
{
|
||||||
defineIntents(c)
|
defineIntents(c)
|
||||||
|
|
@ -65,7 +61,7 @@ class RadioSleeper {
|
||||||
|
|
||||||
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, currentMillis + (minutes * 60 * 1000) - (1 * 60 * 1000), fadeOutIntent)
|
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, currentMillis + (minutes * 60 * 1000) - (1 * 60 * 1000), fadeOutIntent)
|
||||||
sleepAtMillis.value = System.currentTimeMillis() + (minutes * 60 * 1000) - 1 // this -1 allows to round the division for display at the right integer
|
sleepAtMillis.value = System.currentTimeMillis() + (minutes * 60 * 1000) - 1 // this -1 allows to round the division for display at the right integer
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "set sleep to $minutes minutes")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "set sleep to $minutes minutes")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +79,7 @@ class RadioSleeper {
|
||||||
c.startService(cancelFadeOutIntent)
|
c.startService(cancelFadeOutIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "cancelled sleep")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "cancelled sleep")
|
||||||
sleepAtMillis.value = null
|
sleepAtMillis.value = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
package fr.riff_app.riff.planning
|
package fr.forum_thalie.tsumugi.planning
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import fr.riff_app.riff.Async
|
import fr.forum_thalie.tsumugi.Async
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.noConnectionValue
|
import fr.forum_thalie.tsumugi.noConnectionValue
|
||||||
import fr.riff_app.riff.weekdays
|
import fr.forum_thalie.tsumugi.weekdays
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
@ -64,7 +64,6 @@ class Planning {
|
||||||
if (result.has("planning"))
|
if (result.has("planning"))
|
||||||
{
|
{
|
||||||
val programList = result.getJSONArray("planning")
|
val programList = result.getJSONArray("planning")
|
||||||
programmes.clear()
|
|
||||||
for (i in 0 until programList.length())
|
for (i in 0 until programList.length())
|
||||||
{
|
{
|
||||||
val item = programList[i] as JSONObject
|
val item = programList[i] as JSONObject
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package fr.riff_app.riff.planning
|
package fr.forum_thalie.tsumugi.planning
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import fr.riff_app.riff.tag
|
import fr.forum_thalie.tsumugi.tag
|
||||||
import fr.riff_app.riff.weekdays
|
import fr.forum_thalie.tsumugi.weekdays
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ class Programme (val title: String, private val periodicity: Int, private val ho
|
||||||
val isSpanningOverNight =
|
val isSpanningOverNight =
|
||||||
(((0b1000000 shr ((currentDay - 1) % 7) and (periodicity)) != 0) && hourEnd < hourBegin)
|
(((0b1000000 shr ((currentDay - 1) % 7) and (periodicity)) != 0) && hourEnd < hourBegin)
|
||||||
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "$title is today: $isToday or spanning $isSpanningOverNight")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "$title is today: $isToday or spanning $isSpanningOverNight")
|
||||||
// shr = shift-right. It's a binary mask.
|
// shr = shift-right. It's a binary mask.
|
||||||
|
|
||||||
// if the program started yesterday, and spanned over night, it means that there could be a chance that it's still active.
|
// if the program started yesterday, and spanned over night, it means that there could be a chance that it's still active.
|
||||||
|
|
@ -87,6 +87,6 @@ class Programme (val title: String, private val periodicity: Int, private val ho
|
||||||
*/
|
*/
|
||||||
|
|
||||||
init {
|
init {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, this.toString())
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, this.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
package fr.forum_thalie.tsumugi.playerstore
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import fr.forum_thalie.tsumugi.*
|
||||||
|
|
||||||
|
class PlayerStore {
|
||||||
|
|
||||||
|
val isPlaying: MutableLiveData<Boolean> = MutableLiveData()
|
||||||
|
val isServiceStarted: MutableLiveData<Boolean> = MutableLiveData()
|
||||||
|
val volume: MutableLiveData<Int> = MutableLiveData()
|
||||||
|
val playbackState: MutableLiveData<Int> = MutableLiveData()
|
||||||
|
val currentTime: MutableLiveData<Long> = MutableLiveData()
|
||||||
|
val streamerPicture: MutableLiveData<Bitmap> = MutableLiveData()
|
||||||
|
val streamerName: MutableLiveData<String> = MutableLiveData()
|
||||||
|
val currentSong : Song = Song()
|
||||||
|
val currentSongBackup: Song = Song()
|
||||||
|
val lp : ArrayList<Song> = ArrayList()
|
||||||
|
val queue : ArrayList<Song> = ArrayList()
|
||||||
|
val isQueueUpdated: MutableLiveData<Boolean> = MutableLiveData()
|
||||||
|
val isLpUpdated: MutableLiveData<Boolean> = MutableLiveData()
|
||||||
|
val isMuted : MutableLiveData<Boolean> = MutableLiveData()
|
||||||
|
val listenersCount: MutableLiveData<Int> = MutableLiveData()
|
||||||
|
var latencyCompensator : Long = 0
|
||||||
|
var isInitialized: Boolean = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
playbackState.value = PlaybackStateCompat.STATE_STOPPED
|
||||||
|
isPlaying.value = false
|
||||||
|
isServiceStarted.value = false
|
||||||
|
streamerName.value = ""
|
||||||
|
volume.value = preferenceStore.getInt("volume", 100)
|
||||||
|
currentTime.value = System.currentTimeMillis()
|
||||||
|
isQueueUpdated.value = false
|
||||||
|
isLpUpdated.value = false
|
||||||
|
isMuted.value = false
|
||||||
|
currentSong.title.value = noConnectionValue
|
||||||
|
currentSongBackup.title.value = noConnectionValue
|
||||||
|
listenersCount.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ##################################################
|
||||||
|
// ############## QUEUE / LP FUNCTIONS ##############
|
||||||
|
// ##################################################
|
||||||
|
|
||||||
|
fun updateLp() {
|
||||||
|
// note : lp is empty at initialization. This check was needed when we used the R/a/dio API.
|
||||||
|
//if (lp.isNotEmpty()){
|
||||||
|
val n = Song()
|
||||||
|
n.copy(currentSongBackup)
|
||||||
|
if (n.title.value != noConnectionValue && n.title.value != streamDownValue)
|
||||||
|
lp.add(0, n)
|
||||||
|
currentSongBackup.copy(currentSong)
|
||||||
|
isLpUpdated.value = true
|
||||||
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, playerStoreTag + lp.toString())
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ##################################################
|
||||||
|
// ############## PICTURE FUNCTIONS #################
|
||||||
|
// ##################################################
|
||||||
|
|
||||||
|
fun initPicture(c: Context) {
|
||||||
|
streamerPicture.value = BitmapFactory.decodeResource(c.resources,
|
||||||
|
R.drawable.logo_roundsquare
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val playerStoreTag = "====PlayerStore===="
|
||||||
|
companion object {
|
||||||
|
val instance by lazy {
|
||||||
|
PlayerStore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
package fr.riff_app.riff.playerstore
|
package fr.forum_thalie.tsumugi.playerstore
|
||||||
|
|
||||||
import androidx.core.text.HtmlCompat
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import fr.riff_app.riff.noConnectionValue
|
import fr.forum_thalie.tsumugi.noConnectionValue
|
||||||
|
|
||||||
class Song(artistTitle: String = "", _id : Int = 0) {
|
class Song(artistTitle: String = "", _id : Int = 0) {
|
||||||
|
|
||||||
|
|
@ -25,9 +24,8 @@ class Song(artistTitle: String = "", _id : Int = 0) {
|
||||||
return "id=$id | ${artist.value} - ${title.value} | type=${type.value} | times ${startTime.value} - ${stopTime.value}\n"
|
return "id=$id | ${artist.value} - ${title.value} | type=${type.value} | times ${startTime.value} - ${stopTime.value}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setTitleArtist(dataHtml: String)
|
fun setTitleArtist(data: String)
|
||||||
{
|
{
|
||||||
val data = HtmlCompat.fromHtml(dataHtml, HtmlCompat.FROM_HTML_MODE_LEGACY).toString()
|
|
||||||
val hyphenPos = data.indexOf(" - ")
|
val hyphenPos = data.indexOf(" - ")
|
||||||
try {
|
try {
|
||||||
if (hyphenPos < 0)
|
if (hyphenPos < 0)
|
||||||
|
|
@ -48,12 +46,12 @@ class Song(artistTitle: String = "", _id : Int = 0) {
|
||||||
override fun equals(other: Any?) : Boolean
|
override fun equals(other: Any?) : Boolean
|
||||||
{
|
{
|
||||||
val song: Song = other as Song
|
val song: Song = other as Song
|
||||||
return this.title.value === song.title.value && this.artist.value === song.artist.value
|
return this.title.value == song.title.value && this.artist.value == song.artist.value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copy(song: Song) {
|
fun copy(song: Song) {
|
||||||
|
this.title.value = song.title.value
|
||||||
this.artist.value = song.artist.value
|
this.artist.value = song.artist.value
|
||||||
this.title. value = song.title.value
|
|
||||||
this.startTime.value = song.startTime.value
|
this.startTime.value = song.startTime.value
|
||||||
this.stopTime.value = song.stopTime.value
|
this.stopTime.value = song.stopTime.value
|
||||||
this.type.value = song.type.value
|
this.type.value = song.type.value
|
||||||
|
|
@ -1,38 +1,16 @@
|
||||||
package fr.riff_app.riff.preferences
|
package fr.forum_thalie.tsumugi.preferences
|
||||||
|
|
||||||
import android.app.TimePickerDialog
|
import android.app.TimePickerDialog
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.media.AudioManager
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.KeyEvent
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.preference.*
|
import androidx.preference.*
|
||||||
import fr.riff_app.riff.*
|
import fr.forum_thalie.tsumugi.*
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.alarm.RadioAlarm
|
import fr.forum_thalie.tsumugi.alarm.RadioAlarm
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.GlobalScope.coroutineContext
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
|
|
||||||
class AlarmFragment : PreferenceFragmentCompat() {
|
class AlarmFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
|
||||||
(activity as AppCompatActivity).supportActionBar?.title = context.getString(R.string.setupAlarmClock)
|
|
||||||
super.onAttach(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.alarm_preferences, rootKey)
|
setPreferencesFromResource(R.xml.alarm_preferences, rootKey)
|
||||||
|
|
||||||
|
|
@ -47,7 +25,7 @@ class AlarmFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
fun updateIsWakingUpSummary(preference: SwitchPreferenceCompat?, newValue: Boolean? = true, forceTime: Int? = null, forceDays: Set<String>? = null)
|
fun updateIsWakingUpSummary(preference: SwitchPreferenceCompat?, newValue: Boolean? = true, forceTime: Int? = null, forceDays: Set<String>? = null)
|
||||||
{
|
{
|
||||||
val dateLong = RadioAlarm.instance.findNextAlarmTime(requireContext(), forceTime, forceDays)
|
val dateLong = RadioAlarm.instance.findNextAlarmTime(context!!, forceTime, forceDays)
|
||||||
val calendar = Calendar.getInstance()
|
val calendar = Calendar.getInstance()
|
||||||
calendar.timeInMillis = dateLong
|
calendar.timeInMillis = dateLong
|
||||||
if (newValue == true && calendar.timeInMillis > 0)
|
if (newValue == true && calendar.timeInMillis > 0)
|
||||||
|
|
@ -65,14 +43,14 @@ class AlarmFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
val hourOfDayDefault = 7
|
val hourOfDayDefault = 7
|
||||||
val minuteDefault = 0
|
val minuteDefault = 0
|
||||||
if (!PreferenceManager.getDefaultSharedPreferences(requireContext()).contains("alarmTimeFromMidnight"))
|
if (!PreferenceManager.getDefaultSharedPreferences(context!!).contains("alarmTimeFromMidnight"))
|
||||||
{
|
{
|
||||||
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit {
|
PreferenceManager.getDefaultSharedPreferences(context!!).edit {
|
||||||
putInt("alarmTimeFromMidnight", (60*hourOfDayDefault+minuteDefault))
|
putInt("alarmTimeFromMidnight", (60*hourOfDayDefault+minuteDefault))
|
||||||
commit()
|
commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val time = PreferenceManager.getDefaultSharedPreferences(requireContext()).getInt("alarmTimeFromMidnight", (60*hourOfDayDefault+minuteDefault))
|
val time = PreferenceManager.getDefaultSharedPreferences(context!!).getInt("alarmTimeFromMidnight", (60*hourOfDayDefault+minuteDefault))
|
||||||
val hourOfDay = time / 60
|
val hourOfDay = time / 60
|
||||||
val minute = time % 60
|
val minute = time % 60
|
||||||
timeSet?.summary = "${if (hourOfDay < 10) "0" else ""}$hourOfDay:${if (minute < 10) "0" else ""}$minute"
|
timeSet?.summary = "${if (hourOfDay < 10) "0" else ""}$hourOfDay:${if (minute < 10) "0" else ""}$minute"
|
||||||
|
|
@ -80,16 +58,16 @@ class AlarmFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
timeSet?.setOnPreferenceClickListener {
|
timeSet?.setOnPreferenceClickListener {
|
||||||
val timePickerOnTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute ->
|
val timePickerOnTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute ->
|
||||||
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit {
|
PreferenceManager.getDefaultSharedPreferences(context!!).edit {
|
||||||
putInt("alarmTimeFromMidnight", (60*hourOfDay+minute))
|
putInt("alarmTimeFromMidnight", (60*hourOfDay+minute))
|
||||||
commit()
|
commit()
|
||||||
}
|
}
|
||||||
timeSet.summary = "${if (hourOfDay < 10) "0" else ""}$hourOfDay:${if (minute < 10) "0" else ""}$minute"
|
timeSet.summary = "${if (hourOfDay < 10) "0" else ""}$hourOfDay:${if (minute < 10) "0" else ""}$minute"
|
||||||
RadioAlarm.instance.cancelAlarm(requireContext())
|
RadioAlarm.instance.cancelAlarm(context!!)
|
||||||
RadioAlarm.instance.setNextAlarm(requireContext(), isForce = true, forceTime = hourOfDay*60+minute)
|
RadioAlarm.instance.setNextAlarm(context!!, isForce = true, forceTime = hourOfDay*60+minute)
|
||||||
updateIsWakingUpSummary(isWakingUp, isWakingUp?.isChecked, forceTime = hourOfDay*60+minute)
|
updateIsWakingUpSummary(isWakingUp, isWakingUp?.isChecked, forceTime = hourOfDay*60+minute)
|
||||||
}
|
}
|
||||||
val timeNew = PreferenceManager.getDefaultSharedPreferences(requireContext()).getInt("alarmTimeFromMidnight", 7*60)
|
val timeNew = PreferenceManager.getDefaultSharedPreferences(context!!).getInt("alarmTimeFromMidnight", 7*60)
|
||||||
val hourOfDayNew = timeNew / 60
|
val hourOfDayNew = timeNew / 60
|
||||||
val minuteNew = timeNew % 60
|
val minuteNew = timeNew % 60
|
||||||
val timePicker = TimePickerDialog(context, timePickerOnTimeSetListener, hourOfDayNew, minuteNew, true)
|
val timePicker = TimePickerDialog(context, timePickerOnTimeSetListener, hourOfDayNew, minuteNew, true)
|
||||||
|
|
@ -103,8 +81,8 @@ class AlarmFragment : PreferenceFragmentCompat() {
|
||||||
val fullWeek = weekdays.toSet()
|
val fullWeek = weekdays.toSet()
|
||||||
val workingWeek = weekdays.toSet().minusElement(weekdays.last()).minusElement(weekdays.elementAt(weekdays.size - 2))
|
val workingWeek = weekdays.toSet().minusElement(weekdays.last()).minusElement(weekdays.elementAt(weekdays.size - 2))
|
||||||
val listOfDays = when (newValue) {
|
val listOfDays = when (newValue) {
|
||||||
fullWeek -> requireContext().getString(R.string.every_day)
|
fullWeek -> context!!.getString(R.string.every_day)
|
||||||
workingWeek -> requireContext().getString(R.string.working_days)
|
workingWeek -> context!!.getString(R.string.working_days)
|
||||||
else -> {
|
else -> {
|
||||||
// build ORDERED LIST of days... I don't know why the original one is in shambles!!
|
// build ORDERED LIST of days... I don't know why the original one is in shambles!!
|
||||||
val fullWeekOrdered = weekdays
|
val fullWeekOrdered = weekdays
|
||||||
|
|
@ -119,12 +97,12 @@ class AlarmFragment : PreferenceFragmentCompat() {
|
||||||
preference?.summary = listOfDays
|
preference?.summary = listOfDays
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDays(alarmDays, PreferenceManager.getDefaultSharedPreferences(requireContext()).getStringSet("alarmDays", setOf()))
|
updateDays(alarmDays, PreferenceManager.getDefaultSharedPreferences(context).getStringSet("alarmDays", setOf()))
|
||||||
alarmDays?.setOnPreferenceChangeListener { preference, newValue ->
|
alarmDays?.setOnPreferenceChangeListener { preference, newValue ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
updateDays(preference as MultiSelectListPreference, newValue as Set<String>)
|
updateDays(preference as MultiSelectListPreference, newValue as Set<String>)
|
||||||
RadioAlarm.instance.cancelAlarm(requireContext())
|
RadioAlarm.instance.cancelAlarm(context!!)
|
||||||
RadioAlarm.instance.setNextAlarm(requireContext(), isForce = true, forceDays = newValue)
|
RadioAlarm.instance.setNextAlarm(context!!, isForce = true, forceDays = newValue)
|
||||||
updateIsWakingUpSummary(isWakingUp, isWakingUp?.isChecked, forceDays = newValue)
|
updateIsWakingUpSummary(isWakingUp, isWakingUp?.isChecked, forceDays = newValue)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
@ -133,9 +111,9 @@ class AlarmFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
isWakingUp?.setOnPreferenceChangeListener { _, newValue ->
|
isWakingUp?.setOnPreferenceChangeListener { _, newValue ->
|
||||||
if (newValue as Boolean)
|
if (newValue as Boolean)
|
||||||
RadioAlarm.instance.setNextAlarm(requireContext(), isForce = true)
|
RadioAlarm.instance.setNextAlarm(context!!, isForce = true)
|
||||||
else
|
else
|
||||||
RadioAlarm.instance.cancelAlarm(requireContext())
|
RadioAlarm.instance.cancelAlarm(context!!)
|
||||||
timeSet?.isEnabled = newValue
|
timeSet?.isEnabled = newValue
|
||||||
alarmDays?.isEnabled = newValue
|
alarmDays?.isEnabled = newValue
|
||||||
snoozeDuration?.isEnabled = newValue
|
snoozeDuration?.isEnabled = newValue
|
||||||
|
|
@ -143,10 +121,12 @@ class AlarmFragment : PreferenceFragmentCompat() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
alarmDays?.isEnabled = isWakingUp?.isChecked ?: false
|
alarmDays?.isEnabled = isWakingUp?.isChecked ?: false
|
||||||
timeSet?.isEnabled = isWakingUp?.isChecked ?: false
|
timeSet?.isEnabled = isWakingUp?.isChecked ?: false
|
||||||
snoozeDuration?.isEnabled = isWakingUp?.isChecked ?: false
|
snoozeDuration?.isEnabled = isWakingUp?.isChecked ?: false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,25 +1,21 @@
|
||||||
package fr.riff_app.riff.preferences
|
package fr.forum_thalie.tsumugi.preferences
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.preference.*
|
import androidx.preference.*
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.preferenceStore
|
import fr.forum_thalie.tsumugi.preferenceStore
|
||||||
|
|
||||||
class CustomizeFragment : PreferenceFragmentCompat() {
|
class CustomizeFragment : PreferenceFragmentCompat() {
|
||||||
override fun onAttach(context: Context) {
|
|
||||||
(activity as AppCompatActivity).supportActionBar?.title = context.getString(R.string.customizeAppBehavior)
|
|
||||||
super.onAttach(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.customize_preferences, rootKey)
|
setPreferencesFromResource(R.xml.customize_preferences, rootKey)
|
||||||
|
|
||||||
|
|
||||||
val snackbarPersistent = preferenceScreen.findPreference<SwitchPreferenceCompat>("snackbarPersistent")
|
val snackbarPersistent = preferenceScreen.findPreference<SwitchPreferenceCompat>("snackbarPersistent")
|
||||||
snackbarPersistent!!.summary = if (preferenceStore.getBoolean("snackbarPersistent", false))
|
snackbarPersistent!!.summary = if (preferenceStore.getBoolean("snackbarPersistent", true))
|
||||||
getString(R.string.snackbarPersistent)
|
getString(R.string.snackbarPersistent)
|
||||||
else
|
else
|
||||||
getString(R.string.snackbarNonPersistent)
|
getString(R.string.snackbarNonPersistent)
|
||||||
|
|
@ -44,25 +40,5 @@ class CustomizeFragment : PreferenceFragmentCompat() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val fetchPeriod = preferenceScreen.findPreference<ListPreference>("fetchPeriod")
|
|
||||||
fetchPeriod?.summaryProvider = ListPreference.SimpleSummaryProvider.getInstance()
|
|
||||||
fetchPeriod?.setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
val builder1 = AlertDialog.Builder(context!!)
|
|
||||||
if (Integer.parseInt(newValue as String) == 0)
|
|
||||||
builder1.setMessage(R.string.restart_the_app)
|
|
||||||
else
|
|
||||||
builder1.setMessage(R.string.restart_the_app)
|
|
||||||
builder1.setCancelable(true)
|
|
||||||
|
|
||||||
builder1.setPositiveButton("Close" ) { dialog, _ ->
|
|
||||||
dialog.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
val alert11 = builder1.create()
|
|
||||||
alert11.show()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
package fr.riff_app.riff.preferences
|
package fr.forum_thalie.tsumugi.preferences
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.preference.*
|
import androidx.preference.*
|
||||||
|
|
||||||
class MainPreferenceFragment : PreferenceFragmentCompat() {
|
class MainPreferenceFragment : PreferenceFragmentCompat() {
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
(activity as AppCompatActivity).supportActionBar?.title = context?.getString(R.string.settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
@SuppressLint("ApplySharedPref")
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
|
@ -1,20 +1,13 @@
|
||||||
package fr.riff_app.riff.preferences
|
package fr.forum_thalie.tsumugi.preferences
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.preference.*
|
import androidx.preference.*
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import fr.forum_thalie.tsumugi.alarm.RadioSleeper
|
||||||
import fr.riff_app.riff.alarm.RadioSleeper
|
|
||||||
|
|
||||||
|
|
||||||
class SleepFragment : PreferenceFragmentCompat() {
|
class SleepFragment : PreferenceFragmentCompat() {
|
||||||
override fun onAttach(context: Context) {
|
|
||||||
(activity as AppCompatActivity).supportActionBar?.title = context.getString(R.string.setSleepTimer)
|
|
||||||
super.onAttach(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.sleep_preference, rootKey)
|
setPreferencesFromResource(R.xml.sleep_preference, rootKey)
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui
|
package fr.forum_thalie.tsumugi.ui
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentPagerAdapter
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.news
|
package fr.forum_thalie.tsumugi.ui.news
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.news
|
package fr.forum_thalie.tsumugi.ui.news
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
|
@ -20,8 +20,8 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.core.widget.TextViewCompat
|
import androidx.core.widget.TextViewCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.newsDisplayDatePattern
|
import fr.forum_thalie.tsumugi.newsDisplayDatePattern
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
@ -32,7 +32,7 @@ import java.util.*
|
||||||
// but without Picasso (just fetching image by myself.)
|
// but without Picasso (just fetching image by myself.)
|
||||||
class ImageGetterAsyncTask(
|
class ImageGetterAsyncTask(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val source: String?,
|
private val source: String,
|
||||||
private val levelListDrawable: LevelListDrawable
|
private val levelListDrawable: LevelListDrawable
|
||||||
) :
|
) :
|
||||||
AsyncTask<TextView?, Void?, Bitmap?>() {
|
AsyncTask<TextView?, Void?, Bitmap?>() {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.news
|
package fr.forum_thalie.tsumugi.ui.news
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
|
@ -12,7 +12,7 @@ import androidx.lifecycle.ViewModelProviders
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
|
|
||||||
class NewsFragment : Fragment() {
|
class NewsFragment : Fragment() {
|
||||||
|
|
||||||
|
|
@ -43,9 +43,9 @@ class NewsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
newsViewModel.isWebViewLoaded = true
|
newsViewModel.isWebViewLoaded = true
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "webview created")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "webview created")
|
||||||
} else {
|
} else {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "webview already created!?")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "webview already created!?")
|
||||||
}
|
}
|
||||||
|
|
||||||
newsViewModel.root.addOnLayoutChangeListener(orientationLayoutListener)
|
newsViewModel.root.addOnLayoutChangeListener(orientationLayoutListener)
|
||||||
|
|
@ -101,7 +101,7 @@ class NewsFragment : Fragment() {
|
||||||
ViewModelProviders.of(this).get(NewsViewModel::class.java)
|
ViewModelProviders.of(this).get(NewsViewModel::class.java)
|
||||||
|
|
||||||
newsViewModel.fetch(c = context!!, isPreloading = true)
|
newsViewModel.fetch(c = context!!, isPreloading = true)
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "news fetched onCreate")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "news fetched onCreate")
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.news
|
package fr.forum_thalie.tsumugi.ui.news
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
|
@ -8,9 +8,9 @@ import android.webkit.WebView
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.prof.rssparser.Parser
|
import com.prof.rssparser.Parser
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.newsDateTimePattern
|
import fr.forum_thalie.tsumugi.newsDateTimePattern
|
||||||
import fr.riff_app.riff.tag
|
import fr.forum_thalie.tsumugi.tag
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
@ -43,14 +43,14 @@ class NewsViewModel : ViewModel() {
|
||||||
|
|
||||||
val maxNumberOfArticles = 5
|
val maxNumberOfArticles = 5
|
||||||
coroutineScope.launch(Dispatchers.Main) {
|
coroutineScope.launch(Dispatchers.Main) {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "launching coroutine")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "launching coroutine")
|
||||||
val parser = Parser()
|
val parser = Parser()
|
||||||
try {
|
try {
|
||||||
val articleList = parser.getArticles(urlToScrape)
|
val articleList = parser.getArticles(urlToScrape)
|
||||||
newsArray.clear()
|
newsArray.clear()
|
||||||
for (i in 0 until min(articleList.size, maxNumberOfArticles)) {
|
for (i in 0 until min(articleList.size, maxNumberOfArticles)) {
|
||||||
val item = articleList[i]
|
val item = articleList[i]
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "i = $i / ${articleList.size}")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "i = $i / ${articleList.size}")
|
||||||
val news = News()
|
val news = News()
|
||||||
news.title = item.title ?: ""
|
news.title = item.title ?: ""
|
||||||
news.link = item.link ?: urlToScrape
|
news.link = item.link ?: urlToScrape
|
||||||
|
|
@ -60,7 +60,7 @@ class NewsViewModel : ViewModel() {
|
||||||
|
|
||||||
val formatter6 = SimpleDateFormat(newsDateTimePattern, Locale.ENGLISH)
|
val formatter6 = SimpleDateFormat(newsDateTimePattern, Locale.ENGLISH)
|
||||||
val dateString = item.pubDate.toString()
|
val dateString = item.pubDate.toString()
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "$news --- $dateString")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "$news --- $dateString")
|
||||||
|
|
||||||
news.date = formatter6.parse(dateString) ?: Date(0)
|
news.date = formatter6.parse(dateString) ?: Date(0)
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.news
|
package fr.forum_thalie.tsumugi.ui.news
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.nowplaying
|
package fr.forum_thalie.tsumugi.ui.nowplaying
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
|
|
@ -6,6 +6,8 @@ import android.content.Context
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v4.media.session.PlaybackStateCompat
|
import android.support.v4.media.session.PlaybackStateCompat
|
||||||
|
import android.util.Log
|
||||||
|
import android.util.TypedValue
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
@ -13,14 +15,16 @@ import android.view.ViewGroup
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.constraintlayout.widget.ConstraintSet
|
import androidx.constraintlayout.widget.ConstraintSet
|
||||||
|
import androidx.core.widget.TextViewCompat
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import fr.riff_app.riff.*
|
import fr.forum_thalie.tsumugi.*
|
||||||
import fr.riff_app.riff.alarm.RadioSleeper
|
import fr.forum_thalie.tsumugi.alarm.RadioSleeper
|
||||||
import fr.riff_app.riff.planning.Planning
|
import fr.forum_thalie.tsumugi.planning.Planning
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
import fr.riff_app.riff.playerstore.Song
|
import fr.forum_thalie.tsumugi.playerstore.Song
|
||||||
|
import kotlinx.android.synthetic.main.fragment_nowplaying.*
|
||||||
|
|
||||||
|
|
||||||
class NowPlayingFragment : Fragment() {
|
class NowPlayingFragment : Fragment() {
|
||||||
|
|
@ -45,12 +49,12 @@ class NowPlayingFragment : Fragment() {
|
||||||
val volumeText: TextView = root.findViewById(R.id.volume_text)
|
val volumeText: TextView = root.findViewById(R.id.volume_text)
|
||||||
val progressBar: ProgressBar = root.findViewById(R.id.progressBar)
|
val progressBar: ProgressBar = root.findViewById(R.id.progressBar)
|
||||||
val volumeIconImage : ImageView = root.findViewById(R.id.volume_icon)
|
val volumeIconImage : ImageView = root.findViewById(R.id.volume_icon)
|
||||||
val currentProgrammeText: TextView = root.findViewById(R.id.current_programme)
|
|
||||||
val streamerPictureImageView: ImageView = root.findViewById(R.id.streamerPicture)
|
val streamerPictureImageView: ImageView = root.findViewById(R.id.streamerPicture)
|
||||||
|
|
||||||
// Note: these values are not used in the generic app, but if you want to, you can use them.
|
// Note: these values are not used in the generic app, but if you want to, you can use them.
|
||||||
val songTitleNextText: TextView = root.findViewById(R.id.text_song_title_next)
|
val songTitleNextText: TextView = root.findViewById(R.id.text_song_title_next)
|
||||||
val songArtistNextText: TextView = root.findViewById(R.id.text_song_artist_next)
|
//val songArtistNextText: TextView = root.findViewById(R.id.text_song_artist_next)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
val streamerNameText : TextView = root.findViewById(R.id.streamerName)
|
val streamerNameText : TextView = root.findViewById(R.id.streamerName)
|
||||||
|
|
@ -65,14 +69,15 @@ class NowPlayingFragment : Fragment() {
|
||||||
listenersText,8, 16, 2, TypedValue.COMPLEX_UNIT_SP)
|
listenersText,8, 16, 2, TypedValue.COMPLEX_UNIT_SP)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
// trick : I can't observe the queue because it's an ArrayDeque that doesn't trigger any change...
|
// trick : I can't observe the queue because it's an ArrayDeque that doesn't trigger any change...
|
||||||
// so I observe a dedicated Mutable that gets set when the queue is updated.
|
// so I observe a dedicated Mutable that gets set when the queue is updated.
|
||||||
PlayerStore.instance.isQueueUpdated.observe(viewLifecycleOwner, Observer {
|
PlayerStore.instance.isQueueUpdated.observe(viewLifecycleOwner, Observer {
|
||||||
val t = if (PlayerStore.instance.queue.size > 0) PlayerStore.instance.queue[0] else Song(noConnectionValue) // (it.peekFirst != null ? it.peekFirst : Song() )
|
val t = if (PlayerStore.instance.queue.size > 0) PlayerStore.instance.queue[0] else Song("No queue - ") // (it.peekFirst != null ? it.peekFirst : Song() )
|
||||||
songTitleNextText.text = t.title.value
|
songTitleNextText.text = t.title.value
|
||||||
songArtistNextText.text = t.artist.value
|
songArtistNextText.text = t.artist.value
|
||||||
})
|
})
|
||||||
/*
|
|
||||||
PlayerStore.instance.streamerName.observe(viewLifecycleOwner, Observer {
|
PlayerStore.instance.streamerName.observe(viewLifecycleOwner, Observer {
|
||||||
streamerNameText.text = it
|
streamerNameText.text = it
|
||||||
})
|
})
|
||||||
|
|
@ -87,12 +92,10 @@ class NowPlayingFragment : Fragment() {
|
||||||
songTitleText.text = it
|
songTitleText.text = it
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
Planning.instance.currentProgramme.observe(viewLifecycleOwner, Observer {
|
Planning.instance.currentProgramme.observe(viewLifecycleOwner, Observer {
|
||||||
currentProgrammeText.text = "${requireContext().getString(R.string.current_programme)} $it"
|
songTitleNextText.text = it
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
PlayerStore.instance.currentSong.artist.observe(viewLifecycleOwner, Observer {
|
PlayerStore.instance.currentSong.artist.observe(viewLifecycleOwner, Observer {
|
||||||
songArtistText.text = it
|
songArtistText.text = it
|
||||||
})
|
})
|
||||||
|
|
@ -166,10 +169,10 @@ class NowPlayingFragment : Fragment() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
seekBarVolume.progress = PlayerStore.instance.volume.value!!
|
|
||||||
seekBarVolume.setOnSeekBarChangeListener(nowPlayingViewModel.seekBarChangeListener)
|
|
||||||
|
|
||||||
progressBar.max = 100
|
seekBarVolume.setOnSeekBarChangeListener(nowPlayingViewModel.seekBarChangeListener)
|
||||||
|
seekBarVolume.progress = PlayerStore.instance.volume.value!!
|
||||||
|
progressBar.max = 1000
|
||||||
progressBar.progress = 0
|
progressBar.progress = 0
|
||||||
|
|
||||||
syncPlayPauseButtonImage(root)
|
syncPlayPauseButtonImage(root)
|
||||||
|
|
@ -184,10 +187,10 @@ class NowPlayingFragment : Fragment() {
|
||||||
|
|
||||||
val setClipboardListener: View.OnLongClickListener = View.OnLongClickListener {
|
val setClipboardListener: View.OnLongClickListener = View.OnLongClickListener {
|
||||||
val text = PlayerStore.instance.currentSong.artist.value + " - " + PlayerStore.instance.currentSong.title.value
|
val text = PlayerStore.instance.currentSong.artist.value + " - " + PlayerStore.instance.currentSong.title.value
|
||||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = context!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
val clip = android.content.ClipData.newPlainText("Copied Text", text)
|
val clip = android.content.ClipData.newPlainText("Copied Text", text)
|
||||||
clipboard.setPrimaryClip(clip)
|
clipboard.setPrimaryClip(clip)
|
||||||
val snackBarLength = if (preferenceStore.getBoolean("snackbarPersistent", false))
|
val snackBarLength = if (preferenceStore.getBoolean("snackbarPersistent", true))
|
||||||
Snackbar.LENGTH_INDEFINITE
|
Snackbar.LENGTH_INDEFINITE
|
||||||
else Snackbar.LENGTH_LONG
|
else Snackbar.LENGTH_LONG
|
||||||
val snackBar = Snackbar.make(it, "", snackBarLength)
|
val snackBar = Snackbar.make(it, "", snackBarLength)
|
||||||
|
|
@ -270,7 +273,7 @@ class NowPlayingFragment : Fragment() {
|
||||||
(viewHeight*100)/viewWidth
|
(viewHeight*100)/viewWidth
|
||||||
else
|
else
|
||||||
100
|
100
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "orientation set")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "orientation set")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
package fr.riff_app.riff.ui.nowplaying
|
package fr.forum_thalie.tsumugi.ui.nowplaying
|
||||||
|
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
import fr.riff_app.riff.preferenceStore
|
|
||||||
|
|
||||||
class NowPlayingViewModel: ViewModel() {
|
class NowPlayingViewModel: ViewModel() {
|
||||||
|
|
||||||
|
|
@ -23,10 +21,6 @@ class NowPlayingViewModel: ViewModel() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||||
// updated continuously as the user slides the thumb
|
// updated continuously as the user slides the thumb
|
||||||
PlayerStore.instance.volume.value = progress
|
PlayerStore.instance.volume.value = progress
|
||||||
preferenceStore.edit {
|
|
||||||
putInt("volume", progress)
|
|
||||||
commit()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
package fr.riff_app.riff.ui.programme
|
package fr.forum_thalie.tsumugi.ui.programme
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.core.widget.TextViewCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.*
|
||||||
import fr.riff_app.riff.colorAccent
|
import fr.forum_thalie.tsumugi.planning.Planning
|
||||||
import fr.riff_app.riff.colorWhited
|
import fr.forum_thalie.tsumugi.planning.Programme
|
||||||
import fr.riff_app.riff.planning.Planning
|
|
||||||
import fr.riff_app.riff.planning.Programme
|
|
||||||
import fr.riff_app.riff.weekdaysSundayFirst
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class ProgrammeAdapter(private val dataSet: ArrayList<Programme>, private val day: String
|
class ProgrammeAdapter(private val dataSet: ArrayList<Programme>, private val day: String
|
||||||
/*,
|
/*,
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.programme
|
package fr.forum_thalie.tsumugi.ui.programme
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
|
@ -9,10 +9,10 @@ import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.planning.Planning
|
import fr.forum_thalie.tsumugi.planning.Planning
|
||||||
import fr.riff_app.riff.planning.Programme
|
import fr.forum_thalie.tsumugi.planning.Programme
|
||||||
import fr.riff_app.riff.weekdays
|
import fr.forum_thalie.tsumugi.weekdays
|
||||||
|
|
||||||
|
|
||||||
class ProgrammeDayFragment : Fragment() {
|
class ProgrammeDayFragment : Fragment() {
|
||||||
|
|
@ -32,13 +32,13 @@ class ProgrammeDayFragment : Fragment() {
|
||||||
viewModel.day = arguments?.getString("day") ?: ""
|
viewModel.day = arguments?.getString("day") ?: ""
|
||||||
|
|
||||||
val root = inflater.inflate(R.layout.fragment_programme_day, container, false)
|
val root = inflater.inflate(R.layout.fragment_programme_day, container, false)
|
||||||
|
|
||||||
Planning.instance.programmes.forEach {
|
Planning.instance.programmes.forEach {
|
||||||
if (it.isThisDay(day = weekdays.indexOf(viewModel.day)))
|
if (it.isThisDay(day = weekdays.indexOf(viewModel.day)))
|
||||||
programmeOfTheDay.add(it)
|
programmeOfTheDay.add(it)
|
||||||
}
|
}
|
||||||
viewManager = LinearLayoutManager(context)
|
viewManager = LinearLayoutManager(context)
|
||||||
viewAdapter = ProgrammeAdapter(programmeOfTheDay, viewModel.day)
|
viewAdapter =
|
||||||
|
ProgrammeAdapter(programmeOfTheDay, viewModel.day)
|
||||||
recyclerView = root.findViewById<RecyclerView>(R.id.programme_recycler).apply {
|
recyclerView = root.findViewById<RecyclerView>(R.id.programme_recycler).apply {
|
||||||
// use this setting to improve performance if you know that changes
|
// use this setting to improve performance if you know that changes
|
||||||
// in content do not change the layout size of the RecyclerView
|
// in content do not change the layout size of the RecyclerView
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.programme
|
package fr.forum_thalie.tsumugi.ui.programme
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.programme
|
package fr.forum_thalie.tsumugi.ui.programme
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
@ -9,10 +9,10 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentPagerAdapter
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.planning.Planning
|
import fr.forum_thalie.tsumugi.planning.Planning
|
||||||
import fr.riff_app.riff.ui.APagerAdapter
|
import fr.forum_thalie.tsumugi.ui.APagerAdapter
|
||||||
import fr.riff_app.riff.weekdays
|
import fr.forum_thalie.tsumugi.weekdays
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ProgrammeFragment : Fragment() {
|
class ProgrammeFragment : Fragment() {
|
||||||
|
|
@ -37,11 +37,11 @@ class ProgrammeFragment : Fragment() {
|
||||||
|
|
||||||
viewPager.adapter = adapter
|
viewPager.adapter = adapter
|
||||||
val todaySundayFirst = Calendar.getInstance(Planning.instance.timeZone).get(Calendar.DAY_OF_WEEK) - 1
|
val todaySundayFirst = Calendar.getInstance(Planning.instance.timeZone).get(Calendar.DAY_OF_WEEK) - 1
|
||||||
viewPager.currentItem = (todaySundayFirst - 1 + 7)%7 // don't do modulos on negative, seems like it's weird
|
viewPager.currentItem = (todaySundayFirst - 1)%7
|
||||||
|
|
||||||
val tabLayout : TabLayout = root.findViewById(R.id.dayTabLayout)
|
val tabLayout : TabLayout = root.findViewById(R.id.dayTabLayout)
|
||||||
tabLayout.setupWithViewPager(viewPager)
|
tabLayout.setupWithViewPager(viewPager)
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "SongFragment view created")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "SongFragment view created")
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.songs
|
package fr.forum_thalie.tsumugi.ui.songs
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
@ -9,10 +9,10 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentPagerAdapter
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.ui.APagerAdapter
|
import fr.forum_thalie.tsumugi.ui.APagerAdapter
|
||||||
import fr.riff_app.riff.ui.programme.ProgrammeDayFragment
|
import fr.forum_thalie.tsumugi.ui.programme.ProgrammeDayFragment
|
||||||
import fr.riff_app.riff.ui.songs.queuelp.LastPlayedFragment
|
import fr.forum_thalie.tsumugi.ui.songs.queuelp.LastPlayedFragment
|
||||||
|
|
||||||
class SongsFragment : Fragment() {
|
class SongsFragment : Fragment() {
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ class SongsFragment : Fragment() {
|
||||||
|
|
||||||
val tabLayout : TabLayout = root.findViewById(R.id.tabLayout)
|
val tabLayout : TabLayout = root.findViewById(R.id.tabLayout)
|
||||||
tabLayout.setupWithViewPager(viewPager)
|
tabLayout.setupWithViewPager(viewPager)
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "SongFragment view created")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, "SongFragment view created")
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.songs.queuelp
|
package fr.forum_thalie.tsumugi.ui.songs.queuelp
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
@ -9,8 +9,8 @@ import android.view.ViewGroup
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
import fr.forum_thalie.tsumugi.playerstore.PlayerStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple [Fragment] subclass.
|
* A simple [Fragment] subclass.
|
||||||
|
|
@ -31,7 +31,7 @@ class LastPlayedFragment : Fragment() {
|
||||||
|
|
||||||
|
|
||||||
private val queueObserver = Observer<Boolean> {
|
private val queueObserver = Observer<Boolean> {
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, lastPlayedFragmentTag + "queue changed")
|
//[REMOVE LOG CALLS]//[REMOVE LOG CALLS]Log.d(tag, lastPlayedFragmentTag + "queue changed")
|
||||||
viewAdapter.notifyDataSetChanged()
|
viewAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fr.riff_app.riff.ui.songs.queuelp
|
package fr.forum_thalie.tsumugi.ui.songs.queuelp
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
|
@ -8,11 +8,11 @@ import android.view.ViewGroup
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import fr.riff_app.riff.R
|
import fr.forum_thalie.tsumugi.R
|
||||||
import fr.riff_app.riff.colorBlue
|
import fr.forum_thalie.tsumugi.colorBlue
|
||||||
import fr.riff_app.riff.colorWhited
|
import fr.forum_thalie.tsumugi.colorWhited
|
||||||
import fr.riff_app.riff.playerstore.Song
|
import fr.forum_thalie.tsumugi.playerstore.Song
|
||||||
import fr.riff_app.riff.tag
|
import fr.forum_thalie.tsumugi.tag
|
||||||
import kotlinx.android.synthetic.main.song_view.view.*
|
import kotlinx.android.synthetic.main.song_view.view.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package fr.riff_app.riff
|
|
||||||
|
|
||||||
import android.support.v4.media.session.PlaybackStateCompat
|
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class ApiFetchTick : TimerTask() {
|
|
||||||
override fun run() {
|
|
||||||
if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_STOPPED)
|
|
||||||
{
|
|
||||||
PlayerStore.instance.fetchApi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Tick : TimerTask() {
|
|
||||||
override fun run() {
|
|
||||||
PlayerStore.instance.currentTime.postValue(PlayerStore.instance.currentTime.value!! + 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,277 +0,0 @@
|
||||||
package fr.riff_app.riff.playerstore
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.support.v4.media.session.PlaybackStateCompat
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import fr.riff_app.riff.*
|
|
||||||
import fr.riff_app.riff.planning.Planning
|
|
||||||
import org.json.JSONObject
|
|
||||||
import java.net.URL
|
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.time.format.TextStyle
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
class PlayerStore {
|
|
||||||
|
|
||||||
private lateinit var urlToScrape: String
|
|
||||||
val isPlaying: MutableLiveData<Boolean> = MutableLiveData()
|
|
||||||
val isServiceStarted: MutableLiveData<Boolean> = MutableLiveData()
|
|
||||||
val volume: MutableLiveData<Int> = MutableLiveData()
|
|
||||||
val playbackState: MutableLiveData<Int> = MutableLiveData()
|
|
||||||
val currentTime: MutableLiveData<Long> = MutableLiveData()
|
|
||||||
val streamerPicture: MutableLiveData<Bitmap> = MutableLiveData()
|
|
||||||
val streamerName: MutableLiveData<String> = MutableLiveData()
|
|
||||||
val currentSong : Song = Song()
|
|
||||||
val currentSongBackup: Song = Song()
|
|
||||||
val lp : ArrayList<Song> = ArrayList()
|
|
||||||
val queue : ArrayList<Song> = ArrayList()
|
|
||||||
val isQueueUpdated: MutableLiveData<Boolean> = MutableLiveData()
|
|
||||||
val isLpUpdated: MutableLiveData<Boolean> = MutableLiveData()
|
|
||||||
val isMuted : MutableLiveData<Boolean> = MutableLiveData()
|
|
||||||
val listenersCount: MutableLiveData<Int> = MutableLiveData()
|
|
||||||
var latencyCompensator : Long = 0
|
|
||||||
var isInitialized: Boolean = false
|
|
||||||
var isStreamDown: Boolean = false
|
|
||||||
|
|
||||||
init {
|
|
||||||
playbackState.value = PlaybackStateCompat.STATE_STOPPED
|
|
||||||
isPlaying.value = false
|
|
||||||
isServiceStarted.value = false
|
|
||||||
streamerName.value = ""
|
|
||||||
volume.value = preferenceStore.getInt("volume", 100)
|
|
||||||
currentTime.value = System.currentTimeMillis()
|
|
||||||
isQueueUpdated.value = false
|
|
||||||
isLpUpdated.value = false
|
|
||||||
isMuted.value = false
|
|
||||||
currentSong.setTitleArtist(noConnectionValue)
|
|
||||||
currentSongBackup.setTitleArtist(noConnectionValue)
|
|
||||||
listenersCount.value = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fun initUrl(c: Context)
|
|
||||||
{
|
|
||||||
urlToScrape = c.getString(R.string.API_URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTimestamp(s: String) : Long
|
|
||||||
{
|
|
||||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd hh:mm:ss z", Locale.getDefault())
|
|
||||||
try {
|
|
||||||
val t: Date? = dateFormat.parse("$s ${Planning.instance.timeZone.getDisplayName(Planning.instance.timeZone.useDaylightTime(), TimeZone.SHORT)}")
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "date: $s -> $t")
|
|
||||||
return t!!.time
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ##################################################
|
|
||||||
// ################# API FUNCTIONS ##################
|
|
||||||
// ##################################################
|
|
||||||
|
|
||||||
private fun updateApi(res: JSONObject, isCompensatingLatency : Boolean = false) {
|
|
||||||
// If we're not in PLAYING state, update title / artist metadata. If we're playing, the ICY will take care of that.
|
|
||||||
|
|
||||||
val resMain = res.getJSONObject("tracks").getJSONObject("current")
|
|
||||||
val s = extractSong(resMain)
|
|
||||||
if (playbackState.value != PlaybackStateCompat.STATE_PLAYING || currentSong.title.value.isNullOrEmpty()
|
|
||||||
|| currentSong.title.value == noConnectionValue)
|
|
||||||
currentSong.setTitleArtist("${s.artist.value} - ${s.title.value}")
|
|
||||||
|
|
||||||
val starts = s.startTime.value
|
|
||||||
val ends = s.stopTime.value
|
|
||||||
|
|
||||||
if (currentSong.startTime.value != starts)
|
|
||||||
currentSong.startTime.value = starts
|
|
||||||
|
|
||||||
currentSong.stopTime.value = ends
|
|
||||||
|
|
||||||
val apiTime = getTimestamp(res.getJSONObject("station").getString("schedulerTime"))
|
|
||||||
// I noticed that the server has a big (3 to 9 seconds !!) offset for current time.
|
|
||||||
// we can measure it when the player is playing, to compensate it and have our progress bar perfectly timed
|
|
||||||
// latencyCompensator is set to null when beginPlaying() (we can't measure it at the moment we start playing, since we're in the middle of a song),
|
|
||||||
// at this moment, we set it to 0. Then, next time the updateApi is called when we're playing, we measure the latency and we set out latencyComparator.
|
|
||||||
if(isCompensatingLatency)
|
|
||||||
{
|
|
||||||
latencyCompensator = apiTime - (currentSong.startTime.value!!)
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "latency compensator set to ${(latencyCompensator).toFloat() / 1000} s")
|
|
||||||
}
|
|
||||||
currentTime.value = apiTime - (latencyCompensator)
|
|
||||||
|
|
||||||
/*
|
|
||||||
val listeners = resMain.getInt("listeners")
|
|
||||||
listenersCount.value = listeners
|
|
||||||
//[REMOVE LOG CALLS]Log.d((tag, playerStoreTag + "store updated")
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private val scrape : (Any?) -> String =
|
|
||||||
{
|
|
||||||
URL(urlToScrape).readText()
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initApi is called :
|
|
||||||
- at startup
|
|
||||||
- when a streamer changes.
|
|
||||||
the idea is to fetch the queue when a streamer changes (potentially Hanyuu), and at startup.
|
|
||||||
The Last Played is only fetched if it's empty (so, only at startup), not when a streamer changes.
|
|
||||||
*/
|
|
||||||
fun initApi()
|
|
||||||
{
|
|
||||||
val post : (parameter: Any?) -> Unit = {
|
|
||||||
val result = JSONObject(it as String)
|
|
||||||
if (result.has("tracks"))
|
|
||||||
{
|
|
||||||
updateApi(result)
|
|
||||||
currentSongBackup.copy(currentSong)
|
|
||||||
fetchLastRequest()
|
|
||||||
isQueueUpdated.value = true
|
|
||||||
|
|
||||||
isLpUpdated.value = true
|
|
||||||
}
|
|
||||||
isInitialized = true
|
|
||||||
}
|
|
||||||
Async(scrape, post)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fetchApi(isCompensatingLatency: Boolean = false) {
|
|
||||||
val post: (parameter: Any?) -> Unit = {
|
|
||||||
val result = JSONObject(it as String)
|
|
||||||
if (!result.isNull("tracks"))
|
|
||||||
{
|
|
||||||
updateApi(result, isCompensatingLatency)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Async(scrape, post)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun extractSong(songJSON: JSONObject) : Song {
|
|
||||||
val song = Song()
|
|
||||||
song.setTitleArtist(songJSON.getString("name"))
|
|
||||||
song.startTime.value = getTimestamp(songJSON.getString("starts"))
|
|
||||||
song.stopTime.value = getTimestamp(songJSON.getString("ends"))
|
|
||||||
song.type.value = 0 // only used for R/a/dio
|
|
||||||
return song
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ##################################################
|
|
||||||
// ############## QUEUE / LP FUNCTIONS ##############
|
|
||||||
// ##################################################
|
|
||||||
|
|
||||||
fun updateQueue() {
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, queue.toString())
|
|
||||||
fetchLastRequest()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateLp() {
|
|
||||||
// note : lp is empty at initialization. This check was needed when we used the R/a/dio API.
|
|
||||||
//if (lp.isNotEmpty()){
|
|
||||||
val n = Song()
|
|
||||||
n.copy(currentSongBackup)
|
|
||||||
if (n != Song(noConnectionValue) && n != Song(streamDownValue))
|
|
||||||
lp.add(0, n)
|
|
||||||
currentSongBackup.copy(currentSong)
|
|
||||||
isLpUpdated.value = true
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, playerStoreTag + lp.toString())
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun fetchLastRequest()
|
|
||||||
{
|
|
||||||
isQueueUpdated.value = false
|
|
||||||
val sleepScrape: (Any?) -> String = {
|
|
||||||
/* we can maximize our chances to retrieve the last queued song by specifically waiting for the number of seconds we measure between ICY metadata and API change.
|
|
||||||
we add 2 seconds just to get a higher probability that the API has correctly updated. (the latency compensator can have a jitter of 1 second usually)
|
|
||||||
If, against all odds, the API hasn't updated yet, we will retry in the same amount of seconds. So we'll have the data anyway.
|
|
||||||
This way to fetch at the most probable time is a good compromise between fetch speed and fetch frequency
|
|
||||||
We don't fetch too often, and we start to fetch at the most *probable* time.
|
|
||||||
If there's no latencyCompensator measured yet, we only wait for 3 seconds.
|
|
||||||
If the song is the same, it will be called again. 3 seconds is a good compromise between speed and frequency:
|
|
||||||
it might be called twice, rarely 3 times, and it's only the 2 first songs ; after these, the latencyCompensator is set to fetch at the most probable time.
|
|
||||||
*/
|
|
||||||
val sleepTime: Long = if (latencyCompensator > 0) latencyCompensator + 2000 else 3000
|
|
||||||
Thread.sleep(sleepTime) // we wait a bit (10s) for the API to get updated on R/a/dio side!
|
|
||||||
URL(urlToScrape).readText()
|
|
||||||
}
|
|
||||||
|
|
||||||
lateinit var post: (parameter: Any?) -> Unit
|
|
||||||
|
|
||||||
fun postFun(result: JSONObject)
|
|
||||||
{
|
|
||||||
if (result.has("tracks")) {
|
|
||||||
val resMain = result.getJSONObject("tracks")
|
|
||||||
/*
|
|
||||||
if ((resMain.has("isafkstream") && !resMain.getBoolean("isafkstream")) &&
|
|
||||||
queue.isNotEmpty())
|
|
||||||
{
|
|
||||||
queue.clear() //we're not requesting anything anymore.
|
|
||||||
isQueueUpdated.value = true
|
|
||||||
} else if (resMain.has("isafkstream") && resMain.getBoolean("isafkstream") &&
|
|
||||||
queue.isEmpty())
|
|
||||||
{
|
|
||||||
initApi()
|
|
||||||
} else
|
|
||||||
*/
|
|
||||||
if (resMain.has("next")) {
|
|
||||||
val queueJSON =
|
|
||||||
resMain.getJSONObject("next")
|
|
||||||
val t = extractSong(queueJSON)
|
|
||||||
if (queue.isNotEmpty() && (t == queue.last() || t == currentSong) && isQueueUpdated.value == false)
|
|
||||||
{
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, playerStoreTag + "Song already in there: $t\nQueue:$queue")
|
|
||||||
Async(sleepScrape, post)
|
|
||||||
} else {
|
|
||||||
if (queue.isNotEmpty())
|
|
||||||
queue.remove(queue.first())
|
|
||||||
queue.add(queue.size, t)
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, playerStoreTag + "added last queue song: $t")
|
|
||||||
isQueueUpdated.value = true
|
|
||||||
return // FUUUCK IT WAS CALLING THE ASYNC ONE MORE TIME AFTERWARDS !?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
post = {
|
|
||||||
val result = JSONObject(it as String)
|
|
||||||
/* The goal is to pass the result to a function that will process it (postFun).
|
|
||||||
The magic trick is, under circumstances, the last queue song might not have been updated yet when we fetch it.
|
|
||||||
So if this is detected ==> if (t == queue.last() )
|
|
||||||
Then the function re-schedule an Async(sleepScrape, post).
|
|
||||||
To do that, the "post" must be defined BEFORE the function, but the function must be defined BEFORE the "post" value.
|
|
||||||
So I declare "post" as lateinit var, define the function, then define the "post" that calls the function. IT SHOULD WORK.
|
|
||||||
*/
|
|
||||||
postFun(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
Async(sleepScrape, post)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ##################################################
|
|
||||||
// ############## PICTURE FUNCTIONS #################
|
|
||||||
// ##################################################
|
|
||||||
|
|
||||||
fun initPicture(c: Context) {
|
|
||||||
streamerPicture.value = BitmapFactory.decodeResource(c.resources,
|
|
||||||
R.drawable.logo_roundsquare
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val playerStoreTag = "====PlayerStore===="
|
|
||||||
companion object {
|
|
||||||
val instance by lazy {
|
|
||||||
PlayerStore()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
package fr.riff_app.riff.preferences
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.media.AudioManager
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.preference.SeekBarPreference
|
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
|
||||||
import fr.riff_app.riff.Actions
|
|
||||||
import fr.riff_app.riff.R
|
|
||||||
import fr.riff_app.riff.RadioService
|
|
||||||
import fr.riff_app.riff.playerstore.PlayerStore
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
|
|
||||||
class AlarmAdjustVolumeFragment : PreferenceFragmentCompat() {
|
|
||||||
override fun onAttach(context: Context) {
|
|
||||||
(activity as AppCompatActivity).supportActionBar?.title = context.getString(R.string.test_alarm_volume)
|
|
||||||
super.onAttach(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get previous state: if it's playing, we'll resume playing as multimedia; if it was stopped, we'll stop
|
|
||||||
private var isPlayingMultimedia: Boolean = PlayerStore.instance.isPlaying.value ?: false
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
if (isPlayingMultimedia)
|
|
||||||
{
|
|
||||||
actionOnService(Actions.PLAY)
|
|
||||||
} else {
|
|
||||||
actionOnService(Actions.PAUSE)
|
|
||||||
}
|
|
||||||
PlayerStore.instance.volume.value = PreferenceManager.getDefaultSharedPreferences(requireContext()).getInt("volume", 100)
|
|
||||||
super.onStop()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
|
|
||||||
isPlayingMultimedia = PlayerStore.instance.isPlaying.value ?: false
|
|
||||||
// start as alarm
|
|
||||||
actionOnService(Actions.PLAY_OR_FALLBACK)
|
|
||||||
super.onResume()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
fun <T> debounce(delayMs: Long = 500L,
|
|
||||||
coroutineContext: CoroutineContext,
|
|
||||||
f: (T) -> Unit): (T) -> Unit {
|
|
||||||
var debounceJob: Job? = null
|
|
||||||
return { param: T ->
|
|
||||||
if (debounceJob?.isCompleted != false) {
|
|
||||||
debounceJob = CoroutineScope(coroutineContext).launch {
|
|
||||||
delay(delayMs)
|
|
||||||
f(param)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val adjustAlarmVolume: (Int) -> Unit = debounce<Int>(50, GlobalScope.coroutineContext) {
|
|
||||||
android.util.Log.d(tag, "button $it pushed")
|
|
||||||
val keyCode = it
|
|
||||||
val audioManager = requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
||||||
audioManager.apply {
|
|
||||||
val currentVolume = this.getStreamVolume(AudioManager.STREAM_ALARM)
|
|
||||||
val minVolume = 0 // audioManager.getStreamMinVolume(AudioManager.STREAM_ALARM) <- require API28+
|
|
||||||
val maxVolume = this.getStreamMaxVolume(AudioManager.STREAM_ALARM)
|
|
||||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
|
|
||||||
this.setStreamVolume(AudioManager.STREAM_ALARM, max(currentVolume - 1, minVolume), AudioManager.FLAG_SHOW_UI)
|
|
||||||
|
|
||||||
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP){
|
|
||||||
this.setStreamVolume(AudioManager.STREAM_ALARM, min(currentVolume + 1, maxVolume), AudioManager.FLAG_SHOW_UI)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
view.isFocusableInTouchMode = true;
|
|
||||||
view.requestFocus();
|
|
||||||
view.setOnKeyListener { _, i, event ->
|
|
||||||
if (i == KeyEvent.KEYCODE_VOLUME_DOWN || i == KeyEvent.KEYCODE_VOLUME_UP) {
|
|
||||||
adjustAlarmVolume(i)
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.alarm_adjust_volume_preferences, rootKey)
|
|
||||||
|
|
||||||
val alarmVolumeSeekBar = findPreference<SeekBarPreference>("alarmVolume")
|
|
||||||
alarmVolumeSeekBar?.apply {
|
|
||||||
min = 0
|
|
||||||
max = 100
|
|
||||||
updatesContinuously = true
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
actionOnService(Actions.VOLUME, newValue as Int)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun actionOnService(a: Actions, v: Int = 0)
|
|
||||||
{
|
|
||||||
val i = Intent(requireContext(), RadioService::class.java)
|
|
||||||
i.putExtra("action", a.name)
|
|
||||||
i.putExtra("value", v)
|
|
||||||
//[REMOVE LOG CALLS]Log.d(tag, "Sending intent ${a.name}")
|
|
||||||
requireContext().startService(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24"
|
|
||||||
android:tint="#FFFFFF"
|
|
||||||
android:alpha="0.8">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
|
||||||
</vector>
|
|
||||||
|
Before Width: | Height: | Size: 205 B |
|
Before Width: | Height: | Size: 157 B |
|
|
@ -1,11 +1,11 @@
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:opacity="opaque">
|
android:opacity="opaque">
|
||||||
<!-- The background color, preferably the same as your normal theme -->
|
<!-- The background color, preferably the same as your normal theme -->
|
||||||
<item android:drawable="@color/black"/>
|
<item android:drawable="@color/colorAccent"/>
|
||||||
<!-- Your product logo - 144dp color version of your app icon -->
|
<!-- Your product logo - 144dp color version of your app icon -->
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:drawable="@mipmap/ic_launcher"
|
android:drawable="@drawable/ic_tsumugi_lineart"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:height="144dp"
|
android:height="144dp"
|
||||||
android:width="144dp"
|
android:width="144dp"
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 235 B |
|
Before Width: | Height: | Size: 318 B |
|
|
@ -1,11 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="128dp"
|
android:width="108dp"
|
||||||
android:height="128dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="128"
|
android:viewportWidth="108"
|
||||||
android:viewportHeight="128">
|
android:viewportHeight="108"
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
android:strokeWidth="1"
|
android:fillColor="@color/colorAccent"
|
||||||
android:pathData="M-22.4,-18.02h249.46v189.63h-249.46z"
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
android:fillColor="#000000"
|
|
||||||
android:strokeColor="#ffffff"/>
|
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:opacity="opaque">
|
android:opacity="opaque">
|
||||||
<!-- The background color, preferably the same as your normal theme -->
|
<!-- The background color, preferably the same as your normal theme -->
|
||||||
<item android:drawable="@color/black"/>
|
<item android:drawable="@color/colorPrimaryDark"/>
|
||||||
<!-- Your product logo - 144dp color version of your app icon -->
|
<!-- Your product logo - 144dp color version of your app icon -->
|
||||||
|
|
||||||
<item
|
<item
|
||||||
>
|
>
|
||||||
<bitmap
|
<bitmap
|
||||||
android:src="@mipmap/ic_launcher"
|
android:src="@drawable/splash_logo"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
/>
|
/>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 110 KiB |
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
</selector>
|
|
||||||
|
After Width: | Height: | Size: 13 KiB |
|
|
@ -42,7 +42,7 @@
|
||||||
android:id="@+id/logo_persistent"
|
android:id="@+id/logo_persistent"
|
||||||
android:layout_width="?attr/actionBarSize"
|
android:layout_width="?attr/actionBarSize"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
app:srcCompat="@mipmap/ic_launcher"
|
app:srcCompat="@drawable/logo_roundsquare"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,10 @@
|
||||||
android:contentDescription="dj-image"
|
android:contentDescription="dj-image"
|
||||||
android:scaleType="fitStart"
|
android:scaleType="fitStart"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/scrollViewMetadataNext"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@id/imageGuideline"
|
app:layout_constraintStart_toStartOf="@id/imageGuideline"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@mipmap/ic_launcher"
|
app:srcCompat="@drawable/logo_roundsquare"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
<!-- app:layout_constraintBottom_toTopOf="@id/imageLeftGuideline" -->
|
<!-- app:layout_constraintBottom_toTopOf="@id/imageLeftGuideline" -->
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintGuide_percent="0.71" />
|
app:layout_constraintGuide_percent="0.68" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Guideline
|
<androidx.constraintlayout.widget.Guideline
|
||||||
android:id="@+id/imageLeftGuideline"
|
android:id="@+id/imageLeftGuideline"
|
||||||
|
|
@ -93,6 +93,13 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/topInfoGuideline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintGuide_percent="0.95" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/sleepInfo"
|
android:id="@+id/sleepInfo"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
@ -140,7 +147,7 @@
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/volume_icon"
|
android:id="@+id/volume_icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="20dp"
|
android:layout_height="24dp"
|
||||||
android:contentDescription="@string/volume"
|
android:contentDescription="@string/volume"
|
||||||
android:src="@drawable/ic_volume_high"
|
android:src="@drawable/ic_volume_high"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
|
|
@ -155,12 +162,10 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:fillViewport="true"
|
android:fillViewport="true"
|
||||||
android:layout_marginBottom="4dp"
|
app:layout_constraintBottom_toTopOf="@id/topInfoGuideline"
|
||||||
app:layout_constraintBottom_toTopOf="@id/scrollProgramme"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/streamerPicture"
|
app:layout_constraintEnd_toStartOf="@id/streamerPicture"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/seek_bar_volume"
|
app:layout_constraintTop_toBottomOf="@id/seek_bar_volume">
|
||||||
>
|
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
|
@ -179,8 +184,8 @@
|
||||||
android:layout_gravity="top"
|
android:layout_gravity="top"
|
||||||
android:text="@string/up_next"
|
android:text="@string/up_next"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="@color/whited5"
|
android:textColor="@color/whited3"
|
||||||
android:layout_marginTop="0dp"
|
android:layout_marginTop="8dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
@ -190,94 +195,32 @@
|
||||||
android:id="@+id/text_song_artist_next"
|
android:id="@+id/text_song_artist_next"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="bottom|center_horizontal"
|
android:gravity="bottom"
|
||||||
android:text=""
|
android:text=""
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="@color/whited3"
|
android:textColor="@color/whited3"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/upNext"
|
app:layout_constraintTop_toBottomOf="@id/upNext"
|
||||||
android:visibility="visible"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text_song_title_next"
|
android:id="@+id/text_song_title_next"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="bottom|center_horizontal"
|
android:gravity="bottom"
|
||||||
android:text=""
|
android:text=""
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="@color/whited"
|
android:textColor="@color/whited"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/text_song_artist_next"
|
app:layout_constraintTop_toBottomOf="@id/text_song_artist_next" />
|
||||||
android:visibility="visible" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/scrollProgramme"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fillViewport="true"
|
|
||||||
android:layout_marginBottom="0dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/scrollViewMetadataNext"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/topInfoGuideline"
|
|
||||||
>
|
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:visibility="visible"
|
|
||||||
>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/current_programme"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="top|center_horizontal"
|
|
||||||
android:text="@string/current_programme"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textColor="@color/whited3"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:visibility="visible" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_current_programme"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text=""
|
|
||||||
android:layout_marginStart="8sp"
|
|
||||||
android:layout_marginLeft="8sp"
|
|
||||||
android:gravity="start|center_horizontal"
|
|
||||||
android:textAlignment="textStart"
|
|
||||||
android:textColor="@color/whited"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/current_programme"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:visibility="gone"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Guideline
|
|
||||||
android:id="@+id/topInfoGuideline"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
app:layout_constraintGuide_percent="0.97" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
|
@ -321,7 +264,7 @@
|
||||||
android:id="@+id/text_song_title"
|
android:id="@+id/text_song_title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="bottom|center_horizontal"
|
android:gravity="bottom"
|
||||||
android:text=""
|
android:text=""
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="@color/whited"
|
android:textColor="@color/whited"
|
||||||
|
|
@ -333,7 +276,7 @@
|
||||||
android:id="@+id/text_song_artist"
|
android:id="@+id/text_song_artist"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="bottom|center_horizontal"
|
android:gravity="bottom"
|
||||||
android:text=""
|
android:text=""
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="@color/whited3"
|
android:textColor="@color/whited3"
|
||||||
|
|
@ -362,7 +305,7 @@
|
||||||
android:progressDrawable="@drawable/progress_bar_progress"
|
android:progressDrawable="@drawable/progress_bar_progress"
|
||||||
app:layout_constraintBottom_toTopOf="@id/play_pause"
|
app:layout_constraintBottom_toTopOf="@id/play_pause"
|
||||||
tools:layout_editor_absoluteX="0dp"
|
tools:layout_editor_absoluteX="0dp"
|
||||||
android:visibility="visible"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<!-- REMOVE VISIBILITY GONE IF YOU HAVE TIME VALUES TO DISPLAY THE PROGRESS BAR -->
|
<!-- REMOVE VISIBILITY GONE IF YOU HAVE TIME VALUES TO DISPLAY THE PROGRESS BAR -->
|
||||||
<TextView
|
<TextView
|
||||||
|
|
@ -375,7 +318,7 @@
|
||||||
android:textAlignment="textEnd"
|
android:textAlignment="textEnd"
|
||||||
app:layout_constraintEnd_toEndOf="@id/progressBar"
|
app:layout_constraintEnd_toEndOf="@id/progressBar"
|
||||||
app:layout_constraintTop_toBottomOf="@id/progressBar"
|
app:layout_constraintTop_toBottomOf="@id/progressBar"
|
||||||
android:visibility="visible"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<!-- REMOVE VISIBILITY GONE IF YOU HAVE TIME VALUES TO DISPLAY THE PROGRESS BAR -->
|
<!-- REMOVE VISIBILITY GONE IF YOU HAVE TIME VALUES TO DISPLAY THE PROGRESS BAR -->
|
||||||
<TextView
|
<TextView
|
||||||
|
|
@ -388,7 +331,7 @@
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
app:layout_constraintStart_toStartOf="@id/progressBar"
|
app:layout_constraintStart_toStartOf="@id/progressBar"
|
||||||
app:layout_constraintTop_toBottomOf="@id/progressBar"
|
app:layout_constraintTop_toBottomOf="@id/progressBar"
|
||||||
android:visibility="visible"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -403,7 +346,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintGuide_percent="0.63" />
|
app:layout_constraintGuide_percent="0.58" />
|
||||||
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
|
@ -438,7 +381,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintGuide_percent="0.38" />
|
app:layout_constraintGuide_percent="0.33" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Guideline
|
<androidx.constraintlayout.widget.Guideline
|
||||||
android:id="@+id/splitHorizontalLayout"
|
android:id="@+id/splitHorizontalLayout"
|
||||||
|
|
|
||||||
|
|
@ -15,22 +15,23 @@
|
||||||
app:showAsAction="ifRoom"/>
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_refresh"
|
||||||
|
android:title="@string/action_refresh"
|
||||||
|
app:showAsAction="never"/>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_bug_submit"
|
android:id="@+id/action_bug_submit"
|
||||||
android:title="@string/action_bug_submit"
|
android:title="@string/action_bug_submit"
|
||||||
app:showAsAction="never"/>
|
app:showAsAction="never"/>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_refresh"
|
|
||||||
android:title="@string/action_refresh"
|
|
||||||
app:showAsAction="never"/>
|
|
||||||
|
|
||||||
<item android:id="@+id/action_settings"
|
<item android:id="@+id/action_settings"
|
||||||
android:title="@string/action_settings"
|
android:title="@string/action_settings"
|
||||||
android:icon="@drawable/ic_settings"
|
android:icon="@drawable/ic_settings"
|
||||||
app:showAsAction="never"/>
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 5.9 KiB |