Added F-Droid FOSS flavor

This commit is contained in:
Prathamesh More 2022-06-14 23:05:59 +05:30
parent bc39d3a462
commit 2a5e6d7756
42 changed files with 243 additions and 360 deletions

View file

@ -19,20 +19,17 @@ import androidx.preference.PreferenceManager
import cat.ereza.customactivityoncrash.config.CaocConfig
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID
import code.name.monkey.retromusic.activities.ErrorActivity
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.billing.BillingManager
import code.name.monkey.retromusic.helper.WallpaperAccentManager
import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.PurchaseInfo
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
class App : Application() {
lateinit var billingProcessor: BillingProcessor
lateinit var billingManager: BillingManager
private val wallpaperAccentManager = WallpaperAccentManager(this)
override fun onCreate() {
@ -55,33 +52,18 @@ class App : Application() {
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(this).initDynamicShortcuts()
// automatically restores purchases
billingProcessor = BillingProcessor(
this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY,
object : BillingProcessor.IBillingHandler {
override fun onProductPurchased(productId: String, details: PurchaseInfo?) {}
override fun onPurchaseHistoryRestored() {
showToast(R.string.restored_previous_purchase_please_restart)
}
override fun onBillingError(errorCode: Int, error: Throwable?) {}
override fun onBillingInitialized() {}
})
// setting Error activity
CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java)
.restartActivity(MainActivity::class.java).apply()
// Set Default values for now playing preferences
// This will reduce start time for now playing settings fragment as Preference listener of AbsSlidingMusicPanelActivity won't be called
// This will reduce startup time for now playing settings fragment as Preference listener of AbsSlidingMusicPanelActivity won't be called
PreferenceManager.setDefaultValues(this, R.xml.pref_now_playing_screen, false)
}
override fun onTerminate() {
super.onTerminate()
billingProcessor.release()
billingManager.release()
wallpaperAccentManager.release()
}
@ -93,9 +75,7 @@ class App : Application() {
}
fun isProVersion(): Boolean {
return BuildConfig.DEBUG || instance?.billingProcessor!!.isPurchased(
PRO_VERSION_PRODUCT_ID
)
return BuildConfig.DEBUG || instance?.billingManager!!.isProVersion
}
}
}

View file

@ -1,119 +0,0 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package code.name.monkey.retromusic.activities
import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.databinding.ActivityProVersionBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setLightStatusBar
import code.name.monkey.retromusic.extensions.setStatusBarColor
import code.name.monkey.retromusic.extensions.showToast
import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.PurchaseInfo
class PurchaseActivity : AbsThemeActivity(), BillingProcessor.IBillingHandler {
private lateinit var binding: ActivityProVersionBinding
private lateinit var billingProcessor: BillingProcessor
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityProVersionBinding.inflate(layoutInflater)
setContentView(binding.root)
setStatusBarColor(Color.TRANSPARENT)
setLightStatusBar(false)
binding.toolbar.navigationIcon?.setTint(Color.WHITE)
binding.toolbar.setNavigationOnClickListener { onBackPressed() }
binding.restoreButton.isEnabled = false
binding.purchaseButton.isEnabled = false
billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
MaterialUtil.setTint(binding.purchaseButton, true)
binding.restoreButton.setOnClickListener {
restorePurchase()
}
binding.purchaseButton.setOnClickListener {
billingProcessor.purchase(this@PurchaseActivity, PRO_VERSION_PRODUCT_ID)
}
binding.bannerContainer.backgroundTintList =
ColorStateList.valueOf(accentColor())
}
private fun restorePurchase() {
showToast(R.string.restoring_purchase)
billingProcessor.loadOwnedPurchasesFromGoogleAsync(object :
BillingProcessor.IPurchasesResponseListener {
override fun onPurchasesSuccess() {
onPurchaseHistoryRestored()
}
override fun onPurchasesError() {
showToast(R.string.could_not_restore_purchase)
}
})
}
override fun onProductPurchased(productId: String, details: PurchaseInfo?) {
showToast(R.string.thank_you)
setResult(RESULT_OK)
}
override fun onPurchaseHistoryRestored() {
if (App.isProVersion()) {
showToast(R.string.restored_previous_purchase_please_restart)
setResult(RESULT_OK)
} else {
showToast(R.string.no_purchase_found)
}
}
override fun onBillingError(errorCode: Int, error: Throwable?) {
Log.e(TAG, "Billing error: code = $errorCode", error)
}
override fun onBillingInitialized() {
binding.restoreButton.isEnabled = true
binding.purchaseButton.isEnabled = true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> finish()
}
return super.onOptionsItemSelected(item)
}
override fun onDestroy() {
billingProcessor.release()
super.onDestroy()
}
companion object {
private const val TAG: String = "PurchaseActivity"
}
}

View file

@ -14,41 +14,23 @@
*/
package code.name.monkey.retromusic.activities
import android.graphics.Paint
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.databinding.ActivityDonationBinding
import code.name.monkey.retromusic.databinding.ItemDonationOptionBinding
import code.name.monkey.retromusic.extensions.*
import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.PurchaseInfo
import com.anjlab.android.iab.v3.SkuDetails
import code.name.monkey.retromusic.extensions.setStatusBarColorAuto
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.surfaceColor
class SupportDevelopmentActivity : AbsThemeActivity(), BillingProcessor.IBillingHandler {
class SupportDevelopmentActivity : AbsThemeActivity() {
lateinit var binding: ActivityDonationBinding
companion object {
val TAG: String = SupportDevelopmentActivity::class.java.simpleName
const val DONATION_PRODUCT_IDS = R.array.donation_ids
}
var billingProcessor: BillingProcessor? = null
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
@ -57,11 +39,6 @@ class SupportDevelopmentActivity : AbsThemeActivity(), BillingProcessor.IBilling
return super.onOptionsItemSelected(item)
}
fun donate(i: Int) {
val ids = resources.getStringArray(DONATION_PRODUCT_IDS)
billingProcessor?.purchase(this, ids[i])
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDonationBinding.inflate(layoutInflater)
@ -72,148 +49,11 @@ class SupportDevelopmentActivity : AbsThemeActivity(), BillingProcessor.IBilling
setupToolbar()
billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
TintHelper.setTint(binding.progress, accentColor())
binding.donation.setTextColor(accentColor())
}
private fun setupToolbar() {
val toolbarColor = surfaceColor()
binding.toolbar.setBackgroundColor(toolbarColor)
binding.toolbar.setBackgroundColor(surfaceColor())
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
setSupportActionBar(binding.toolbar)
}
override fun onBillingInitialized() {
loadSkuDetails()
}
private fun loadSkuDetails() {
binding.progressContainer.isVisible = true
binding.recyclerView.isVisible = false
val ids = resources.getStringArray(DONATION_PRODUCT_IDS)
billingProcessor!!.getPurchaseListingDetailsAsync(
ArrayList(listOf(*ids)),
object : BillingProcessor.ISkuDetailsResponseListener {
override fun onSkuDetailsResponse(skuDetails: MutableList<SkuDetails>?) {
if (skuDetails == null || skuDetails.isEmpty()) {
binding.progressContainer.isVisible = false
return
}
binding.progressContainer.isVisible = false
binding.recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(this@SupportDevelopmentActivity, 2)
adapter = SkuDetailsAdapter(this@SupportDevelopmentActivity, skuDetails)
isVisible = true
}
}
override fun onSkuDetailsError(error: String?) {
Log.e(TAG, error.toString())
}
})
}
override fun onProductPurchased(productId: String, details: PurchaseInfo?) {
// loadSkuDetails();
showToast(R.string.thank_you)
}
override fun onBillingError(errorCode: Int, error: Throwable?) {
Log.e(TAG, "Billing error: code = $errorCode", error)
}
override fun onPurchaseHistoryRestored() {
// loadSkuDetails();
showToast(R.string.restored_previous_purchases)
}
override fun onDestroy() {
billingProcessor?.release()
super.onDestroy()
}
}
class SkuDetailsAdapter(
private var donationsDialog: SupportDevelopmentActivity,
objects: List<SkuDetails>,
) : RecyclerView.Adapter<SkuDetailsAdapter.ViewHolder>() {
private var skuDetailsList: List<SkuDetails> = ArrayList()
init {
skuDetailsList = objects
}
private fun getIcon(position: Int): Int {
return when (position) {
0 -> R.drawable.ic_cookie
1 -> R.drawable.ic_take_away
2 -> R.drawable.ic_take_away_coffe
3 -> R.drawable.ic_beer
4 -> R.drawable.ic_fast_food_meal
5 -> R.drawable.ic_popcorn
6 -> R.drawable.ic_card_giftcard
7 -> R.drawable.ic_food_croissant
else -> R.drawable.ic_card_giftcard
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder {
return ViewHolder(
ItemDonationOptionBinding.inflate(
LayoutInflater.from(donationsDialog),
viewGroup,
false
)
)
}
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
val skuDetails = skuDetailsList[i]
with(viewHolder.binding) {
itemTitle.text = skuDetails.title.replace("(Retro Music Player MP3 Player)", "")
.trim { it <= ' ' }
itemText.text = skuDetails.description
itemText.isVisible = false
itemPrice.text = skuDetails.priceText
itemImage.setImageResource(getIcon(i))
}
val purchased = donationsDialog.billingProcessor!!.isPurchased(skuDetails.productId)
val titleTextColor = if (purchased) ATHUtil.resolveColor(
donationsDialog,
android.R.attr.textColorHint
) else donationsDialog.textColorPrimary()
val contentTextColor =
if (purchased) titleTextColor else donationsDialog.textColorSecondary()
with(viewHolder.binding) {
itemTitle.setTextColor(titleTextColor)
itemText.setTextColor(contentTextColor)
itemPrice.setTextColor(titleTextColor)
strikeThrough(itemTitle, purchased)
strikeThrough(itemText, purchased)
strikeThrough(itemPrice, purchased)
}
viewHolder.itemView.isEnabled = !purchased
viewHolder.itemView.setOnClickListener { donationsDialog.donate(i) }
}
override fun getItemCount(): Int {
return skuDetailsList.size
}
class ViewHolder(val binding: ItemDonationOptionBinding) : RecyclerView.ViewHolder(binding.root)
companion object {
private fun strikeThrough(textView: TextView, strikeThrough: Boolean) {
textView.paintFlags =
if (strikeThrough) textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
else textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}
}
}

View file

@ -1,93 +0,0 @@
package code.name.monkey.retromusic.activities.base
import code.name.monkey.retromusic.cast.RetroSessionManagerListener
import code.name.monkey.retromusic.cast.RetroWebServer
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import org.koin.android.ext.android.inject
abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
private var mCastSession: CastSession? = null
private val sessionManager by lazy {
CastContext.getSharedInstance(this).sessionManager
}
private val webServer: RetroWebServer by inject()
private val playServicesAvailable: Boolean by lazy {
try {
GoogleApiAvailability
.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS
} catch (e: Exception) {
false
}
}
private val sessionManagerListener by lazy {
object : RetroSessionManagerListener {
override fun onSessionStarting(castSession: CastSession) {
webServer.start()
}
override fun onSessionStarted(castSession: CastSession, p1: String) {
invalidateOptionsMenu()
mCastSession = castSession
MusicPlayerRemote.switchToRemotePlayback(castSession)
}
override fun onSessionEnded(castSession: CastSession, p1: Int) {
invalidateOptionsMenu()
if (mCastSession == castSession) {
mCastSession = null
}
MusicPlayerRemote.switchToLocalPlayback()
webServer.stop()
}
override fun onSessionResumed(castSession: CastSession, p1: Boolean) {
invalidateOptionsMenu()
mCastSession = castSession
webServer.start()
MusicPlayerRemote.switchToRemotePlayback(castSession)
}
override fun onSessionSuspended(castSession: CastSession, p1: Int) {
invalidateOptionsMenu()
if (mCastSession == castSession) {
mCastSession = null
}
MusicPlayerRemote.switchToLocalPlayback()
webServer.stop()
}
}
}
override fun onResume() {
super.onResume()
if (playServicesAvailable) {
sessionManager.addSessionManagerListener(
sessionManagerListener,
CastSession::class.java
)
if (mCastSession == null) {
mCastSession = sessionManager.currentCastSession
}
}
}
override fun onPause() {
super.onPause()
if (playServicesAvailable) {
sessionManager.removeSessionManagerListener(
sessionManagerListener,
CastSession::class.java
)
mCastSession = null
}
}
}

View file

@ -31,7 +31,6 @@ import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.maybeShowAnnoyingToasts
import code.name.monkey.retromusic.util.theme.getNightMode
import code.name.monkey.retromusic.util.theme.getThemeResValue
import com.google.android.play.core.splitcompat.SplitCompat
import java.util.*
abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
@ -105,6 +104,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
Locale.forLanguageTag(code)
}
super.attachBaseContext(LanguageContextWrapper.wrap(newBase, locale))
SplitCompat.install(this)
installSplitCompat()
}
}

View file

@ -1,50 +0,0 @@
package code.name.monkey.retromusic.cast
import androidx.core.net.toUri
import code.name.monkey.retromusic.cast.RetroWebServer.Companion.MIME_TYPE_AUDIO
import code.name.monkey.retromusic.cast.RetroWebServer.Companion.PART_COVER_ART
import code.name.monkey.retromusic.cast.RetroWebServer.Companion.PART_SONG
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaInfo.STREAM_TYPE_BUFFERED
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.cast.MediaMetadata.*
import com.google.android.gms.common.images.WebImage
import java.net.MalformedURLException
import java.net.URL
object CastHelper {
private const val CAST_MUSIC_METADATA_ID = "metadata_id"
private const val CAST_MUSIC_METADATA_ALBUM_ID = "metadata_album_id"
private const val CAST_URL_PROTOCOL = "http"
fun Song.toMediaInfo(): MediaInfo? {
val song = this
val baseUrl: URL
try {
baseUrl = URL(CAST_URL_PROTOCOL, RetroUtil.getIpAddress(true), SERVER_PORT, "")
} catch (e: MalformedURLException) {
return null
}
val songUrl = "$baseUrl/$PART_SONG?id=${song.id}"
val albumArtUrl = "$baseUrl/$PART_COVER_ART?id=${song.albumId}"
val musicMetadata = MediaMetadata(MEDIA_TYPE_MUSIC_TRACK).apply {
putInt(CAST_MUSIC_METADATA_ID, song.id.toInt())
putInt(CAST_MUSIC_METADATA_ALBUM_ID, song.albumId.toInt())
putString(KEY_TITLE, song.title)
putString(KEY_ARTIST, song.artistName)
putString(KEY_ALBUM_TITLE, song.albumName)
putInt(KEY_TRACK_NUMBER, song.trackNumber)
addImage(WebImage(albumArtUrl.toUri()))
}
return MediaInfo.Builder(songUrl).apply {
setStreamType(STREAM_TYPE_BUFFERED)
setContentType(MIME_TYPE_AUDIO)
setMetadata(musicMetadata)
setStreamDuration(song.duration)
}.build()
}
}

View file

@ -1,43 +0,0 @@
@file:Suppress("unused")
package code.name.monkey.retromusic.cast
import android.content.Context
import code.name.monkey.retromusic.activities.MainActivity
import com.google.android.gms.cast.CastMediaControlIntent
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.SessionProvider
import com.google.android.gms.cast.framework.media.CastMediaOptions
import com.google.android.gms.cast.framework.media.MediaIntentReceiver
import com.google.android.gms.cast.framework.media.NotificationOptions
class CastOptionsProvider : OptionsProvider {
override fun getCastOptions(context: Context): CastOptions {
val buttonActions: MutableList<String> = ArrayList()
buttonActions.add(MediaIntentReceiver.ACTION_SKIP_PREV)
buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK)
buttonActions.add(MediaIntentReceiver.ACTION_SKIP_NEXT)
buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING)
val compatButtonActionsIndices = intArrayOf(1, 3)
val notificationOptions = NotificationOptions.Builder()
.setActions(buttonActions, compatButtonActionsIndices)
.setTargetActivityClassName(MainActivity::class.java.name)
.build()
val mediaOptions = CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.setExpandedControllerActivityClassName(MainActivity::class.java.name)
.build()
return CastOptions.Builder()
.setReceiverApplicationId(CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID)
.setCastMediaOptions(mediaOptions)
.build()
}
override fun getAdditionalSessionProviders(context: Context): MutableList<SessionProvider>? {
return null
}
}

View file

@ -1,14 +0,0 @@
package code.name.monkey.retromusic.cast
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
interface RetroSessionManagerListener : SessionManagerListener<CastSession> {
override fun onSessionResuming(p0: CastSession, p1: String) {}
override fun onSessionStartFailed(p0: CastSession, p1: Int) {}
override fun onSessionResumeFailed(p0: CastSession, p1: Int) {}
override fun onSessionEnding(castSession: CastSession) {}
}

View file

@ -1,127 +0,0 @@
package code.name.monkey.retromusic.cast
import android.content.Context
import code.name.monkey.retromusic.util.MusicUtil
import fi.iki.elonen.NanoHTTPD
import fi.iki.elonen.NanoHTTPD.Response.Status
import java.io.*
const val SERVER_PORT = 9090
class RetroWebServer(val context: Context) : NanoHTTPD(SERVER_PORT) {
companion object {
private const val MIME_TYPE_IMAGE = "image/jpg"
const val MIME_TYPE_AUDIO = "audio/mp3"
const val PART_COVER_ART = "coverart"
const val PART_SONG = "song"
const val PARAM_ID = "id"
}
override fun serve(session: IHTTPSession?): Response {
if (session?.uri?.contains(PART_COVER_ART) == true) {
val albumId = session.parameters?.get(PARAM_ID)?.get(0) ?: return errorResponse()
val albumArtUri = MusicUtil.getMediaStoreAlbumCoverUri(albumId.toLong())
val fis: InputStream?
try {
fis = context.contentResolver.openInputStream(albumArtUri)
} catch (e: FileNotFoundException) {
return errorResponse()
}
return newChunkedResponse(Status.OK, MIME_TYPE_IMAGE, fis)
} else if (session?.uri?.contains(PART_SONG) == true) {
val songId = session.parameters?.get(PARAM_ID)?.get(0) ?: return errorResponse()
val songUri = MusicUtil.getSongFileUri(songId.toLong())
val songPath = MusicUtil.getSongFilePath(context, songUri)
val song = File(songPath)
return serveFile(session.headers!!, song, MIME_TYPE_AUDIO)
}
return newFixedLengthResponse(Status.NOT_FOUND, MIME_PLAINTEXT, "Not Found")
}
private fun serveFile(
header: MutableMap<String, String>, file: File,
mime: String
): Response {
var res: Response
try {
// Support (simple) skipping:
var startFrom: Long = 0
var endAt: Long = -1
// The value of header range will be bytes=0-1024 something like this
// We get the value of from Bytes i.e. startFrom and toBytes i.e. endAt below
var range = header["range"]
if (range != null) {
if (range.startsWith("bytes=")) {
range = range.substring("bytes=".length)
val minus = range.indexOf('-')
try {
if (minus > 0) {
startFrom = range
.substring(0, minus).toLong()
endAt = range.substring(minus + 1).toLong()
}
} catch (ignored: NumberFormatException) {
}
}
}
// Chunked Response is used when serving audio file
// Change return code and add Content-Range header when skipping is
// requested
val fileLen = file.length()
if (range != null && startFrom >= 0) {
if (startFrom >= fileLen) {
res = newFixedLengthResponse(
Status.RANGE_NOT_SATISFIABLE,
MIME_PLAINTEXT, ""
)
res.addHeader("Content-Range", "bytes 0-0/$fileLen")
} else {
if (endAt < 0) {
endAt = fileLen - 1
}
var newLen = endAt - startFrom + 1
if (newLen < 0) {
newLen = 0
}
val dataLen = newLen
val fis: FileInputStream = object : FileInputStream(file) {
@Throws(IOException::class)
override fun available(): Int {
return dataLen.toInt()
}
}
fis.skip(startFrom)
res = newChunkedResponse(
Status.PARTIAL_CONTENT, mime,
fis
)
res.addHeader("Content-Length", "" + dataLen)
res.addHeader(
"Content-Range", "bytes " + startFrom + "-"
+ endAt + "/" + fileLen
)
}
} else {
res = newFixedLengthResponse(
Status.OK, mime,
file.inputStream(), file.length()
)
res.addHeader("Accept-Ranges", "bytes")
res.addHeader("Content-Length", "" + fileLen)
}
} catch (ioe: IOException) {
res = newFixedLengthResponse(
Status.FORBIDDEN,
MIME_PLAINTEXT, "FORBIDDEN: Reading file failed."
)
}
return res
}
private fun errorResponse(message: String = "Error Occurred"): Response {
return newFixedLengthResponse(Status.INTERNAL_ERROR, MIME_PLAINTEXT, message)
}
}

View file

@ -95,7 +95,7 @@ class SleepTimerDialog : DialogFragment() {
shouldFinishLastSong.isVisible = false
timerUpdater.start()
setPositiveButton(android.R.string.ok, null)
setNegativeButton(R.string.cast_stop) { _, _ ->
setNegativeButton(R.string.action_cancel) { _, _ ->
timerUpdater.cancel()
val previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE)
if (previous != null) {

View file

@ -24,6 +24,7 @@ import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.extensions.setUpMediaRouteButton
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.GridStyle
import code.name.monkey.retromusic.fragments.ReloadType
@ -41,7 +42,6 @@ import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
import com.afollestad.materialcab.createCab
import com.google.android.gms.cast.framework.CastButtonFactory
class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
IAlbumClickListener, ICabHolder {
@ -169,7 +169,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
setupLayoutMenu(layoutItem.subMenu)
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
requireContext().setUpMediaRouteButton(menu)
}
private fun setUpSortOrderMenu(

View file

@ -25,6 +25,7 @@ import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_NAME
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.extensions.setUpMediaRouteButton
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.GridStyle
import code.name.monkey.retromusic.fragments.ReloadType
@ -43,7 +44,6 @@ import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
import com.afollestad.materialcab.createCab
import com.google.android.gms.cast.framework.CastButtonFactory
class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
IArtistClickListener, IAlbumArtistClickListener, ICabHolder {
@ -180,7 +180,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
setupAlbumArtistMenu(menu)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
requireContext().setUpMediaRouteButton(menu)
}
private fun setupAlbumArtistMenu(menu: Menu) {

View file

@ -26,12 +26,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.retromusic.EXTRA_GENRE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.GenreAdapter
import code.name.monkey.retromusic.extensions.setUpMediaRouteButton
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
import code.name.monkey.retromusic.interfaces.IGenreClickListener
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.material.transition.MaterialSharedAxis
class
@ -67,7 +67,7 @@ GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
menu.removeItem(R.id.action_sort_order)
menu.findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
requireContext().setUpMediaRouteButton(menu)
}
override fun onResume() {

View file

@ -35,10 +35,7 @@ import code.name.monkey.retromusic.adapter.HomeAdapter
import code.name.monkey.retromusic.databinding.FragmentHomeBinding
import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog
import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.dip
import code.name.monkey.retromusic.extensions.drawNextToNavbar
import code.name.monkey.retromusic.extensions.elevatedAccentColor
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.glide.GlideApp
@ -48,7 +45,6 @@ import code.name.monkey.retromusic.interfaces.IScrollHelper
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil.userName
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.MaterialFadeThrough
import com.google.android.material.transition.MaterialSharedAxis
@ -212,7 +208,7 @@ class HomeFragment :
ATHToolbarActivity.getToolbarBackgroundColor(binding.toolbar)
)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
requireContext().setUpMediaRouteButton(menu)
}
override fun scrollToTop() {

View file

@ -30,11 +30,11 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentLibraryBinding
import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog
import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog
import code.name.monkey.retromusic.extensions.setUpMediaRouteButton
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil
import com.google.android.gms.cast.framework.CastButtonFactory
class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
@ -99,7 +99,7 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
getToolbarBackgroundColor(binding.toolbar)
)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
requireContext().setUpMediaRouteButton(menu)
}
override fun onMenuItemSelected(item: MenuItem): Boolean {

View file

@ -24,13 +24,13 @@ import code.name.monkey.retromusic.EXTRA_PLAYLIST
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.extensions.setUpMediaRouteButton
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder
import code.name.monkey.retromusic.interfaces.IPlaylistClickListener
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.material.transition.MaterialSharedAxis
class PlaylistsFragment :
@ -85,7 +85,7 @@ class PlaylistsFragment :
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
MenuCompat.setGroupDividerEnabled(menu, true)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
requireContext().setUpMediaRouteButton(menu)
}
override fun onMenuItemSelected(item: MenuItem): Boolean {

View file

@ -26,6 +26,7 @@ import androidx.preference.PreferenceManager
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.dip
import code.name.monkey.retromusic.extensions.goToProVersion
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.preferences.*
import code.name.monkey.retromusic.util.NavigationUtil
@ -39,7 +40,7 @@ abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() {
internal fun showProToastAndNavigate(message: String) {
showToast(getString(R.string.message_pro_feature, message))
NavigationUtil.goToProVersion(requireActivity())
requireContext().goToProVersion()
}
internal fun setSummary(preference: Preference, value: Any?) {

View file

@ -27,6 +27,7 @@ import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentMainSettingsBinding
import code.name.monkey.retromusic.extensions.drawAboveSystemBarsWithPadding
import code.name.monkey.retromusic.extensions.goToProVersion
import code.name.monkey.retromusic.util.NavigationUtil
class MainSettingsFragment : Fragment(), View.OnClickListener {
@ -77,11 +78,11 @@ class MainSettingsFragment : Fragment(), View.OnClickListener {
binding.buyProContainer.apply {
isGone = App.isProVersion()
setOnClickListener {
NavigationUtil.goToProVersion(requireContext())
requireContext().goToProVersion()
}
}
binding.buyPremium.setOnClickListener {
NavigationUtil.goToProVersion(requireContext())
requireContext().goToProVersion()
}
ThemeStore.accentColor(requireContext()).let {
binding.buyPremium.setTextColor(it)

View file

@ -21,12 +21,10 @@ import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEListPreference
import code.name.monkey.retromusic.LANGUAGE_NAME
import code.name.monkey.retromusic.LAST_ADDED_CUTOFF
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.installLanguageAndRecreate
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.ReloadType.HomeSections
import com.google.android.play.core.splitinstall.SplitInstallManagerFactory
import com.google.android.play.core.splitinstall.SplitInstallRequest
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import java.util.*
/**
* @author Hemanth S (h4h13).
@ -58,21 +56,7 @@ class OtherSettingsFragment : AbsSettingsFragment() {
val languagePreference: Preference? = findPreference(LANGUAGE_NAME)
languagePreference?.setOnPreferenceChangeListener { prefs, newValue ->
setSummary(prefs, newValue)
val code = newValue.toString()
val manager = SplitInstallManagerFactory.create(requireContext())
if (code != "auto") {
// Try to download language resources
val request =
SplitInstallRequest.newBuilder().addLanguage(Locale.forLanguageTag(code))
.build()
manager.startInstall(request)
// Recreate the activity on download complete
.addOnCompleteListener {
restartActivity()
}
} else {
requireActivity().recreate()
}
requireActivity().installLanguageAndRecreate(newValue.toString())
true
}
}

View file

@ -21,6 +21,7 @@ import androidx.annotation.LayoutRes
import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.extensions.setUpMediaRouteButton
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.GridStyle
import code.name.monkey.retromusic.fragments.ReloadType
@ -35,7 +36,6 @@ import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
import com.afollestad.materialcab.createCab
import com.google.android.gms.cast.framework.CastButtonFactory
class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager>(),
ICabHolder {
@ -136,7 +136,7 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
setupLayoutMenu(layoutItem.subMenu)
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
//Setting up cast button
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
requireContext().setUpMediaRouteButton(menu)
}
private fun setUpSortOrderMenu(sortOrderMenu: SubMenu) {

View file

@ -27,10 +27,10 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.SongRepository
import code.name.monkey.retromusic.service.CastPlayer
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.getExternalStorageDirectory
import code.name.monkey.retromusic.util.logE
import com.google.android.gms.cast.framework.CastSession
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
@ -456,8 +456,8 @@ object MusicPlayerRemote : KoinComponent {
.dropLastWhile { it.isEmpty() }.toTypedArray()[1]
}
fun switchToRemotePlayback(castSession: CastSession) {
musicService?.switchToRemotePlayback(castSession)
fun switchToRemotePlayback(castPlayer: CastPlayer) {
musicService?.switchToRemotePlayback(castPlayer)
}
fun switchToLocalPlayback() {

View file

@ -81,7 +81,7 @@ class AlbumCoverStylePreferenceDialog : DialogFragment(),
if (isAlbumCoverStyle(coverStyle)) {
val result = getString(coverStyle.titleRes) + " theme is Pro version feature."
showToast(result)
NavigationUtil.goToProVersion(requireActivity())
requireContext().goToProVersion()
} else {
PreferenceUtil.albumCoverStyle = coverStyle
}

View file

@ -91,7 +91,7 @@ class NowPlayingScreenPreferenceDialog : DialogFragment(), ViewPager.OnPageChang
val result =
"${getString(nowPlayingScreen.titleRes)} theme is Pro version feature."
showToast(result)
NavigationUtil.goToProVersion(requireContext())
requireContext().goToProVersion()
} else {
PreferenceUtil.nowPlayingScreen = nowPlayingScreen
}

View file

@ -1,110 +0,0 @@
package code.name.monkey.retromusic.service
import code.name.monkey.retromusic.cast.CastHelper.toMediaInfo
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.MediaSeekOptions
import com.google.android.gms.cast.MediaStatus
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.media.RemoteMediaClient
class CastPlayer(castSession: CastSession) : Playback, RemoteMediaClient.Callback() {
override val isInitialized: Boolean = true
private val remoteMediaClient: RemoteMediaClient? = castSession.remoteMediaClient
init {
remoteMediaClient?.registerCallback(this)
remoteMediaClient?.setPlaybackRate(playbackSpeed.toDouble().coerceIn(0.5, 2.0))
}
private var isActuallyPlaying = false
override val isPlaying: Boolean
get() {
return remoteMediaClient?.isPlaying == true || isActuallyPlaying
}
override val audioSessionId: Int = 0
override var callbacks: Playback.PlaybackCallbacks? = null
override fun setDataSource(
song: Song,
force: Boolean,
completion: (success: Boolean) -> Unit,
) {
try {
val mediaLoadOptions =
MediaLoadOptions.Builder().setPlayPosition(0).setAutoplay(true).build()
remoteMediaClient?.load(song.toMediaInfo()!!, mediaLoadOptions)
completion(true)
} catch (e: Exception) {
e.printStackTrace()
completion(false)
}
}
override fun setNextDataSource(path: String?) {}
override fun start(): Boolean {
isActuallyPlaying = true
remoteMediaClient?.play()
return true
}
override fun stop() {
isActuallyPlaying = false
remoteMediaClient?.stop()
}
override fun release() {
stop()
}
override fun pause(): Boolean {
isActuallyPlaying = false
remoteMediaClient?.pause()
return true
}
override fun duration(): Int {
return remoteMediaClient?.streamDuration?.toInt() ?: 0
}
override fun position(): Int {
return remoteMediaClient?.approximateStreamPosition?.toInt() ?: 0
}
override fun seek(whereto: Int): Int {
remoteMediaClient?.seek(MediaSeekOptions.Builder().setPosition(whereto.toLong()).build())
return whereto
}
override fun setVolume(vol: Float) = true
override fun setAudioSessionId(sessionId: Int) = true
override fun setCrossFadeDuration(duration: Int) {}
override fun setPlaybackSpeedPitch(speed: Float, pitch: Float) {
remoteMediaClient?.setPlaybackRate(speed.toDouble().coerceIn(0.5, 2.0))
}
override fun onStatusUpdated() {
when (remoteMediaClient?.playerState) {
MediaStatus.PLAYER_STATE_IDLE -> {
val idleReason = remoteMediaClient.idleReason
if (idleReason == MediaStatus.IDLE_REASON_FINISHED) {
callbacks?.onTrackEnded()
}
}
MediaStatus.PLAYER_STATE_PLAYING, MediaStatus.PLAYER_STATE_PAUSED -> {
callbacks?.onPlayStateChanged()
}
}
}
}

View file

@ -15,10 +15,10 @@
package code.name.monkey.retromusic.service
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.os.PowerManager
import android.os.PowerManager.WakeLock
@ -62,8 +62,7 @@ class MediaButtonIntentReceiver : MediaButtonReceiver() {
private var mClickCounter = 0
private var mLastClickTime: Long = 0
@SuppressLint("HandlerLeak") // false alarm, handler is already static
private val mHandler = object : Handler() {
private val mHandler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {

View file

@ -86,7 +86,6 @@ import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
import com.google.android.gms.cast.framework.CastSession
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.Default
import kotlinx.coroutines.Dispatchers.IO
@ -1171,8 +1170,8 @@ class MusicService : MediaBrowserServiceCompat(),
playbackManager.switchToLocalPlayback(this::restorePlaybackState)
}
fun switchToRemotePlayback(castSession: CastSession) {
playbackManager.switchToRemotePlayback(castSession, this::restorePlaybackState)
fun switchToRemotePlayback(castPlayer: CastPlayer) {
playbackManager.switchToRemotePlayback(castPlayer, this::restorePlaybackState)
}
private fun restorePlaybackState(wasPlaying: Boolean, progress: Int) {

View file

@ -8,7 +8,6 @@ import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil.playbackPitch
import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed
import com.google.android.gms.cast.framework.CastSession
class PlaybackManager(val context: Context) {
@ -160,11 +159,11 @@ class PlaybackManager(val context: Context) {
}
fun switchToRemotePlayback(
castSession: CastSession,
castPlayer: CastPlayer,
onChange: (wasPlaying: Boolean, progress: Int) -> Unit,
) {
playbackLocation = PlaybackLocation.REMOTE
switchToPlayback(CastPlayer(castSession), onChange)
switchToPlayback(castPlayer, onChange)
}
private fun switchToPlayback(

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util
import android.app.Activity
import android.content.SharedPreferences
import androidx.core.content.edit
import com.google.android.play.core.review.ReviewManagerFactory
object AppRater {
private const val DO_NOT_SHOW_AGAIN = "do_not_show_again"// Package Name
private const val APP_RATING = "app_rating"// Package Name
private const val LAUNCH_COUNT = "launch_count"// Package Name
private const val DATE_FIRST_LAUNCH = "date_first_launch"// Package Name
private const val DAYS_UNTIL_PROMPT = 3//Min number of days
private const val LAUNCHES_UNTIL_PROMPT = 5//Min number of launches
@JvmStatic
fun appLaunched(context: Activity) {
val prefs = context.getSharedPreferences(APP_RATING, 0)
if (prefs.getBoolean(DO_NOT_SHOW_AGAIN, false)) {
return
}
prefs.edit {
// Increment launch counter
val launchCount = prefs.getLong(LAUNCH_COUNT, 0) + 1
putLong(LAUNCH_COUNT, launchCount)
// Get date of first launch
var dateFirstLaunch = prefs.getLong(DATE_FIRST_LAUNCH, 0)
if (dateFirstLaunch == 0L) {
dateFirstLaunch = System.currentTimeMillis()
putLong(DATE_FIRST_LAUNCH, dateFirstLaunch)
}
// Wait at least n days before opening
if (launchCount >= LAUNCHES_UNTIL_PROMPT) {
if (System.currentTimeMillis() >= dateFirstLaunch + DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000) {
//showRateDialog(context, editor)
showPlayStoreReviewDialog(context, this)
}
}
}
}
private fun showPlayStoreReviewDialog(context: Activity, editor: SharedPreferences.Editor) {
val manager = ReviewManagerFactory.create(context)
val flow = manager.requestReviewFlow()
flow.addOnCompleteListener { request ->
if (request.isSuccessful) {
val reviewInfo = request.result
val flowManager = manager.launchReviewFlow(context, reviewInfo)
flowManager.addOnCompleteListener {
if (it.isSuccessful) {
editor.putBoolean(DO_NOT_SHOW_AGAIN, true)
editor.commit()
}
}
}
}
}
}

View file

@ -39,12 +39,6 @@ object NavigationUtil {
)
}
fun goToProVersion(context: Context) {
context.startActivity(
Intent(context, PurchaseActivity::class.java), null
)
}
fun goToSupportDevelopment(activity: Activity) {
activity.startActivity(
Intent(activity, SupportDevelopmentActivity::class.java), null

View file

@ -1,33 +0,0 @@
package code.name.monkey.retromusic.util
import android.content.Context
import android.content.Intent
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.activities.PurchaseActivity
object PremiumShow {
private const val PREF_NAME = "premium_show"
private const val LAUNCH_COUNT = "launch_count"
private const val DATE_FIRST_LAUNCH = "date_first_launch"
@JvmStatic
fun launch(context: Context) {
val pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
if (App.isProVersion()) {
return
}
val prefEditor = pref.edit()
val launchCount = pref.getLong(LAUNCH_COUNT, 0) + 1
prefEditor.putLong(LAUNCH_COUNT, launchCount)
var dateLaunched = pref.getLong(DATE_FIRST_LAUNCH, 0)
if (dateLaunched == 0L) {
dateLaunched = System.currentTimeMillis()
prefEditor.putLong(DATE_FIRST_LAUNCH, dateLaunched)
}
if (System.currentTimeMillis() >= dateLaunched + 2 * 24 * 60 * 60 * 1000) {
context.startActivity(Intent(context, PurchaseActivity::class.java), null)
}
prefEditor.apply()
}
}