diff --git a/app/src/main/assets/chat.html b/app/src/main/assets/chat.html deleted file mode 100644 index 650c9a2..0000000 --- a/app/src/main/assets/chat.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - -
- -
- - - - \ No newline at end of file diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png index 2c5335a..606603c 100644 Binary files a/app/src/main/ic_launcher-web.png and b/app/src/main/ic_launcher-web.png differ diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/BaseNotification.kt b/app/src/main/java/fr/forum_thalie/tsumugi/BaseNotification.kt index 1b18345..c236c7f 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/BaseNotification.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/BaseNotification.kt @@ -71,7 +71,7 @@ abstract class BaseNotification(private val notificationChannelId: String, builder.setSmallIcon(R.drawable.lollipop_logo) builder.color = -0xf58b01 // same color as Accent. Can't use c.getColor since it's API23+ } else { - builder.setSmallIcon(R.drawable.normal_logo) + builder.setSmallIcon(R.drawable.logo_roundsquare) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/BootBroadcastReceiver.kt b/app/src/main/java/fr/forum_thalie/tsumugi/BootBroadcastReceiver.kt index 118b168..e8c0c79 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/BootBroadcastReceiver.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/BootBroadcastReceiver.kt @@ -8,8 +8,6 @@ import android.util.Log import androidx.preference.PreferenceManager import fr.forum_thalie.tsumugi.alarm.RadioAlarm import fr.forum_thalie.tsumugi.playerstore.PlayerStore -import fr.forum_thalie.tsumugi.streamerNotificationService.WorkerStore -import fr.forum_thalie.tsumugi.streamerNotificationService.startStreamerMonitor class BootBroadcastReceiver : BroadcastReceiver(){ @@ -19,8 +17,6 @@ class BootBroadcastReceiver : BroadcastReceiver(){ preferenceStore = PreferenceManager.getDefaultSharedPreferences(context) if (arg1.action == Intent.ACTION_BOOT_COMPLETED) { - WorkerStore.instance.init(context) - startStreamerMonitor(context) // will actually start it only if enabled in settings RadioAlarm.instance.setNextAlarm(context) // schedule next alarm } @@ -29,8 +25,6 @@ class BootBroadcastReceiver : BroadcastReceiver(){ RadioAlarm.instance.setNextAlarm(context) // schedule next alarm if (PlayerStore.instance.streamerName.value.isNullOrBlank()) PlayerStore.instance.initPicture(context) - if (!PlayerStore.instance.isInitialized) - PlayerStore.instance.initApi() val i = Intent(context, RadioService::class.java) i.putExtra("action", Actions.PLAY_OR_FALLBACK.name) diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/MainActivity.kt b/app/src/main/java/fr/forum_thalie/tsumugi/MainActivity.kt index 9e6fc8f..acf7cd6 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/MainActivity.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/MainActivity.kt @@ -15,12 +15,8 @@ import fr.forum_thalie.tsumugi.playerstore.PlayerStore import java.util.Timer import android.view.MenuItem -import androidx.preference.PreferenceManager import com.google.android.material.snackbar.Snackbar import fr.forum_thalie.tsumugi.alarm.RadioAlarm -import fr.forum_thalie.tsumugi.streamerNotificationService.WorkerStore -import fr.forum_thalie.tsumugi.streamerNotificationService.startStreamerMonitor -import fr.forum_thalie.tsumugi.ui.songs.request.Requestor /* Log to file import @@ -39,11 +35,11 @@ class MainActivity : BaseActivity() { * Called on first creation and when restoring state. */ private fun setupBottomNavigationBar() { - val bottomNavigationView = findViewById(R.id.bottom_nav) + val bottomNavigationView : BottomNavigationView = findViewById(R.id.bottom_nav) //val navGraphIds = listOf(R.navigation.home, R.navigation.list, R.navigation.form) val navGraphIds = listOf(R.navigation.navigation_nowplaying, R.navigation.navigation_songs, - R.navigation.navigation_news, R.navigation.navigation_chat) + R.navigation.navigation_news) // Setup the bottom navigation view with a list of navigation graphs val controller = bottomNavigationView.setupWithNavController( @@ -77,15 +73,15 @@ class MainActivity : BaseActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle item selection return when (item.itemId) { + /* R.id.action_refresh -> { PlayerStore.instance.queue.clear() PlayerStore.instance.lp.clear() - PlayerStore.instance.initApi() - Requestor.instance.initFavorites() val s = Snackbar.make(findViewById(R.id.nav_host_container), "Refreshing data..." as CharSequence, Snackbar.LENGTH_LONG) s.show() true } + */ R.id.action_settings -> { val i = Intent(this, ParametersActivity::class.java) startActivity(i) @@ -118,10 +114,6 @@ class MainActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - WorkerStore.instance.init(this) - startStreamerMonitor(this) // this checks the preferenceStore before actually starting a service, don't worry. - RadioAlarm.instance.cancelAlarm(c = this) RadioAlarm.instance.setNextAlarm(c = this) // this checks the preferenceStore before actually setting an alarm, don't worry. @@ -132,8 +124,6 @@ class MainActivity : BaseActivity() { colorRedList = (ResourcesCompat.getColorStateList(resources, R.color.button_red, null)) colorGreenListCompat = (ResourcesCompat.getColorStateList(resources, R.color.button_green_compat, null)) - PlayerStore.instance.initApi() // the service will call the initApi on defining the streamerName Observer too, but it's better to initialize the API as soon as the user opens the activity. - // Post-UI Launch if (PlayerStore.instance.isInitialized) { @@ -149,9 +139,6 @@ class MainActivity : BaseActivity() { // initialize some API data PlayerStore.instance.initPicture(this) PlayerStore.instance.streamerName.value = "" // initializing the streamer name will trigger an initApi from the observer in the Service. - - // initialize the favorites - Requestor.instance.initFavorites() } if (!isTimerStarted) diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ParametersActivity.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ParametersActivity.kt index 4bcef87..d8294da 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ParametersActivity.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/ParametersActivity.kt @@ -29,7 +29,6 @@ class ParametersActivity : BaseActivity() { ActionOpenParam.ALARM.name -> AlarmFragment() ActionOpenParam.SLEEP.name -> SleepFragment() ActionOpenParam.CUSTOMIZE.name -> CustomizeFragment() - ActionOpenParam.STREAMER_NOTIFICATION_SERVICE.name -> StreamerNotifServiceFragment() else -> MainPreferenceFragment() } diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt b/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt index 6ed4eb5..0fada1d 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt @@ -107,29 +107,6 @@ class RadioService : MediaBrowserServiceCompat() { // ################### OBSERVERS #################### // ################################################## - private val titleObserver: Observer = Observer { - if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_PLAYING) - { - 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 == getString(R.string.ed) -> { - PlayerStore.instance.isStreamDown = true - } - else -> { - PlayerStore.instance.fetchApi(numberOfSongs >= 2) - } - } - } - nowPlayingNotification.update(this) - } - private val volumeObserver: Observer = Observer { setVolume(it) } @@ -145,20 +122,14 @@ class RadioService : MediaBrowserServiceCompat() { stopPlaying() } - private val startTimeObserver = Observer { - // We're listening to startTime to determine if we have to update Queue and Lp. - // this is because startTime is set by the API and never by the ICY, so both cases are covered (playing and stopped) - // should be OK even when a new streamer comes in. - if (it != PlayerStore.instance.currentSongBackup.startTime.value) // we have a new song + private val titleObserver = Observer { + // We're checking if a new song arrives. If so, we put the currentSong in Lp and update the backup. + if (PlayerStore.instance.currentSong != PlayerStore.instance.currentSongBackup + && it != noConnectionValue) { PlayerStore.instance.updateLp() - PlayerStore.instance.updateQueue() } - } - - private val streamerObserver = Observer { - PlayerStore.instance.initApi() - nowPlayingNotification.update(this) // should update the streamer icon + nowPlayingNotification.update(this) } private val streamerPictureObserver = Observer { @@ -224,9 +195,7 @@ class RadioService : MediaBrowserServiceCompat() { nowPlayingNotification.create(this, mediaSession) - PlayerStore.instance.streamerName.observeForever(streamerObserver) PlayerStore.instance.currentSong.title.observeForever(titleObserver) - PlayerStore.instance.currentSong.startTime.observeForever(startTimeObserver) PlayerStore.instance.volume.observeForever(volumeObserver) PlayerStore.instance.isPlaying.observeForever(isPlayingObserver) PlayerStore.instance.isMuted.observeForever(isMutedObserver) @@ -234,12 +203,6 @@ class RadioService : MediaBrowserServiceCompat() { startForeground(radioServiceId, nowPlayingNotification.notification) - // 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) - PlayerStore.instance.isServiceStarted.value = true Log.d(tag, radioTag + "created") } @@ -303,7 +266,6 @@ class RadioService : MediaBrowserServiceCompat() { player.release() unregisterReceiver(receiver) PlayerStore.instance.currentSong.title.removeObserver(titleObserver) - PlayerStore.instance.currentSong.startTime.removeObserver(startTimeObserver) PlayerStore.instance.volume.removeObserver(volumeObserver) PlayerStore.instance.isPlaying.removeObserver(isPlayingObserver) PlayerStore.instance.isMuted.removeObserver(isMutedObserver) diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/Tickers.kt b/app/src/main/java/fr/forum_thalie/tsumugi/Tickers.kt index a99ae5a..40049a5 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/Tickers.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/Tickers.kt @@ -11,11 +11,3 @@ class Tick : TimerTask() { } } -class ApiFetchTick : TimerTask() { - override fun run() { - if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_STOPPED) - { - PlayerStore.instance.fetchApi() - } - } -} diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/playerstore/PlayerStore.kt b/app/src/main/java/fr/forum_thalie/tsumugi/playerstore/PlayerStore.kt index 4cf734e..8df0546 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/playerstore/PlayerStore.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/playerstore/PlayerStore.kt @@ -31,10 +31,8 @@ class PlayerStore { val isLpUpdated: MutableLiveData = MutableLiveData() val isMuted : MutableLiveData = MutableLiveData() val listenersCount: MutableLiveData = MutableLiveData() - private val urlToScrape = "https://r-a-d.io/api" var latencyCompensator : Long = 0 var isInitialized: Boolean = false - var isStreamDown: Boolean = false init { playbackState.value = PlaybackStateCompat.STATE_STOPPED @@ -47,6 +45,7 @@ class PlayerStore { isLpUpdated.value = false isMuted.value = false currentSong.title.value = noConnectionValue + currentSongBackup.title.value = noConnectionValue listenersCount.value = 0 } @@ -54,6 +53,7 @@ class PlayerStore { // ################# API FUNCTIONS ################## // ################################################## + /* private fun updateApi(resMain: 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. if (playbackState.value != PlaybackStateCompat.STATE_PLAYING || currentSong.title.value.isNullOrEmpty() @@ -154,24 +154,26 @@ class PlayerStore { } Async(scrape, post) } + */ // ################################################## // ############## QUEUE / LP FUNCTIONS ############## // ################################################## fun updateLp() { - // note : lp must never be empty. There should always be some songs "last played". - // if not, then the function has been called before initialization. No need to do anything. - if (lp.isNotEmpty()){ + // 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) - lp.add(0, n) + if (n.title.value != noConnectionValue) + lp.add(0, n) currentSongBackup.copy(currentSong) isLpUpdated.value = true Log.d(tag, playerStoreTag + lp.toString()) - } + //} } + /* fun updateQueue() { if (queue.isNotEmpty()) { queue.remove(queue.first()) @@ -257,11 +259,13 @@ class PlayerStore { song.type.value = songJSON.getInt("type") return song } + */ // ################################################## // ############## PICTURE FUNCTIONS ################# // ################################################## + /* private fun fetchPicture(fileUrl: String) { val scrape: (Any?) -> Bitmap? = { @@ -287,10 +291,11 @@ class PlayerStore { } Async(scrape, post) } + */ fun initPicture(c: Context) { streamerPicture.value = BitmapFactory.decodeResource(c.resources, - R.drawable.actionbar_logo + R.drawable.logo_roundsquare ) } diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/preferences/CustomizeFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/preferences/CustomizeFragment.kt index f8d8efb..a41b394 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/preferences/CustomizeFragment.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/preferences/CustomizeFragment.kt @@ -8,19 +8,11 @@ import androidx.appcompat.app.AlertDialog import androidx.preference.* import fr.forum_thalie.tsumugi.R import fr.forum_thalie.tsumugi.preferenceStore -import fr.forum_thalie.tsumugi.ui.songs.request.Requestor class CustomizeFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.customize_preferences, rootKey) - val userNamePref = preferenceScreen.findPreference("userName") - userNamePref?.summaryProvider = EditTextPreference.SimpleSummaryProvider.getInstance() - userNamePref?.setOnPreferenceChangeListener { _, newValue -> - val name = newValue as String - Requestor.instance.initFavorites(name) // need to be as parameter cause the callback is called BEFORE PARAMETER SET - true - } val snackbarPersistent = preferenceScreen.findPreference("snackbarPersistent") snackbarPersistent!!.summary = if (preferenceStore.getBoolean("snackbarPersistent", true)) @@ -48,33 +40,5 @@ class CustomizeFragment : PreferenceFragmentCompat() { true } - val helpFavorites = preferenceScreen.findPreference("helpFavorites") - helpFavorites?.setOnPreferenceClickListener { _ -> - val url = getString(R.string.github_url_wiki_irc_for_favorites) - val i = Intent(Intent.ACTION_VIEW) - i.data = Uri.parse(url) - startActivity(i) - true - } - - val fetchPeriod = preferenceScreen.findPreference("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.fetch_disabled_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 - } - } } \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/preferences/StreamerNotifServiceFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/preferences/StreamerNotifServiceFragment.kt deleted file mode 100644 index 0383ee1..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/preferences/StreamerNotifServiceFragment.kt +++ /dev/null @@ -1,63 +0,0 @@ -package fr.forum_thalie.tsumugi.preferences - -import android.os.Bundle -import androidx.appcompat.app.AlertDialog -import androidx.preference.* -import fr.forum_thalie.tsumugi.R -import fr.forum_thalie.tsumugi.preferenceStore -import fr.forum_thalie.tsumugi.streamerNotificationService.WorkerStore -import fr.forum_thalie.tsumugi.streamerNotificationService.startStreamerMonitor -import fr.forum_thalie.tsumugi.streamerNotificationService.stopStreamerMonitor - -class StreamerNotifServiceFragment : PreferenceFragmentCompat() { - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.streamer_notif_service_preferences, rootKey) - - - val streamerPeriod = preferenceScreen.findPreference("streamerMonitorPeriodPref") - - val streamerNotification = preferenceScreen.findPreference("newStreamerNotification") - streamerNotification?.setOnPreferenceChangeListener { _, newValue -> - if ((newValue as Boolean)) { - val builder1 = AlertDialog.Builder(context!!) - builder1.setMessage(R.string.warningStreamerNotif) - builder1.setCancelable(false) - builder1.setPositiveButton( - "Yes" - ) { dialog, _ -> - startStreamerMonitor(context!!, force = true) // force enabled because the preference value is not yet set when running this callback. - streamerPeriod?.isEnabled = true - dialog.cancel() - } - - builder1.setNegativeButton( - "No" - ) { dialog, _ -> - - stopStreamerMonitor(context!!) - (streamerNotification as SwitchPreferenceCompat).isChecked = false - dialog.cancel() - } - - val alert11 = builder1.create() - alert11.show() - } - else { - stopStreamerMonitor(context!!) - streamerPeriod?.isEnabled = false - WorkerStore.instance.isServiceStarted = false - } - true - } - - streamerPeriod?.summaryProvider = ListPreference.SimpleSummaryProvider.getInstance() - streamerPeriod?.isEnabled = preferenceStore.getBoolean("newStreamerNotification", true) - streamerPeriod?.setOnPreferenceChangeListener { _, newValue -> - WorkerStore.instance.tickerPeriod = (Integer.parseInt(newValue as String)).toLong() * 60 - // this should be sufficient, the next alarm schedule should take the new tickerPeriod. - true - } - - - } -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/ServiceNotification.kt b/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/ServiceNotification.kt deleted file mode 100644 index bd203aa..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/ServiceNotification.kt +++ /dev/null @@ -1,41 +0,0 @@ -package fr.forum_thalie.tsumugi.streamerNotificationService - -import android.content.Context -import fr.forum_thalie.tsumugi.BaseNotification -import java.util.* - -class ServiceNotification( - notificationChannelId: String, - notificationChannel : Int, - notificationId: Int, - notificationImportance: Int - -) : BaseNotification - ( - notificationChannelId, - notificationChannel, - notificationId, - notificationImportance -){ - - override fun create(c: Context) - { - super.create(c) - update() - } - - fun update() - { - val date = Date() // given date - val calendar = Calendar.getInstance() // creates a new calendar instance - calendar.time = date // assigns calendar to given date - val hours = calendar.get(Calendar.HOUR_OF_DAY) // gets hour in 24h format - //val hours_american = calendar.get(Calendar.HOUR) // gets hour in 12h format - val minutes = calendar.get(Calendar.MINUTE) - val seconds = calendar.get(Calendar.SECOND) - - builder.setContentTitle("Never miss a stream! Current: ${WorkerStore.instance.streamerName.value}") - builder.setContentText("Last update: ${hours}:${minutes}:${seconds}") - notification = builder.build() - } -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerMonitorExtensions.kt b/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerMonitorExtensions.kt deleted file mode 100644 index d3cb66c..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerMonitorExtensions.kt +++ /dev/null @@ -1,114 +0,0 @@ -package fr.forum_thalie.tsumugi.streamerNotificationService - -import android.app.AlarmManager -import android.app.PendingIntent -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.os.Build -import android.os.SystemClock -import android.util.Log -import androidx.core.app.NotificationCompat -import androidx.preference.PreferenceManager -import fr.forum_thalie.tsumugi.* -import fr.forum_thalie.tsumugi.alarm.RadioAlarm -import fr.forum_thalie.tsumugi.playerstore.PlayerStore -import org.json.JSONObject -import java.net.URL - -fun startNextAlarmStreamer(c: Context){ - // the notification works with an alarm re-scheduled at fixed rate. - // if the service stopped, the alarm is not re-scheduled. - if (WorkerStore.instance.isServiceStarted) - { - val alarmIntent = Intent(c, StreamerMonitorService::class.java).let { intent -> - intent.putExtra("action", Actions.NOTIFY.name) - PendingIntent.getService(c, 0, intent, 0) - } - - val alarmMgr = c.getSystemService(Context.ALARM_SERVICE) as AlarmManager - when { - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> alarmMgr.setExactAndAllowWhileIdle( - AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + WorkerStore.instance.tickerPeriod * 1000, - alarmIntent - ) - Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> alarmMgr.setExact( - AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + WorkerStore.instance.tickerPeriod * 1000, - alarmIntent - ) - else -> alarmMgr.set( - AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + WorkerStore.instance.tickerPeriod * 1000, - alarmIntent - ) - } - } else { - Log.d(tag, "alarm called while service is dead - skipped.") - } -} - -fun stopStreamerMonitor(context: Context) -{ - val intent = Intent(context, StreamerMonitorService::class.java) - intent.putExtra("action", Actions.KILL.name) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startService(intent) - } else { - context.startService(intent) - } - - Log.i(tag, "Service stopped") -} - -fun startStreamerMonitor(context: Context, force: Boolean = false) -{ - if (!force) - { - val isNotifyingForNewStreamer = PreferenceManager.getDefaultSharedPreferences(context).getBoolean("newStreamerNotification", false) - if (!isNotifyingForNewStreamer) - return - } - - val intent = Intent(context, StreamerMonitorService::class.java) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent) - } else { - context.startService(intent) - } - - Log.i(tag, "Service started on boot") -} - -fun fetchStreamer(applicationContext: Context) { - val urlToScrape = "https://r-a-d.io/api" - val scrape : (Any?) -> String = - { - URL(urlToScrape).readText() - } - val post: (parameter: Any?) -> Unit = { - val result = JSONObject(it as String) - if (!result.isNull("main")) - { - val name = result.getJSONObject("main").getJSONObject("dj").getString("djname") - WorkerStore.instance.streamerName.value = name - } - } - - // notify - val t = ServiceNotification( - notificationChannelId = applicationContext.getString(R.string.streamerServiceChannelId), - notificationChannel = R.string.streamerServiceChannel, - notificationId = 2, - notificationImportance = NotificationCompat.PRIORITY_LOW - ) - t.create(applicationContext) - t.show() - - try{ - Async(scrape, post) - Log.d(tag, "enqueue next work in ${WorkerStore.instance.tickerPeriod} seconds") - } catch (e: Exception) { - } -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerMonitorService.kt b/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerMonitorService.kt deleted file mode 100644 index fae27ae..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerMonitorService.kt +++ /dev/null @@ -1,123 +0,0 @@ -package fr.forum_thalie.tsumugi.streamerNotificationService - - -import android.app.Service -import android.content.Intent -import android.os.Build -import android.os.IBinder -import android.util.Log -import androidx.core.app.NotificationCompat -import androidx.lifecycle.Observer -import androidx.preference.PreferenceManager -import fr.forum_thalie.tsumugi.Actions -import fr.forum_thalie.tsumugi.R -import fr.forum_thalie.tsumugi.tag -import java.util.* - -class StreamerMonitorService : Service() { - override fun onBind(intent: Intent): IBinder? { - return null // no binding allowed nor needed - } - private val streamerNameObserver: Observer = Observer { - val previousStreamer: String - if (PreferenceManager.getDefaultSharedPreferences(this).contains("streamerName")) - { - previousStreamer = PreferenceManager.getDefaultSharedPreferences(this).getString("streamerName", "") ?: "" - /* 3 conditions: - - the streamer changed from previously - - there is a previous non-empty streamer (at least second time running it) - - the current streamer is non-empty (this can happen at Activity start where init() is called) - */ - if (previousStreamer != it && previousStreamer != "" && it != "") - { - // notify - val newStreamer = StreamerNotification( - notificationChannelId = this.getString(R.string.streamerNotificationChannelId), - notificationChannel = R.string.streamerNotificationChannel, - notificationId = 3, - notificationImportance = NotificationCompat.PRIORITY_DEFAULT - ) - newStreamer.create(this) - newStreamer.show() - } - } - - with(PreferenceManager.getDefaultSharedPreferences(this).edit()){ - putString("streamerName", it) - commit() - } - } - - override fun onCreate() { - super.onCreate() - val streamerMonitorNotification = ServiceNotification( - notificationChannelId = this.getString(R.string.streamerServiceChannelId), - notificationChannel = R.string.streamerServiceChannel, - notificationId = 2, - notificationImportance = NotificationCompat.PRIORITY_LOW - ) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - { - streamerMonitorNotification.create(this) - streamerMonitorNotification.update() - streamerMonitorNotification.show() - startForeground(2, streamerMonitorNotification.notification) - } - - WorkerStore.instance.tickerPeriod = 60 * - (if (PreferenceManager.getDefaultSharedPreferences(this).contains("streamerMonitorPeriodPref")) - Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(this).getString("streamerMonitorPeriodPref", "15")!!).toLong() - else - 15) - Log.d(tag, "tickerPeriod = ${WorkerStore.instance.tickerPeriod}") - - with(PreferenceManager.getDefaultSharedPreferences(this).edit()){ - remove("streamerName") - commit() // I commit on main thread to be sure it's been updated before continuing. - } - WorkerStore.instance.streamerName.observeForever(streamerNameObserver) - WorkerStore.instance.isServiceStarted = true - startNextAlarmStreamer(this) - Log.d(tag, "streamerMonitor created") - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - val isNotifyingForNewStreamer = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("newStreamerNotification", false) - - // it's probably redundant but it shouldn't hurt - if (!isNotifyingForNewStreamer || !WorkerStore.instance.isServiceStarted) - { - stopForeground(true) - stopSelf() - return START_NOT_STICKY - } - when (intent?.getStringExtra("action")) { - Actions.NOTIFY.name -> { - val date = Date() // given date - val calendar = Calendar.getInstance() // creates a new calendar instance - calendar.time = date // assigns calendar to given date - val hours = calendar.get(Calendar.HOUR_OF_DAY) // gets hour in 24h format - //val hours_american = calendar.get(Calendar.HOUR) // gets hour in 12h format - val minutes = calendar.get(Calendar.MINUTE) // gets month number, NOTE this is zero based! - - Log.d(tag, "Fetched streamer name at ${hours}:${if (minutes < 10) "0" else ""}${minutes}") - fetchStreamer(this) - startNextAlarmStreamer(this) // schedule next alarm - return START_STICKY - } - Actions.KILL.name -> { - stopForeground(true) - stopSelf() - return START_NOT_STICKY - } - } - return START_STICKY - //super.onStartCommand(intent, flags, startId) - } - - override fun onDestroy() { - WorkerStore.instance.streamerName.removeObserver(streamerNameObserver) - WorkerStore.instance.isServiceStarted = false - super.onDestroy() - } -} diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerNotification.kt b/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerNotification.kt deleted file mode 100644 index f40c028..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/StreamerNotification.kt +++ /dev/null @@ -1,35 +0,0 @@ -package fr.forum_thalie.tsumugi.streamerNotificationService - -import android.content.Context -import fr.forum_thalie.tsumugi.BaseNotification -import java.util.* - -class StreamerNotification( - notificationChannelId: String, - notificationChannel : Int, - notificationId: Int, - notificationImportance: Int - -) : BaseNotification - ( - notificationChannelId, - notificationChannel, - notificationId, - notificationImportance -){ - override fun create(c: Context) { - super.create(c) - val date = Date() // given date - val calendar = Calendar.getInstance() // creates a new calendar instance - calendar.time = date // assigns calendar to given date - val hours = calendar.get(Calendar.HOUR_OF_DAY) // gets hour in 24h format - //val hours_american = calendar.get(Calendar.HOUR) // gets hour in 12h format - val minutes = calendar.get(Calendar.MINUTE) // gets month number, NOTE this is zero based! - - builder.setContentTitle("${WorkerStore.instance.streamerName.value} started streaming!") - builder.setContentText("Started at ${hours}:${if (minutes < 10) "0" else ""}${minutes}") - builder.setAutoCancel(true) - super.show() - } - -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/WorkerStore.kt b/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/WorkerStore.kt deleted file mode 100644 index b20b50d..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/streamerNotificationService/WorkerStore.kt +++ /dev/null @@ -1,46 +0,0 @@ -package fr.forum_thalie.tsumugi.streamerNotificationService - -import android.content.Context -import android.util.Log -import androidx.core.app.NotificationCompat -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.Observer -import androidx.preference.PreferenceManager -import fr.forum_thalie.tsumugi.R -import fr.forum_thalie.tsumugi.tag - -class WorkerStore { - companion object { - val instance = WorkerStore() - } - - val streamerName = MutableLiveData() - var isServiceStarted : Boolean = false - var tickerPeriod : Long = 45 // seconds - - init { - tickerPeriod = 45 - streamerName.value = "" - isServiceStarted = false - } - - fun init(c: Context) - { - tickerPeriod = 45 - streamerName.value = "" - val tickerPeriod = 60 * - (if (PreferenceManager.getDefaultSharedPreferences(c).contains("streamerMonitorPeriodPref")) - Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(c).getString("streamerMonitorPeriodPref", "15")!!).toLong() - else - 15 - ) - instance.tickerPeriod = tickerPeriod - Log.d(tag, "tickerPeriod = $tickerPeriod") - - with(PreferenceManager.getDefaultSharedPreferences(c).edit()){ - remove("streamerName") - commit() // I commit on main thread to be sure it's been updated before continuing. - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/ChatFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/ChatFragment.kt deleted file mode 100644 index 89718b1..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/ChatFragment.kt +++ /dev/null @@ -1,52 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.chat - -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.WindowManager -import android.webkit.WebView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProviders -import fr.forum_thalie.tsumugi.R - - -class ChatFragment : Fragment() { - - private lateinit var chatViewModel: ChatViewModel - - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - activity?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) - - chatViewModel = - ViewModelProviders.of(this).get(ChatViewModel::class.java) - - if (!chatViewModel.isChatLoaded) - { - - try { - chatViewModel.root = inflater.inflate(R.layout.fragment_chat, container, false) - chatViewModel.webView = chatViewModel.root.findViewById(R.id.chat_webview) - chatViewModel.webViewChat = WebViewChat(chatViewModel.webView as WebView) - chatViewModel.webViewChat!!.start() - } catch (e: Exception) { - chatViewModel.root = inflater.inflate(R.layout.fragment_error_chat, container, false) - } - - chatViewModel.isChatLoaded = true - Log.d(tag, "webview created") - } else { - Log.d(tag, "webview already created!?") - } - - return chatViewModel.root - } - - -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/ChatViewModel.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/ChatViewModel.kt deleted file mode 100644 index 0a4a1aa..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/ChatViewModel.kt +++ /dev/null @@ -1,12 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.chat - -import android.view.View -import android.webkit.WebView -import androidx.lifecycle.ViewModel - -class ChatViewModel : ViewModel() { - lateinit var root: View - var webView: WebView? = null - var isChatLoaded = false - var webViewChat: WebViewChat? = null -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/WebViewChat.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/WebViewChat.kt deleted file mode 100644 index 580c617..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/chat/WebViewChat.kt +++ /dev/null @@ -1,47 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.chat - -import android.annotation.SuppressLint -import android.content.Intent -import android.net.Uri -import android.webkit.WebChromeClient -import android.webkit.WebView - -class WebViewChat(private val webView: WebView) { - - @SuppressLint("SetJavaScriptEnabled") - fun start() { - - val webSetting = this.webView.settings - webSetting.javaScriptEnabled = true - webSetting.setSupportZoom(false) - - /* TODO: in the future, it could be nice to have a parameters screen where you can: - - Set the text zoom - - Set your username (to not type it every time, would it be possible?) - - Hide the chat? - - do more? */ - webSetting.textZoom = 90 - - webSetting.setSupportMultipleWindows(true) - // needs to open target="_blank" links as KiwiIRC links have this attribute. - // shamelessly ripped off https://stackoverflow.com/questions/18187714/android-open-target-blank-links-in-webview-with-external-browser - this.webView.webChromeClient = object : WebChromeClient() { - override fun onCreateWindow( - view: WebView, - dialog: Boolean, - userGesture: Boolean, - resultMsg: android.os.Message - ): Boolean { - val result = view.hitTestResult - val data = result.extra - val context = view.context - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(data)) - context.startActivity(browserIntent) - return false - } - } - - webView.loadUrl("file:///android_asset/chat.html") - } - - } diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/SongsFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/SongsFragment.kt index 1e68823..2ebc21d 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/SongsFragment.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/SongsFragment.kt @@ -5,62 +5,19 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.TextView import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentPagerAdapter -import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import androidx.viewpager.widget.ViewPager -import com.google.android.material.snackbar.BaseTransientBottomBar -import com.google.android.material.snackbar.Snackbar import com.google.android.material.tabs.TabLayout import fr.forum_thalie.tsumugi.R -import fr.forum_thalie.tsumugi.preferenceStore import fr.forum_thalie.tsumugi.ui.songs.queuelp.LastPlayedFragment -import fr.forum_thalie.tsumugi.ui.songs.queuelp.QueueFragment -import fr.forum_thalie.tsumugi.ui.songs.request.FavoritesFragment -import fr.forum_thalie.tsumugi.ui.songs.request.RequestFragment -import fr.forum_thalie.tsumugi.ui.songs.request.Requestor class SongsFragment : Fragment() { private lateinit var adapter : SongsPagerAdapter - private lateinit var snackBar : Snackbar private lateinit var root: View private lateinit var viewPager: ViewPager - - private val snackBarTextObserver: Observer = Observer { - if (Requestor.instance.snackBarText.value != "") - { - val snackBarLength = if (preferenceStore.getBoolean("snackbarPersistent", true)) - Snackbar.LENGTH_INDEFINITE - else Snackbar.LENGTH_LONG - snackBar = Snackbar.make(viewPager, "", snackBarLength) - - if (snackBarLength == Snackbar.LENGTH_INDEFINITE) - snackBar.setAction("OK") { - snackBar.dismiss() - } - - snackBar.behavior = BaseTransientBottomBar.Behavior().apply { - setSwipeDirection(BaseTransientBottomBar.Behavior.SWIPE_DIRECTION_ANY) - } - - val snackBarView = snackBar.view - val textView = - snackBarView.findViewById(com.google.android.material.R.id.snackbar_text) as TextView - if (Requestor.instance.addRequestMeta != "") - textView.maxLines = 4 - else - textView.maxLines = 2 - snackBar.setText((it as CharSequence)) - snackBar.show() - Requestor.instance.snackBarText.value = "" // resetting afterwards to avoid re-triggering it when we enter again the fragment - Requestor.instance.addRequestMeta = "" - } - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -71,9 +28,8 @@ class SongsFragment : Fragment() { viewPager = root.findViewById(R.id.tabPager) adapter = SongsPagerAdapter(childFragmentManager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) adapter.addFragment(LastPlayedFragment.newInstance(), "last played") - adapter.addFragment(QueueFragment.newInstance(), "queue") - adapter.addFragment(RequestFragment.newInstance(), "request") - adapter.addFragment(FavoritesFragment.newInstance(), "Favorites") + + //adapter.addFragment(QueueFragment.newInstance(), "queue") viewPager.adapter = adapter @@ -81,14 +37,8 @@ class SongsFragment : Fragment() { tabLayout.setupWithViewPager(viewPager) Log.d(tag, "SongFragment view created") - Requestor.instance.snackBarText.observeForever(snackBarTextObserver) return root } - override fun onDestroyView() { - Requestor.instance.snackBarText.removeObserver(snackBarTextObserver) - super.onDestroyView() - } - } \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/queuelp/QueueFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/queuelp/QueueFragment.kt deleted file mode 100644 index 72a7b7f..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/queuelp/QueueFragment.kt +++ /dev/null @@ -1,70 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.songs.queuelp - -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import fr.forum_thalie.tsumugi.R -import fr.forum_thalie.tsumugi.playerstore.PlayerStore -import fr.forum_thalie.tsumugi.playerstore.Song - -class QueueFragment : Fragment(){ - private val lastPlayedFragmentTag = this::class.java.name - - private lateinit var recyclerView: RecyclerView - private lateinit var viewAdapter: RecyclerView.Adapter<*> - private lateinit var viewManager: RecyclerView.LayoutManager - - - private val queueObserver = Observer { - Log.d(tag, lastPlayedFragmentTag + "queue changed") - viewAdapter.notifyDataSetChanged() - } - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // Inflate the layout for this fragment - val root = inflater.inflate(R.layout.fragment_last_played, container, false) - - viewManager = LinearLayoutManager(context) - viewAdapter = SongAdaptater( - if (PlayerStore.instance.queue.isEmpty()) - ArrayList(listOf((Song("No queue - ")))) - else - PlayerStore.instance.queue - ) - - recyclerView = root.findViewById(R.id.queue_lp_recycler).apply { - // use this setting to improve performance if you know that changes - // in content do not change the layout size of the RecyclerView - setHasFixedSize(true) - - // use a linear layout manager - layoutManager = viewManager - - // specify an viewAdapter (see also next example) - adapter = viewAdapter - } - - PlayerStore.instance.isQueueUpdated.observeForever(queueObserver) - - return root - } - - override fun onDestroyView() { - PlayerStore.instance.isQueueUpdated.removeObserver(queueObserver) - super.onDestroyView() - } - - companion object { - @JvmStatic - fun newInstance() = QueueFragment() - } -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/CooldownCalculator.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/CooldownCalculator.kt deleted file mode 100644 index 64175fe..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/CooldownCalculator.kt +++ /dev/null @@ -1,69 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.songs.request - -import kotlin.math.exp -import kotlin.math.max - -/* -//PHP cooldown calculator - -function pretty_cooldown($lp, $lr, $rc) { - $delay = delay($rc); - $now = time(); - $cd = intval(max($lp + $delay - $now, $lr + $delay - $now)); - if ($cd <= 0) - return "Request"; - $days = intdiv_1($cd, 86400); - $cd = $cd % 86400; - $hours = intdiv_1($cd, 3600); - $cd = $cd % 3600; - $minutes = intdiv_1($cd, 60); - $seconds = $cd % 60; - if ($days > 0) - return "Requestable in ".$days."d".$hours."h"; - else if ($hours > 0) - return "Requestable in ".$hours."h".$minutes."m"; - else if ($minutes > 0) - return "Requestable in ".$minutes."m".$seconds."s"; - return "Request"; -} -function requestable($lastplayed, $requests) { - $delay = delay($requests); - return (time() - $lastplayed) > $delay; -} -function delay($priority) { - // priority is 30 max - if ($priority > 30) - $priority = 30; - // between 0 and 7 return magic - if ($priority >= 0 and $priority <= 7) - $cd = -11057 * $priority * $priority + 172954 * $priority + 81720; - // if above that, return magic crazy numbers - else - $cd = (int) (599955 * exp(0.0372 * $priority) + 0.5); - return $cd / 2; -} - */ - -// this function implements the magic delay used on R/a/dio website: -// https://github.com/R-a-dio/site/blob/develop/app/start/global.php#L125 -// (Seriously guys, what were you thinking with these crazy magic numbers...) -fun delay(rawPriority: Int) : Int { - val priority = if (rawPriority > 30) 30 else rawPriority - val coolDown : Int = - if (priority in 0..7) - -11057 * priority * priority + 172954 * priority + 81720 - else - (599955 * exp(0.0372 * (priority.toDouble()) + 0.5)).toInt() - return coolDown/2 -} - -// I tweaked this to report in a single point whether the song is requestable or not -fun coolDown(lastPlayed: Int?, lastRequest: Int?, requestsNbr: Int?) : Long { - if (requestsNbr == null || lastPlayed == null || lastRequest == null) - return Long.MAX_VALUE // maximum positive value : the song won't be requestable - - val delay = delay(requestsNbr) - val now = (System.currentTimeMillis() / 1000) - return max(lastPlayed, lastRequest) + delay - now - // if coolDown < 0, the song is requestable. -} diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/FavoritesFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/FavoritesFragment.kt deleted file mode 100644 index 2631a7b..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/FavoritesFragment.kt +++ /dev/null @@ -1,132 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.songs.request - -import android.os.Build -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.SearchView -import android.widget.TextView -import androidx.appcompat.widget.AppCompatButton -import androidx.fragment.app.Fragment -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import fr.forum_thalie.tsumugi.* - - -class FavoritesFragment : Fragment() { - - private lateinit var recyclerView: RecyclerView - private lateinit var viewAdapter: RecyclerView.Adapter<*> - private lateinit var viewManager: RecyclerView.LayoutManager - private lateinit var searchView: SearchView - private lateinit var root: View - private lateinit var recyclerSwipe: SwipeRefreshLayout - - private val favoritesSongObserver : Observer = Observer { - viewAdapter.notifyDataSetChanged() - createView(isCallback = true) // force-re-create the view, but do not call again the initFavorites (avoid callback loop) - recyclerSwipe.isRefreshing = false // disable refreshing animation. Needs to be done manually... - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - super.onCreateView(inflater, container, savedInstanceState) - root = inflater.inflate(R.layout.fragment_request, container, false) - - return createView() - } - - private fun createView(isCallback: Boolean = false) : View? - { - - viewAdapter = RequestSongAdapter(Requestor.instance.favoritesSongArray) - - val listener : SearchView.OnQueryTextListener = object : SearchView.OnQueryTextListener{ - override fun onQueryTextSubmit(query: String?): Boolean { - // do nothing - return true - } - override fun onQueryTextChange(newText: String?): Boolean { - (viewAdapter as RequestSongAdapter).filter(newText ?: "") - return true - } - } - - searchView = root.findViewById(R.id.searchBox) - searchView.queryHint = "Search filter..." - searchView.setOnQueryTextListener(listener) - viewManager = LinearLayoutManager(context) - recyclerView = root.findViewById(R.id.request_recycler).apply { - // use this setting to improve performance if you know that changes - // in content do not change the layout size of the RecyclerView - setHasFixedSize(true) - - // use a linear layout manager - layoutManager = viewManager - - // specify an viewAdapter (see also next example) - adapter = viewAdapter - } - - val noUserNameText : TextView = root.findViewById(R.id.noUserNameText) - - recyclerSwipe = root.findViewById(R.id.recyclerSwipe) as SwipeRefreshLayout - recyclerSwipe.setOnRefreshListener { - val userName1 = preferenceStore.getString("userName", null) - Log.d(tag,"userName = $userName1") - if (userName1 != null && !userName1.isBlank()) - { - noUserNameText.visibility = View.GONE - Requestor.instance.initFavorites() - } else { - noUserNameText.visibility = View.VISIBLE - recyclerSwipe.isRefreshing = false - } - } - - - val userName1 = preferenceStore.getString("userName", null) - Log.d(tag,"userName = $userName1") - if (userName1 != null && !userName1.isBlank()) - { - noUserNameText.visibility = View.GONE - if (!isCallback) // avoid callback loop if called from the Observer. - Requestor.instance.initFavorites() - } else { - noUserNameText.visibility = View.VISIBLE - recyclerSwipe.isRefreshing = false - } - - val raFButton : AppCompatButton = root.findViewById(R.id.ra_f_button) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) // for API21+ Material Design makes ripples on the button. - raFButton.supportBackgroundTintList = colorGreenList - else // But on API20- no Material Design support, so we add some more color when clicked - raFButton.supportBackgroundTintList = colorGreenListCompat - raFButton.isEnabled = true - raFButton.isClickable = true - raFButton.setOnClickListener { - val s = Requestor.instance.raF() - Requestor.instance.snackBarText.value = "" - Requestor.instance.addRequestMeta = "Request: ${s.artist.value} - ${s.title.value}\n" - Requestor.instance.request(s.id) - } - raFButton.visibility = View.VISIBLE - - Requestor.instance.isFavoritesUpdated.observe(viewLifecycleOwner, favoritesSongObserver) - return root - } - - - companion object { - @JvmStatic - fun newInstance() = FavoritesFragment() - } -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestFragment.kt deleted file mode 100644 index fa19627..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestFragment.kt +++ /dev/null @@ -1,81 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.songs.request - -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.SearchView -import androidx.fragment.app.Fragment -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import fr.forum_thalie.tsumugi.R - -class RequestFragment : Fragment() { - - private lateinit var recyclerView: RecyclerView - private lateinit var viewAdapter: RecyclerView.Adapter<*> - private lateinit var viewManager: RecyclerView.LayoutManager - private lateinit var searchView: SearchView - - private val listener : SearchView.OnQueryTextListener = object : SearchView.OnQueryTextListener{ - override fun onQueryTextSubmit(query: String?): Boolean { - if (query == null || query.isEmpty()) - Requestor.instance.snackBarText.value = "Field is empty, no search possible." - else - Requestor.instance.search(query) - return true - } - override fun onQueryTextChange(newText: String?): Boolean { - if (newText == "") - { - Requestor.instance.reset() - viewAdapter.notifyDataSetChanged() // this is to remove the "Load more" button - } - return true - } - } - - private val requestSongObserver = Observer { - Log.d(tag, "request song list changed") - viewAdapter.notifyDataSetChanged() - } - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - // Inflate the layout for this fragment - val root = inflater.inflate(R.layout.fragment_request, container, false) - - val recyclerSwipe = root.findViewById(R.id.recyclerSwipe) as SwipeRefreshLayout - recyclerSwipe.isEnabled = false // don't need to pull-to-refresh for Request - - searchView = root.findViewById(R.id.searchBox) - searchView.setOnQueryTextListener(listener) - - viewManager = LinearLayoutManager(context) - viewAdapter = RequestSongAdapter(Requestor.instance.requestSongArray) - - recyclerView = root.findViewById(R.id.request_recycler).apply { - // use this setting to improve performance if you know that changes - // in content do not change the layout size of the RecyclerView - setHasFixedSize(true) - - // use a linear layout manager - layoutManager = viewManager - - // specify an viewAdapter (see also next example) - adapter = viewAdapter - } - Requestor.instance.isRequestResultUpdated.observe(viewLifecycleOwner, requestSongObserver) - return root - } - - companion object { - @JvmStatic - fun newInstance() = RequestFragment() - } -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestResponse.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestResponse.kt deleted file mode 100644 index a4c1e73..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestResponse.kt +++ /dev/null @@ -1,42 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.songs.request - -import fr.forum_thalie.tsumugi.playerstore.Song -import org.json.JSONObject - -class RequestResponse(jsonResponse: JSONObject) { - //val total: Int = jsonResponse.getInt("total") - //val perPage: Int = jsonResponse.getInt("per_page") // should stay 20 but in any case... - val currentPage: Int = jsonResponse.getInt("current_page") - val lastPage: Int = jsonResponse.getInt("last_page") - //val fromNbr: Int = jsonResponse.getInt("from") - //val toNbr: Int = jsonResponse.getInt("to") - var songs : ArrayList = ArrayList() - - init { - val songList = jsonResponse.getJSONArray("data") - for (i in 0 until songList.length()) - { - - val title = (songList[i] as JSONObject).getString("title") - val artist = (songList[i] as JSONObject).getString("artist") - val id = (songList[i] as JSONObject).getInt("id") - - val s = Song("", id) - s.title.value = title - s.artist.value = artist - s.isRequestable = (songList[i] as JSONObject).getBoolean("requestable") - // TODO add the time before being requestable. - songs.add(s) - } - } - - override fun toString(): String { - var s = "" - for (i in 0 until songs.size) - { - s += (songs[i].artist.value + " - " + songs[i].title.value + " | ") - } - return s - } - -} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestSongAdapter.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestSongAdapter.kt deleted file mode 100644 index 6f72f8a..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/RequestSongAdapter.kt +++ /dev/null @@ -1,148 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.songs.request - -import android.annotation.SuppressLint -import android.os.Build -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.ViewGroup -import android.widget.TextView -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.widget.TextViewCompat -import androidx.recyclerview.widget.RecyclerView -import fr.forum_thalie.tsumugi.* -import fr.forum_thalie.tsumugi.playerstore.Song -import kotlinx.android.synthetic.main.request_song_view.view.* -import android.view.View -import kotlinx.android.synthetic.main.button_load_more.view.* -import android.R.attr.name -import android.text.method.TextKeyListener.clear -import android.util.Log -import java.util.* -import kotlin.collections.ArrayList - - -class RequestSongAdapter(private val dataSet: ArrayList - /*, - context: Context, - resource: Int, - objects: Array*/ -) : RecyclerView.Adapter() /*ArrayAdapter(context, resource, objects)*/ { - - private val viewTypeCell = 1 // normal cell with song and request button - private val viewTypeFooter = 2 // the bottom cell should be the "load more" button whenever needed - - // Provide a reference to the views for each data item - // Complex data items may need more than one view per item, and - // you provide access to all the views for a data item in a view holder. - // Each data item is just a string in this case that is shown in a TextView. - class MyViewHolder(view: ConstraintLayout) : RecyclerView.ViewHolder(view) - - - // Create new views (invoked by the layout manager) - override fun onCreateViewHolder(parent: ViewGroup, - viewType: Int): MyViewHolder { - // create a new view - - val view = - if (viewType == viewTypeCell) - LayoutInflater.from(parent.context).inflate(R.layout.request_song_view, parent, false) as ConstraintLayout - else - LayoutInflater.from(parent.context).inflate(R.layout.button_load_more, parent, false) as ConstraintLayout - - // set the view's size, margins, paddings and layout parameters - //... - return MyViewHolder(view) - } - - // Replace the contents of a view (invoked by the layout manager) - @SuppressLint("SetTextI18n") - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - - if (itemCount <= 1) - { - // in any case, if there's nothing, don't display the loadMore button!! - holder.itemView.loadMoreButton.visibility = View.GONE - return - } - - if (holder.itemViewType == viewTypeFooter) - { - if (Requestor.instance.isLoadMoreVisible) - holder.itemView.loadMoreButton.visibility = View.VISIBLE - else - holder.itemView.loadMoreButton.visibility = View.GONE - holder.itemView.loadMoreButton.text = "Load more results" - holder.itemView.loadMoreButton.setOnClickListener{ - Requestor.instance.loadMore() - } - return - } - - val artist = holder.itemView.findViewById(R.id.request_song_artist) - val title = holder.itemView.findViewById(R.id.request_song_title) - val button = holder.itemView.request_button - - if (dataSet[position].isRequestable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) // for API21+ Material Design makes ripples on the button. - button.supportBackgroundTintList = colorGreenList - else // But on API20- no Material Design support, so we add some more color when clicked - button.supportBackgroundTintList = colorGreenListCompat - button.isEnabled = true - button.isClickable = true - button.setOnClickListener { - Requestor.instance.request(dataSet[position].id) - } - } else { - button.supportBackgroundTintList = colorRedList - button.isEnabled = false - button.isClickable = false - } - - TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration( - button,2, 24, 2, TypedValue.COMPLEX_UNIT_SP) - artist.text = dataSet[position].artist.value - title.text = dataSet[position].title.value - } - - // Return the size of your dataset (invoked by the layout manager) - override fun getItemCount() = dataSet.size + 1 // add 1 for the "Load more results" button - - override fun getItemViewType(position: Int): Int { - return if (position == dataSet.size) viewTypeFooter else viewTypeCell - } - - /* - override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - // create a new view - val view = LayoutInflater.from(parent.context) - .inflate(R.layout.song_view, parent, false) as ConstraintLayout - } - */ - - // a filtering function. As naive as it could be, but it should work. - private val dataSetOrig = ArrayList() - init { - dataSetOrig.addAll(dataSet) - } - - fun filter(entry: String) { - var text = entry - dataSet.clear() - Log.d(tag, "entering filter") - if (text.isEmpty()) { - dataSet.addAll(dataSetOrig) - } else { - text = text.toLowerCase(locale = Locale.ROOT) - for (item in dataSetOrig) { - Log.d(tag, "$text, ${item.artist.value!!.toLowerCase(locale = Locale.ROOT)}, ${item.title.value!!.toLowerCase(locale = Locale.ROOT)}") - if (item.artist.value!!.toLowerCase(locale = Locale.ROOT).contains(text) || - item.title.value!!.toLowerCase(locale = Locale.ROOT).contains(text)) { - dataSet.add(item) - } - } - } - notifyDataSetChanged() - } - -} - diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/Requestor.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/Requestor.kt deleted file mode 100644 index a9259b2..0000000 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/songs/request/Requestor.kt +++ /dev/null @@ -1,301 +0,0 @@ -package fr.forum_thalie.tsumugi.ui.songs.request - -import android.util.Log -import androidx.lifecycle.MutableLiveData -import fr.forum_thalie.tsumugi.ActionOnError -import fr.forum_thalie.tsumugi.Async -import fr.forum_thalie.tsumugi.playerstore.Song -import fr.forum_thalie.tsumugi.preferenceStore -import fr.forum_thalie.tsumugi.tag -import org.json.JSONArray -import org.json.JSONException -import org.json.JSONObject -import java.io.BufferedReader -import java.io.IOException -import java.io.InputStreamReader -import java.net.CookieHandler -import java.net.CookieManager -import java.net.MalformedURLException -import java.net.URL -import java.util.* -import java.util.regex.Pattern - -import javax.net.ssl.HttpsURLConnection -import kotlin.collections.ArrayList -import kotlin.random.Random - -/** - * Requests a song via the website's API - * - * We scrape the website for a CSRF token and POST it to /request/ endpoint with - * the song id - * - * Created by Kethsar on 1/2/2017. - * Converted to Kotlin and adapted by Yattoz on 05 Nov. 2019 - */ - -class Requestor { - var addRequestMeta: String = "" - private val cookieManager: CookieManager = CookieManager() - private val requestUrl = "https://r-a-d.io/request/%1\$d" - private val searchUrl = "https://r-a-d.io/api/search/%1s?page=%2\$d" - private val favoritesUrl = "https://r-a-d.io/faves/%1s?dl=true" - private val songThresholdStep = 50 - private var songThreshold = songThresholdStep - private var localQuery = "" - - private var token: String? = null - val snackBarText : MutableLiveData = MutableLiveData() - private var responseArray : ArrayList = ArrayList() - val requestSongArray : ArrayList = ArrayList() - val favoritesSongArray : ArrayList = ArrayList() - val isRequestResultUpdated : MutableLiveData = MutableLiveData() - val isFavoritesUpdated : MutableLiveData = MutableLiveData() - var isLoadMoreVisible: Boolean = false - - - init { - snackBarText.value = "" - isRequestResultUpdated.value = false - isFavoritesUpdated.value = false - isLoadMoreVisible = false - } - - fun initFavorites(userName : String? = preferenceStore.getString("userName", null)){ - Log.d(tag, "initializing favorites") - favoritesSongArray.clear() - if (userName == null) - { - // Display is done by default in the XML. - Log.d(tag, "no user name set for favorites") - isFavoritesUpdated.value = true - return - } - val favoritesUserUrl = String.format(Locale.getDefault(), favoritesUrl, userName) - val scrapeFavorites : (Any?) -> JSONArray = { - JSONArray(URL(favoritesUserUrl).readText()) - } - val postFavorites : (Any?) -> Unit = { - val res = it as JSONArray - for (i in 0 until (res).length()) - { - val item = res.getJSONObject(i) - val artistTitle = item.getString("meta") - val id : Int? = if (item.isNull("tracks_id")) - null - else - item.getInt("tracks_id") - - val lastRequested : Int? = if (item.isNull("lastrequested")) null else item.getInt("lastrequested") - val lastPlayed : Int? = if (item.isNull("lastplayed")) null else item.getInt("lastplayed") - val requestCount : Int? = if (item.isNull("requestcount")) null else item.getInt("requestcount") - val isRequestable = (coolDown(lastPlayed, lastRequested, requestCount) < 0) - //Log.d(tag, "val : $id") - favoritesSongArray.add(Song(artistTitle, id ?: 0, isRequestable)) - } - Log.d(tag, "favorites : $favoritesSongArray") - isFavoritesUpdated.value = true - } - Async(scrapeFavorites, postFavorites, ActionOnError.NOTIFY) - } - - fun search(query: String) - { - responseArray.clear() - requestSongArray.clear() - localQuery = query - searchPage(query, 1) // the searchPage function is recursive to get all pages. - } - - private fun searchPage(query: String, pageNumber : Int) - { - val searchURL = String.format(Locale.getDefault(), searchUrl, query, pageNumber) - val scrape : (Any?) -> JSONObject = { - val res = URL(searchURL).readText() - val json = JSONObject(res) - json - } - val post : (Any?) -> Unit = { - val response = RequestResponse(it as JSONObject) - - responseArray.add(response) - for (i in 0 until response.songs.size) - { - requestSongArray.add(response.songs[i]) - } - isRequestResultUpdated.value = true - if (requestSongArray.size >= songThreshold) - { - isLoadMoreVisible = true - - } else { - if (response.currentPage < response.lastPage) - searchPage(query, pageNumber + 1) // recursive call to get the next page - else - finishSearch() - } - - } - Async(scrape, post, ActionOnError.NOTIFY) - } - - private fun finishSearch() - { - isLoadMoreVisible = false - } - - fun reset() - { - requestSongArray.clear() - responseArray.clear() - isRequestResultUpdated.value = false - songThreshold = songThresholdStep - } - - fun loadMore() - { - songThreshold += songThresholdStep - searchPage(localQuery, responseArray.last().currentPage + 1) - } - - - /** - * Scrape the website for the CSRF token required for requesting - * scrapeToken and postToken are the two lambas run by the Async() class. - */ - - private val scrapeToken : (Any?) -> Any? = { - val radioSearchUrl = "https://r-a-d.io/search" - var searchURL: URL? = null - var retVal: String? = null - var reader: BufferedReader? = null - - CookieHandler.setDefault(cookieManager) // it[0] ?? - - try { - searchURL = URL(radioSearchUrl) - } catch (e: MalformedURLException) { - e.printStackTrace() - } - - try { - reader = BufferedReader(InputStreamReader(searchURL!!.openStream(), "UTF-8")) - var line: String? - line = reader.readLine() - while (line != null) - { - line = line.trim { it <= ' ' } - val p = Pattern.compile("value=\"(\\w+)\"") - val m = p.matcher(line) - - if (line.startsWith(" (Unit) = { - token = it as String? - } - - /** - * Request the song with the CSRF token that was scraped - */ - private val requestSong: (Any?) -> Any? = { - val reqString = it as String - var response = "" - - try { - val reqURL = URL(reqString) - val conn = reqURL.openConnection() as HttpsURLConnection - val tokenObject = JSONObject() - - tokenObject.put("_token", token) - val requestBytes = tokenObject.toString().toByteArray() - - conn.requestMethod = "POST" - conn.doOutput = true - conn.doInput = true - conn.setChunkedStreamingMode(0) - conn.setRequestProperty("Content-Type", "application/json") - - val os = conn.outputStream - os.write(requestBytes) - - val responseCode = conn.responseCode - - if (responseCode == HttpsURLConnection.HTTP_OK) { - var line: String? - val br = BufferedReader(InputStreamReader( - conn.inputStream)) - line = br.readLine() - while (line != null) { - response += line - line = br.readLine() - } - } else { - response += "" - } - } catch (ex: IOException) { - ex.printStackTrace() - } catch (ex: JSONException) { - ex.printStackTrace() - } - - response - } - - private val postSong : (Any?) -> (Unit) = { - val response = JSONObject(it as String) - val key = response.names()!!.get(0) as String - val value = response.getString(key) - - snackBarText.postValue(addRequestMeta + value) - } - - - fun request(songID: Int?) { - val requestSongUrl = String.format(requestUrl, songID!!) - if (token == null) { - Async(scrapeToken, postToken, ActionOnError.NOTIFY) - } - Async(requestSong, postSong, ActionOnError.NOTIFY, requestSongUrl) - } - - fun raF() : Song { - // request a random favorite song. HELL YEAH - val requestableSongArray = ArrayList() - for (i in 0 until favoritesSongArray.size) - { - if (favoritesSongArray[i].isRequestable && (favoritesSongArray[i].id ?: 0) > 0) - requestableSongArray.add(favoritesSongArray[i]) - } - return if (requestableSongArray.isNotEmpty()) { - val songNbr = Random(System.currentTimeMillis()).nextInt(1, requestableSongArray.size) - requestableSongArray[songNbr] - } else { - Song("No song requestable - ") - } - } - - companion object { - val instance by lazy { - Requestor() - } - } - -} diff --git a/app/src/main/res/drawable-anydpi-v24/lollipop_logo.xml b/app/src/main/res/drawable-anydpi-v24/lollipop_logo.xml deleted file mode 100644 index e95de7f..0000000 --- a/app/src/main/res/drawable-anydpi-v24/lollipop_logo.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable-anydpi/ic_chat_processing.xml b/app/src/main/res/drawable-anydpi/ic_chat_processing.xml deleted file mode 100644 index aac6443..0000000 --- a/app/src/main/res/drawable-anydpi/ic_chat_processing.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-anydpi/ic_open_in_browser.xml b/app/src/main/res/drawable-anydpi/ic_open_in_browser.xml deleted file mode 100644 index 6f81348..0000000 --- a/app/src/main/res/drawable-anydpi/ic_open_in_browser.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-hdpi/ic_chat_processing.png b/app/src/main/res/drawable-hdpi/ic_chat_processing.png deleted file mode 100644 index d1743c6..0000000 Binary files a/app/src/main/res/drawable-hdpi/ic_chat_processing.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_open_in_browser.png b/app/src/main/res/drawable-hdpi/ic_open_in_browser.png deleted file mode 100644 index 787c104..0000000 Binary files a/app/src/main/res/drawable-hdpi/ic_open_in_browser.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/lollipop_logo.png b/app/src/main/res/drawable-hdpi/lollipop_logo.png index 4016d46..f2a8921 100644 Binary files a/app/src/main/res/drawable-hdpi/lollipop_logo.png and b/app/src/main/res/drawable-hdpi/lollipop_logo.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_chat_processing.png b/app/src/main/res/drawable-mdpi/ic_chat_processing.png deleted file mode 100644 index c92ff3f..0000000 Binary files a/app/src/main/res/drawable-mdpi/ic_chat_processing.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_open_in_browser.png b/app/src/main/res/drawable-mdpi/ic_open_in_browser.png deleted file mode 100644 index b668f95..0000000 Binary files a/app/src/main/res/drawable-mdpi/ic_open_in_browser.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/lollipop_logo.png b/app/src/main/res/drawable-mdpi/lollipop_logo.png index 9d6e952..0f687a7 100644 Binary files a/app/src/main/res/drawable-mdpi/lollipop_logo.png and b/app/src/main/res/drawable-mdpi/lollipop_logo.png differ diff --git a/app/src/main/res/drawable-v23/launch_screen.xml b/app/src/main/res/drawable-v23/launch_screen.xml index 13b4f47..4fd97f2 100644 --- a/app/src/main/res/drawable-v23/launch_screen.xml +++ b/app/src/main/res/drawable-v23/launch_screen.xml @@ -1,11 +1,11 @@ - + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_radio_logo_round.xml b/app/src/main/res/drawable/ic_radio_logo_round.xml deleted file mode 100644 index 76263ae..0000000 --- a/app/src/main/res/drawable/ic_radio_logo_round.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_radiologo.xml b/app/src/main/res/drawable/ic_radiologo.xml deleted file mode 100644 index 7a21266..0000000 --- a/app/src/main/res/drawable/ic_radiologo.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/ic_tsumugi_lineart.xml b/app/src/main/res/drawable/ic_tsumugi_lineart.xml new file mode 100644 index 0000000..4fcc31c --- /dev/null +++ b/app/src/main/res/drawable/ic_tsumugi_lineart.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/logo_roundsquare.png b/app/src/main/res/drawable/logo_roundsquare.png new file mode 100644 index 0000000..fd5e6a3 Binary files /dev/null and b/app/src/main/res/drawable/logo_roundsquare.png differ diff --git a/app/src/main/res/drawable/normal_logo.png b/app/src/main/res/drawable/normal_logo.png deleted file mode 100644 index 9a286c8..0000000 Binary files a/app/src/main/res/drawable/normal_logo.png and /dev/null differ diff --git a/app/src/main/res/drawable/seek_bar_progress.xml b/app/src/main/res/drawable/seek_bar_progress.xml deleted file mode 100644 index ab7b54d..0000000 --- a/app/src/main/res/drawable/seek_bar_progress.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/seek_bar_thumb.xml b/app/src/main/res/drawable/seek_bar_thumb.xml deleted file mode 100644 index 0a623c6..0000000 --- a/app/src/main/res/drawable/seek_bar_thumb.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7006b70..be58590 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -37,15 +37,17 @@ app:layout_constraintTop_toTopOf="parent" > + + android:contentDescription="@string/r_a_dio_icon" + android:visibility="gone"/> + app:layout_constraintTop_toBottomOf="@id/streamerPicture" + android:visibility="gone"/> + app:layout_constraintTop_toBottomOf="@id/streamerName" + android:visibility="gone" + /> + + tools:layout_editor_absoluteX="0dp" + android:visibility="gone"/> + + app:layout_constraintTop_toBottomOf="@id/progressBar" + android:visibility="gone"/> + + app:layout_constraintTop_toBottomOf="@id/progressBar" + android:visibility="gone"/> diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index d97db44..ddcba1b 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -16,9 +16,5 @@ android:icon="@drawable/ic_newspaper" android:title="@string/title_news"/> - diff --git a/app/src/main/res/menu/toolbar_menu.xml b/app/src/main/res/menu/toolbar_menu.xml index 2c3b164..7f2d091 100644 --- a/app/src/main/res/menu/toolbar_menu.xml +++ b/app/src/main/res/menu/toolbar_menu.xml @@ -14,11 +14,12 @@ android:icon="@drawable/ic_alarm" app:showAsAction="ifRoom"/> - +