6.5.2 commit

This commit is contained in:
Xilin Jia 2024-09-03 06:58:12 +01:00
parent 0299b53c8c
commit c29eb0bf1b
17 changed files with 102 additions and 124 deletions

View File

@ -31,8 +31,8 @@ android {
testApplicationId "ac.mdiq.podcini.tests"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
versionCode 3020235
versionName "6.5.1"
versionCode 3020236
versionName "6.5.2"
applicationId "ac.mdiq.podcini.R"
def commit = ""
@ -90,8 +90,8 @@ android {
compose true
}
splits {
abi {
splits {
abi {
enable true
reset()
include "arm64-v8a" // Specify the ABI you want to split.
@ -142,11 +142,11 @@ android {
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard.cfg"
resValue "string", "app_name", "Podcini.R"
resValue "string", "provider_authority", "ac.mdiq.podcini.R.provider"
// debuggable false
vcsInfo.include false
minifyEnabled true
shrinkResources true
signingConfig signingConfigs.releaseConfig
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard.cfg"
}
debug {
resValue "string", "app_name", "Podcini.R Debug"
@ -161,8 +161,8 @@ android {
def buildType = variant.buildType.name
def versionName = variant.versionName
def flavorName = variant.flavorName ?: ""
def abiName = output.getFilter(com.android.build.OutputFile.ABI) ?: "universal"
outputFileName = "${applicationName}_${flavorName}_${buildType}_${versionName}_${abiName}.apk"
def abiName = output.getFilter(com.android.build.OutputFile.ABI) ?: ""
outputFileName = "${applicationName}_${buildType}_${flavorName}_${versionName}_${abiName}.apk"
}
}
androidResources {

View File

@ -1,17 +1,21 @@
-dontobfuscate
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
#-renamesourcefileattribute SourceFile
-keepattributes Exceptions, SourceFile,LineNumberTable
-optimizations !code/allocation/variable
-optimizationpasses 5
## Rules for VistaGuide
# -keepclassmembers class ac.mdiq.vista** {*;}
-keep class ac.mdiq.vista.extractor.timeago.patterns.** { *; }
-keep class org.mozilla.javascript.** { *; }
-keep class org.mozilla.classfile.ClassFileWriter
-keep class java.beans.**
-dontwarn org.mozilla.javascript.tools.**
-keep class java.beans.**
-dontwarn java.beans.**
-keep class ac.mdiq.vista.settings.notifications.** { *; }
-allowaccessmodification
-dontskipnonpubliclibraryclassmembers
@ -19,8 +23,6 @@
# Without this, methods only used in tests are removed and break tests.
-keep class ac.mdiq.podcini**
-keepclassmembers class ac.mdiq.podcini** {*;}
# -keep class de.test.podcini**
# -keepclassmembers class de.test.podcini** {*;}
# Keep methods used in tests.
# This is only needed when running tests with proguard enabled.
@ -40,9 +42,6 @@
-dontwarn okhttp3.**
-dontwarn okio.**
# android-iconify
#-keep class com.joanzapata.** { *; }
#### Proguard rules for fyyd client
# Retrofit 2.0
-dontwarn retrofit2.**
@ -62,10 +61,10 @@
####
# awaitility
-dontwarn java.beans.BeanInfo
-dontwarn java.beans.Introspector
-dontwarn java.beans.IntrospectionException
-dontwarn java.beans.PropertyDescriptor
# -dontwarn java.beans.BeanInfo
# -dontwarn java.beans.Introspector
# -dontwarn java.beans.IntrospectionException
# -dontwarn java.beans.PropertyDescriptor
-dontwarn java.lang.management.ManagementFactory
-dontwarn java.lang.management.ThreadInfo
-dontwarn java.lang.management.ThreadMXBean

View File

@ -45,8 +45,8 @@
android:supportsRtl="true"
android:logo="@mipmap/ic_launcher"
android:resizeableActivity="true"
android:allowAudioPlaybackCapture="true"
android:networkSecurityConfig="@xml/network_security_config">
android:allowAudioPlaybackCapture="true">
<!-- android:networkSecurityConfig="@xml/network_security_config">-->
<service android:name=".playback.service.PlaybackService"
android:foregroundServiceType="mediaPlayback"

View File

@ -8,10 +8,12 @@ import ac.mdiq.vista.extractor.downloader.Response
import ac.mdiq.vista.extractor.exceptions.ReCaptchaException
import android.content.Context
import androidx.preference.PreferenceManager
import okhttp3.Cache
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request.Builder
import okhttp3.RequestBody
import java.io.File
import java.io.IOException
import java.util.*
import java.util.concurrent.TimeUnit
@ -22,7 +24,7 @@ class VistaDownloaderImpl private constructor(builder: OkHttpClient.Builder) : D
private val mCookies: MutableMap<String, String> = HashMap()
private val client: OkHttpClient = builder
.readTimeout(30, TimeUnit.SECONDS)
// .cache(new Cache(new File(context.getExternalCacheDir(), "okhttp"), 16 * 1024 * 1024))
// .cache(Cache(File(context.getExternalCacheDir(), "okhttp"), 16 * 1024 * 1024))
.build()
private fun getCookies(url: String): String {
@ -107,17 +109,22 @@ class VistaDownloaderImpl private constructor(builder: OkHttpClient.Builder) : D
}
}
val response = client.newCall(requestBuilder.build()).execute()
if (response.code == 429) {
response.close()
throw ReCaptchaException("reCaptcha Challenge requested", url)
try {
val response = client.newCall(requestBuilder.build()).execute()
if (response.code == 429) {
response.close()
throw ReCaptchaException("reCaptcha Challenge requested", url)
}
val body = response.body
val responseBodyToReturn: String? = body?.string()
val latestUrl = response.request.url.toString()
return Response(response.code, response.message, response.headers.toMultimap(), responseBodyToReturn, latestUrl)
} catch (e: Throwable) {
e.printStackTrace()
throw IOException("Something is wrong ${e.message}")
}
val body = response.body
val responseBodyToReturn: String? = body?.string()
val latestUrl = response.request.url.toString()
return Response(response.code, response.message, response.headers.toMultimap(), responseBodyToReturn, latestUrl)
}
companion object {

View File

@ -101,9 +101,7 @@ object PodciniHttpClient {
if (!proxyConfig!!.username.isNullOrEmpty() && proxyConfig!!.password != null) {
builder.proxyAuthenticator { _: Route?, response: Response ->
val credentials = basic(proxyConfig!!.username!!, proxyConfig!!.password!!)
response.request.newBuilder()
.header("Proxy-Authorization", credentials)
.build()
response.request.newBuilder().header("Proxy-Authorization", credentials).build()
}
}
}
@ -126,9 +124,7 @@ object PodciniHttpClient {
@Throws(IOException::class)
override fun intercept(chain: Chain): Response {
TrafficStats.setThreadStatsTag(Thread.currentThread().id.toInt())
return chain.proceed(chain.request().newBuilder()
.header("User-Agent", ClientConfig.USER_AGENT?:"")
.build())
return chain.proceed(chain.request().newBuilder().header("User-Agent", ClientConfig.USER_AGENT?:"").build())
}
}

View File

@ -1,5 +1,6 @@
package ac.mdiq.podcini.net.feed.discovery
import ac.mdiq.podcini.util.Logd
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
@ -21,13 +22,9 @@ class CombinedSearcher : PodcastSearcher {
try {
val results = searcher.search(query)
searchResults[index] = results
} catch (e: Throwable) {
Log.d(TAG, Log.getStackTraceString(e))
}
} catch (e: Throwable) { Logd(TAG, Log.getStackTraceString(e)) }
}
} else {
null
}
} else null
}.filterNotNull() // Remove null jobs
// Wait for all search jobs to complete
searchJobs.awaitAll()

View File

@ -391,11 +391,7 @@ class GpodnetService(private val httpClient: OkHttpClient, baseHosturl: String?,
throw GpodnetServiceAuthenticationException("Wrong username or password")
} else {
if (BuildConfig.DEBUG) {
try {
Logd(TAG, response.body!!.string())
} catch (e: IOException) {
e.printStackTrace()
}
try { Logd(TAG, response.body!!.string()) } catch (e: IOException) { e.printStackTrace() }
}
if (responseCode >= 500) {
throw GpodnetServiceBadStatusCodeException("Gpodder.net is currently unavailable (code " + responseCode + ")", responseCode)

View File

@ -39,7 +39,9 @@ object UrlChecker {
// prepareUrl(removedWebsite)
// }
// }
!(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://")) -> "http://$url"
// TODO: test
// !(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://")) -> "http://$url"
!(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://")) -> "https://$url"
else -> url
}
}

View File

@ -1,6 +1,5 @@
package ac.mdiq.podcini.playback.service
import ac.mdiq.podcini.BuildConfig
import ac.mdiq.podcini.R
import ac.mdiq.podcini.net.download.service.HttpCredentialEncoder
import ac.mdiq.podcini.net.download.service.PodciniHttpClient
@ -20,11 +19,11 @@ import ac.mdiq.podcini.storage.model.Feed
import ac.mdiq.podcini.storage.model.MediaType
import ac.mdiq.podcini.storage.model.Playable
import ac.mdiq.podcini.storage.utils.EpisodeUtil
import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.config.ClientConfig
import ac.mdiq.podcini.util.EventFlow
import ac.mdiq.podcini.util.FlowEvent
import ac.mdiq.podcini.util.FlowEvent.PlayEvent.Action
import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.config.ClientConfig
import ac.mdiq.vista.extractor.MediaFormat
import ac.mdiq.vista.extractor.Vista
import ac.mdiq.vista.extractor.stream.*
@ -56,7 +55,6 @@ import androidx.media3.exoplayer.source.ProgressiveMediaSource
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector.SelectionOverride
import androidx.media3.exoplayer.trackselection.ExoTrackSelection
import androidx.media3.exoplayer.util.EventLogger
import androidx.media3.extractor.DefaultExtractorsFactory
import androidx.media3.extractor.mp3.Mp3Extractor
import androidx.media3.ui.DefaultTrackNameProvider
@ -67,8 +65,6 @@ import java.lang.Runnable
import java.util.*
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.concurrent.Volatile
/**
@ -186,28 +182,29 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
@Throws(IllegalArgumentException::class, IllegalStateException::class)
private fun setDataSource(metadata: MediaMetadata, media: EpisodeMedia) {
val url = media.getStreamUrl() ?: return
Logd(TAG, "setDataSource1: $url")
val preferences = media.episodeOrFetch()?.feed?.preferences
val user = preferences?.username
val password = preferences?.password
if (media.episode?.feed?.type == Feed.FeedType.YOUTUBE.name) {
Logd(TAG, "setDataSource setting for YouTube source")
Logd(TAG, "setDataSource1 setting for YouTube source")
try {
val streamInfo = StreamInfo.getInfo(Vista.getService(0), url)
val vService = Vista.getService(0)
val streamInfo = StreamInfo.getInfo(vService, url)
val audioStreamsList = getFilteredAudioStreams(streamInfo.audioStreams)
Logd(TAG, "setDataSource1 got ${audioStreamsList.size}")
val audioIndex = if (isNetworkRestricted) 0 else audioStreamsList.size - 1
val audioStream = audioStreamsList[audioIndex]
Logd(TAG, "setDataSource1 use audio quality: ${audioStream.bitrate}")
val aSource = DefaultMediaSourceFactory(context).createMediaSource(MediaItem.Builder().setTag(metadata).setUri(Uri.parse(audioStream.content)).build())
Logd(TAG, "setDataSource use audio quality: ${audioStream.bitrate}")
if (media.episode?.feed?.preferences?.playAudioOnly != true) {
Logd(TAG, "setDataSource result: $streamInfo")
Logd(TAG, "setDataSource videoStreams: ${streamInfo.videoStreams.size} videoOnlyStreams: ${streamInfo.videoOnlyStreams.size} audioStreams: ${streamInfo.audioStreams.size}")
Logd(TAG, "setDataSource1 result: $streamInfo")
Logd(TAG, "setDataSource1 videoStreams: ${streamInfo.videoStreams.size} videoOnlyStreams: ${streamInfo.videoOnlyStreams.size} audioStreams: ${streamInfo.audioStreams.size}")
val videoStreamsList = getSortedStreamVideosList(streamInfo.videoStreams, streamInfo.videoOnlyStreams, true, true)
val videoIndex = 0
val videoStream = videoStreamsList[videoIndex]
Logd(TAG, "setDataSource use video quality: ${videoStream.resolution}")
Logd(TAG, "setDataSource1 use video quality: ${videoStream.resolution}")
val vSource = DefaultMediaSourceFactory(context).createMediaSource(MediaItem.Builder().setTag(metadata).setUri(Uri.parse(videoStream.content)).build())
val mediaSources: MutableList<MediaSource> = java.util.ArrayList()
val mediaSources: MutableList<MediaSource> = ArrayList()
mediaSources.add(vSource)
mediaSources.add(aSource)
mediaSource = MergingMediaSource(true, *mediaSources.toTypedArray<MediaSource>())
@ -215,9 +212,9 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
} else mediaSource = aSource
mediaItem = mediaSource?.mediaItem
setSourceCredentials(user, password)
} catch (throwable: Throwable) { Logd(TAG, "setDataSource error: ${throwable.message}") }
} catch (throwable: Throwable) { Log.e(TAG, "setDataSource1 error: ${throwable.message}") }
} else {
Logd(TAG, "setDataSource setting for Podcast source")
Logd(TAG, "setDataSource1 setting for Podcast source")
setDataSource(metadata, url,user, password)
}
}
@ -255,15 +252,15 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
* streams and normal video streams are available
* @return the sorted list
*/
fun getSortedStreamVideosList(videoStreams: List<VideoStream>?, videoOnlyStreams: List<VideoStream>?, ascendingOrder: Boolean,
private fun getSortedStreamVideosList(videoStreams: List<VideoStream>?, videoOnlyStreams: List<VideoStream>?, ascendingOrder: Boolean,
preferVideoOnlyStreams: Boolean): List<VideoStream> {
val videoStreamsOrdered = if (preferVideoOnlyStreams) listOf(videoStreams, videoOnlyStreams) else listOf(videoOnlyStreams, videoStreams)
val allInitialStreams = videoStreamsOrdered.filterNotNull().flatMap { it }.toList()
val allInitialStreams = videoStreamsOrdered.filterNotNull().flatten().toList()
val comparator = compareBy<VideoStream> { it.resolution.toResolutionValue() }
return if (ascendingOrder) allInitialStreams.sortedWith(comparator) else { allInitialStreams.sortedWith(comparator.reversed()) }
}
fun String.toResolutionValue(): Int {
private fun String.toResolutionValue(): Int {
val match = Regex("(\\d+)p|(\\d+)k").find(this)
return when {
match?.groupValues?.get(1) != null -> match.groupValues[1].toInt()
@ -272,7 +269,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
}
}
fun getFilteredAudioStreams(audioStreams: List<AudioStream>?): List<AudioStream> {
private fun getFilteredAudioStreams(audioStreams: List<AudioStream>?): List<AudioStream> {
if (audioStreams == null) return listOf()
val collectedStreams = mutableSetOf<AudioStream>()
for (stream in audioStreams) {
@ -281,7 +278,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
continue
collectedStreams.add(stream)
}
return collectedStreams.toList().sortedWith(compareBy<AudioStream> { it.bitrate })
return collectedStreams.toList().sortedWith(compareBy { it.bitrate })
}
/**
@ -355,7 +352,8 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
if (streamurl != null) {
val media = curMedia
if (media is EpisodeMedia) {
setDataSource(metadata, media)
val deferred = CoroutineScope(Dispatchers.IO).async { setDataSource(metadata, media) }
runBlocking { deferred.await() }
// val preferences = media.episodeOrFetch()?.feed?.preferences
// setDataSource(metadata, streamurl, preferences?.username, preferences?.password)
} else setDataSource(metadata, streamurl, null, null)
@ -381,13 +379,12 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
e.printStackTrace()
setPlayerStatus(PlayerStatus.ERROR, null)
EventFlow.postStickyEvent(FlowEvent.PlayerErrorEvent(e.localizedMessage ?: ""))
} finally {
}
} finally { }
}
override fun resume() {
if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
Log.d(TAG, "Resuming/Starting playback")
Logd(TAG, "Resuming/Starting playback")
acquireWifiLockIfNecessary()
setPlaybackParams(getCurrentPlaybackSpeed(curMedia), UserPreferences.isSkipSilence)
setVolume(1.0f, 1.0f)
@ -441,9 +438,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
releaseWifiLockIfNecessary()
when {
curMedia != null -> playMediaObject(curMedia!!, isStreaming, startWhenPrepared.get(), prepareImmediately = false, true)
else -> {
Logd(TAG, "Call to reinit: media and mediaPlayer were null, ignored")
}
else -> Logd(TAG, "Call to reinit: media and mediaPlayer were null, ignored")
}
}
@ -466,11 +461,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
PlayerStatus.PLAYING, PlayerStatus.PAUSED, PlayerStatus.PREPARED -> {
Logd(TAG, "seekTo() called $t")
if (seekLatch != null && seekLatch!!.count > 0) {
try {
seekLatch!!.await(3, TimeUnit.SECONDS)
} catch (e: InterruptedException) {
Log.e(TAG, Log.getStackTraceString(e))
}
try { seekLatch!!.await(3, TimeUnit.SECONDS) } catch (e: InterruptedException) { Log.e(TAG, Log.getStackTraceString(e)) }
}
seekLatch = CountDownLatch(1)
statusBeforeSeeking = status
@ -479,11 +470,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
if (curMedia != null) EventFlow.postEvent(FlowEvent.PlaybackPositionEvent(curMedia, t, curMedia!!.getDuration()))
audioSeekCompleteListener?.run()
if (statusBeforeSeeking == PlayerStatus.PREPARED) curMedia?.setPosition(t)
try {
seekLatch!!.await(3, TimeUnit.SECONDS)
} catch (e: InterruptedException) {
Log.e(TAG, Log.getStackTraceString(e))
}
try { seekLatch!!.await(3, TimeUnit.SECONDS) } catch (e: InterruptedException) { Log.e(TAG, Log.getStackTraceString(e)) }
}
PlayerStatus.INITIALIZED -> {
curMedia?.setPosition(t)
@ -729,7 +716,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
override fun onIsPlayingChanged(isPlaying: Boolean) {
val stat = if (isPlaying) PlayerStatus.PLAYING else PlayerStatus.PAUSED
setPlayerStatus(stat, curMedia)
Log.d(TAG, "onIsPlayingChanged $isPlaying")
Logd(TAG, "onIsPlayingChanged $isPlaying")
}
override fun onPlayerError(error: PlaybackException) {
Logd(TAG, "onPlayerError ${error.message}")
@ -808,7 +795,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
.setAudioOffloadPreferences(audioOffloadPreferences)
.build()
if (BuildConfig.DEBUG) exoPlayer!!.addAnalyticsListener(EventLogger())
// if (BuildConfig.DEBUG) exoPlayer!!.addAnalyticsListener(EventLogger())
if (exoplayerListener != null) {
exoPlayer?.removeListener(exoplayerListener!!)

View File

@ -19,7 +19,6 @@ import android.util.Log
class PowerConnectionReceiver : BroadcastReceiver() {
@UnstableApi override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
Log.d(TAG, "onReceive charging intent: $action")
ClientConfigurator.initialize(context)

View File

@ -152,11 +152,11 @@ object Feeds {
}
fun getFeed(feedId: Long, copy: Boolean = false): Feed? {
if (BuildConfig.DEBUG) {
val stackTrace = Thread.currentThread().stackTrace
val caller = if (stackTrace.size > 3) stackTrace[3] else null
Logd(TAG, "${caller?.className}.${caller?.methodName} getFeed called")
}
// if (BuildConfig.DEBUG) {
// val stackTrace = Thread.currentThread().stackTrace
// val caller = if (stackTrace.size > 3) stackTrace[3] else null
// Logd(TAG, "${caller?.className}.${caller?.methodName} getFeed called")
// }
val f = realm.query(Feed::class, "id == $feedId").first().find()
return if (f != null) {
if (copy) realm.copyFromRealm(f)

View File

@ -689,9 +689,7 @@ import java.util.concurrent.Semaphore
runOnIOScope {
val feed_ = realm.query(Feed::class, "id == ${feed.id}").first().find()
if (feed_ != null) {
upsert(feed_) {
it.sortOrder = sortOrder
}
upsert(feed_) { it.sortOrder = sortOrder }
}
}
}
@ -737,6 +735,10 @@ import java.util.concurrent.Semaphore
private const val ARGUMENT_FEED_ID = "argument.ac.mdiq.podcini.feed_id"
private const val KEY_UP_ARROW = "up_arrow"
var tts: TextToSpeech? = null
var ttsReady = false
var ttsWorking = false
fun newInstance(feedId: Long): FeedEpisodesFragment {
val i = FeedEpisodesFragment()
val b = Bundle()
@ -744,9 +746,5 @@ import java.util.concurrent.Semaphore
i.arguments = b
return i
}
var tts: TextToSpeech? = null
var ttsReady = false
var ttsWorking = false
}
}

View File

@ -268,6 +268,7 @@ class OnlineFeedViewFragment : Fragment() {
val channelTabInfo = ChannelTabInfo.getInfo(service, channelInfo.tabs.first())
Logd(TAG, "startFeedBuilding result1: $channelTabInfo ${channelTabInfo.relatedItems.size}")
selectedDownloadUrl = prepareUrl(url)
// selectedDownloadUrl = url
val feed_ = Feed(selectedDownloadUrl, null)
feed_.id = 1234567889L
feed_.type = Feed.FeedType.YOUTUBE.name

View File

@ -403,7 +403,7 @@ import java.util.*
}
private fun onFeedPrefsChanged(event: FlowEvent.FeedPrefsChangeEvent) {
Log.d(TAG,"speedPresetChanged called")
Logd(TAG,"speedPresetChanged called")
for (item in queueItems) {
if (item.feed?.id == event.feed.id) item.feed = null
}

View File

@ -31,18 +31,12 @@ object RatingDialog {
mPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val firstDate: Long = mPreferences.getLong(KEY_FIRST_START_DATE, 0)
if (firstDate == 0L) {
resetStartDate()
}
if (firstDate == 0L) resetStartDate()
}
fun check() {
if (shouldShow()) {
try {
showInAppReview()
} catch (e: Exception) {
Log.e(TAG, Log.getStackTraceString(e))
}
try { showInAppReview() } catch (e: Exception) { Log.e(TAG, Log.getStackTraceString(e)) }
}
}
@ -58,9 +52,8 @@ object RatingDialog {
val flow: Task<Void?> = manager.launchReviewFlow(context as Activity, reviewInfo)
flow.addOnCompleteListener { task1: Task<Void?>? ->
val previousAttempts: Int = mPreferences.getInt(KEY_NUMBER_OF_REVIEWS, 0)
if (previousAttempts >= 3) {
saveRated()
} else {
if (previousAttempts >= 3) saveRated()
else {
resetStartDate()
mPreferences
.edit()
@ -69,14 +62,10 @@ object RatingDialog {
}
Logd("ReviewDialog", "Successfully finished in-app review")
}
.addOnFailureListener { error: Exception? ->
Logd("ReviewDialog", "failed in reviewing process")
}
.addOnFailureListener { error: Exception? -> Logd("ReviewDialog", "failed in reviewing process") }
}
}
.addOnFailureListener { error: Exception? ->
Logd("ReviewDialog", "failed to get in-app review request")
}
.addOnFailureListener { error: Exception? -> Logd("ReviewDialog", "failed to get in-app review request") }
}
private fun rated(): Boolean {
@ -99,9 +88,7 @@ object RatingDialog {
}
private fun shouldShow(): Boolean {
if (rated() || BuildConfig.DEBUG) {
return false
}
if (rated() || BuildConfig.DEBUG) return false
val now = System.currentTimeMillis()
val firstDate: Long = mPreferences.getLong(KEY_FIRST_START_DATE, now)

View File

@ -1,3 +1,8 @@
# 6.5.2
* replace all url of http to https
* resolved the nasty issue of Youtube media not properly played in release app
# 6.5.1
* further improved behavior in video player, seamless switch among audio-only, window and fullscreen modes, and automatical switch to audio when exit

View File

@ -0,0 +1,4 @@
Version 6.5.2 brings several changes:
* replace all url of http to https
* resolved the nasty issue of Youtube media not properly played in release app