mirror of
https://github.com/AllanWang/Frost-for-Facebook.git
synced 2024-11-08 20:12:39 +01:00
enhancement/video-player (#480)
* Add toolbar visibility toggle and draw it over viewer * Set contract bindings once available * Fix video url param error and prepare progressanimator * Add gif support and better transitions * Interface a lot of things * Reorder back press * Clean up files and fix selector * Add gif support * Redraw bounds when necessary
This commit is contained in:
parent
ec7fdc2521
commit
2b51bc4bfa
@ -42,12 +42,14 @@
|
||||
android:theme="@style/FrostTheme" />
|
||||
<activity
|
||||
android:name=".activities.WebOverlayActivity"
|
||||
android:configChanges="orientation|screenSize|locale"
|
||||
android:hardwareAccelerated="true"
|
||||
android:label="@string/frost_name"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/FrostTheme.Overlay.Slide" />
|
||||
<activity
|
||||
android:name=".activities.WebOverlayBasicActivity"
|
||||
android:configChanges="orientation|screenSize|locale"
|
||||
android:hardwareAccelerated="true"
|
||||
android:label="@string/frost_web"
|
||||
android:launchMode="singleTop"
|
||||
@ -55,6 +57,7 @@
|
||||
<activity
|
||||
android:name=".activities.FrostWebActivity"
|
||||
android:autoRemoveFromRecents="true"
|
||||
android:configChanges="orientation|screenSize|locale"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:label="@string/frost_web"
|
||||
@ -70,6 +73,7 @@
|
||||
android:autoVerify="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
@ -135,8 +139,6 @@
|
||||
<activity
|
||||
android:name=".activities.ImageActivity"
|
||||
android:theme="@style/FrostTheme.Transparent" />
|
||||
<activity android:name=".activities.VideoActivity"
|
||||
android:theme="@style/FrostTheme.Video" />
|
||||
|
||||
<service
|
||||
android:name=".services.NotificationService"
|
||||
|
@ -9,7 +9,7 @@ if (!window.hasOwnProperty('frost_media')) {
|
||||
* Commonality; check for valid target
|
||||
*/
|
||||
var element = e.target || e.srcElement;
|
||||
if (!element.hasAttribute("data-sigil") || !element.getAttribute("data-sigil").includes("playInlineVideo")) return;
|
||||
if (!element.hasAttribute("data-sigil") || !element.getAttribute("data-sigil").toLowerCase().includes("inlinevideo")) return;
|
||||
console.log("Found inline video");
|
||||
element = element.parentNode;
|
||||
if (!element.hasAttribute("data-store")) return;
|
||||
@ -20,8 +20,8 @@ if (!window.hasOwnProperty('frost_media')) {
|
||||
return;
|
||||
}
|
||||
if (!dataStore.src) return;
|
||||
console.log("Inline video", dataStore.src);
|
||||
if (typeof Frost !== 'undefined') Frost.loadVideo(dataStore.src);
|
||||
console.log("Inline video " + dataStore.src);
|
||||
if (typeof Frost !== 'undefined') Frost.loadVideo(dataStore.src, dataStore.animatedGifVideo);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return;
|
||||
|
20
app/src/main/assets/js/media.min.js
vendored
20
app/src/main/assets/js/media.min.js
vendored
@ -1,20 +1,20 @@
|
||||
if(!window.hasOwnProperty("frost_media")){
|
||||
console.log("Registering frost_media"),
|
||||
window.frost_media=!0
|
||||
;var _frostMediaClick=function(t){
|
||||
var e=t.target||t.srcElement
|
||||
;if(e.hasAttribute("data-sigil")&&e.getAttribute("data-sigil").includes("playInlineVideo")&&(console.log("Found inline video"),
|
||||
e=e.parentNode,
|
||||
e.hasAttribute("data-store"))){
|
||||
;var _frostMediaClick=function(e){
|
||||
var t=e.target||e.srcElement
|
||||
;if(t.hasAttribute("data-sigil")&&t.getAttribute("data-sigil").toLowerCase().includes("inlinevideo")&&(console.log("Found inline video"),
|
||||
t=t.parentNode,
|
||||
t.hasAttribute("data-store"))){
|
||||
var i
|
||||
;try{
|
||||
i=JSON.parse(e.getAttribute("data-store"))
|
||||
}catch(t){
|
||||
i=JSON.parse(t.getAttribute("data-store"))
|
||||
}catch(e){
|
||||
return
|
||||
}
|
||||
i.src&&(console.log("Inline video",i.src),"undefined"!=typeof Frost&&Frost.loadVideo(i.src),
|
||||
t.stopPropagation(),
|
||||
t.preventDefault())
|
||||
i.src&&(console.log("Inline video "+i.src),"undefined"!=typeof Frost&&Frost.loadVideo(i.src,i.animatedGifVideo),
|
||||
e.stopPropagation(),
|
||||
e.preventDefault())
|
||||
}
|
||||
}
|
||||
;document.addEventListener("click",_frostMediaClick,!0)
|
||||
|
@ -1,10 +1,12 @@
|
||||
package com.pitchedapps.frost.activities
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import ca.allanwang.kau.internal.KauBaseActivity
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.pitchedapps.frost.R
|
||||
import com.pitchedapps.frost.contracts.VideoViewerContract
|
||||
import com.pitchedapps.frost.utils.L
|
||||
import com.pitchedapps.frost.utils.Prefs
|
||||
import com.pitchedapps.frost.utils.materialDialogThemed
|
||||
@ -18,7 +20,10 @@ import io.reactivex.schedulers.Schedulers
|
||||
*/
|
||||
abstract class BaseActivity : KauBaseActivity() {
|
||||
override fun onBackPressed() {
|
||||
if (isTaskRoot && Prefs.exitConfirmation) {
|
||||
if (this is MainActivity && searchView?.onBackPressed() == true) return
|
||||
if (this is VideoViewerContract && videoOnBackPress()) return
|
||||
if (this is MainActivity && currentFragment.onBackPressed()) return
|
||||
if (this !is WebOverlayActivityBase && isTaskRoot && Prefs.exitConfirmation) {
|
||||
materialDialogThemed {
|
||||
title(R.string.kau_exit)
|
||||
content(R.string.kau_exit_confirmation)
|
||||
@ -27,12 +32,14 @@ abstract class BaseActivity : KauBaseActivity() {
|
||||
onPositive { _, _ -> super.onBackPressed() }
|
||||
checkBoxPromptRes(R.string.kau_do_not_show_again, false, { _, b -> Prefs.exitConfirmation = !b })
|
||||
}
|
||||
} else super.onBackPressed()
|
||||
return
|
||||
}
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setFrostTheme()
|
||||
if (this !is WebOverlayActivityBase) setFrostTheme()
|
||||
}
|
||||
|
||||
private var networkDisposable: Disposable? = null
|
||||
@ -47,8 +54,7 @@ abstract class BaseActivity : KauBaseActivity() {
|
||||
networkDisposable = ReactiveNetwork.observeNetworkConnectivity(applicationContext)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
connectivity: Connectivity ->
|
||||
.subscribe { connectivity: Connectivity ->
|
||||
connectivity.apply {
|
||||
L.d("Network connectivity changed: isAvailable: $isAvailable isRoaming: $isRoaming")
|
||||
consumer(connectivity)
|
||||
@ -64,12 +70,23 @@ abstract class BaseActivity : KauBaseActivity() {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposeNetworkConnectivity()
|
||||
observeNetworkConnectivity()
|
||||
// disposeNetworkConnectivity()
|
||||
// observeNetworkConnectivity()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
disposeNetworkConnectivity()
|
||||
// disposeNetworkConnectivity()
|
||||
}
|
||||
|
||||
|
||||
override fun onStop() {
|
||||
if (this is VideoViewerContract) videoOnStop()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
if (this is VideoViewerContract) videoViewer?.updateLocation()
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.PointF
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.net.Uri
|
||||
@ -48,6 +47,7 @@ import com.pitchedapps.frost.R
|
||||
import com.pitchedapps.frost.contracts.ActivityWebContract
|
||||
import com.pitchedapps.frost.contracts.FileChooserContract
|
||||
import com.pitchedapps.frost.contracts.FileChooserDelegate
|
||||
import com.pitchedapps.frost.contracts.VideoViewerContract
|
||||
import com.pitchedapps.frost.dbflow.loadFbCookie
|
||||
import com.pitchedapps.frost.dbflow.loadFbTabs
|
||||
import com.pitchedapps.frost.enums.MainActivityLayout
|
||||
@ -63,7 +63,6 @@ import com.pitchedapps.frost.utils.iab.FrostBilling
|
||||
import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
|
||||
import com.pitchedapps.frost.utils.iab.IabMain
|
||||
import com.pitchedapps.frost.views.BadgedIcon
|
||||
import com.pitchedapps.frost.views.FrostVideoContainerContract
|
||||
import com.pitchedapps.frost.views.FrostVideoViewer
|
||||
import com.pitchedapps.frost.views.FrostViewPager
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
@ -77,18 +76,18 @@ import java.util.concurrent.TimeUnit
|
||||
|
||||
class MainActivity : BaseActivity(),
|
||||
ActivityWebContract, FileChooserContract by FileChooserDelegate(),
|
||||
FrostVideoContainerContract,
|
||||
VideoViewerContract,
|
||||
FrostBilling by IabMain() {
|
||||
|
||||
lateinit var adapter: SectionsPagerAdapter
|
||||
val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper)
|
||||
override val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper)
|
||||
val toolbar: Toolbar by bindView(R.id.toolbar)
|
||||
val viewPager: FrostViewPager by bindView(R.id.container)
|
||||
val fab: FloatingActionButton by bindView(R.id.fab)
|
||||
val tabs: TabLayout by bindView(R.id.tabs)
|
||||
val appBar: AppBarLayout by bindView(R.id.appbar)
|
||||
val coordinator: CoordinatorLayout by bindView(R.id.main_content)
|
||||
var videoViewer: FrostVideoViewer? = null
|
||||
override var videoViewer: FrostVideoViewer? = null
|
||||
lateinit var drawer: Drawer
|
||||
lateinit var drawerHeader: AccountHeader
|
||||
var webFragmentObservable = PublishSubject.create<Int>()!!
|
||||
@ -130,8 +129,7 @@ class MainActivity : BaseActivity(),
|
||||
"Frost id" to Prefs.frostId)
|
||||
}
|
||||
}
|
||||
setContentView(R.layout.activity_frame_wrapper)
|
||||
frameWrapper.inflate(Prefs.mainActivityLayout.layoutRes, true)
|
||||
setFrameContentView(Prefs.mainActivityLayout.layoutRes)
|
||||
setSupportActionBar(toolbar)
|
||||
adapter = SectionsPagerAdapter(supportFragmentManager, loadFbTabs())
|
||||
viewPager.adapter = adapter
|
||||
@ -147,7 +145,7 @@ class MainActivity : BaseActivity(),
|
||||
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
|
||||
val delta: Float by lazy { positionOffset * (255 - 128).toFloat() }
|
||||
val delta = positionOffset * (255 - 128).toFloat()
|
||||
tabsForEachView { tabPosition, view ->
|
||||
view.setAllAlpha(when (tabPosition) {
|
||||
position -> 255.0f - delta
|
||||
@ -169,14 +167,6 @@ class MainActivity : BaseActivity(),
|
||||
onCreateBilling()
|
||||
}
|
||||
|
||||
fun showVideo(url: String) {
|
||||
if (videoViewer != null) {
|
||||
videoViewer?.setVideo(url)
|
||||
} else {
|
||||
videoViewer = FrostVideoViewer.showVideo(url, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) {
|
||||
(0 until tabs.tabCount).asSequence().forEach { i ->
|
||||
action(i, tabs.getTabAt(i)!!.customView as BadgedIcon)
|
||||
@ -312,7 +302,7 @@ class MainActivity : BaseActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
fun Builder.primaryFrostItem(item: FbItem) = this.primaryItem(item.titleId) {
|
||||
private fun Builder.primaryFrostItem(item: FbItem) = this.primaryItem(item.titleId) {
|
||||
iicon = item.icon
|
||||
iconColor = Prefs.textColor.toLong()
|
||||
textColor = Prefs.textColor.toLong()
|
||||
@ -331,7 +321,7 @@ class MainActivity : BaseActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
fun Builder.secondaryFrostItem(@StringRes title: Int, onClick: () -> Unit) = this.secondaryItem(title) {
|
||||
private fun Builder.secondaryFrostItem(@StringRes title: Int, onClick: () -> Unit) = this.secondaryItem(title) {
|
||||
textColor = Prefs.textColor.toLong()
|
||||
selectedIconColor = Prefs.textColor.toLong()
|
||||
selectedTextColor = Prefs.textColor.toLong()
|
||||
@ -436,23 +426,11 @@ class MainActivity : BaseActivity(),
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
videoViewer?.pause()
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
onDestroyBilling()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (videoViewer?.onBackPressed() == true) return
|
||||
if (searchView?.onBackPressed() == true) return
|
||||
if (currentFragment.onBackPressed()) return
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
inline val currentFragment
|
||||
get() = supportFragmentManager.findFragmentByTag("android:switcher:${R.id.container}:${viewPager.currentItem}") as WebFragment
|
||||
|
||||
@ -489,16 +467,4 @@ class MainActivity : BaseActivity(),
|
||||
else
|
||||
PointF(0f, 0f)
|
||||
|
||||
override val videoContainer: FrameLayout
|
||||
get() = frameWrapper
|
||||
|
||||
override fun onVideoFinished() {
|
||||
L.d("Video view released")
|
||||
videoViewer = null
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
videoViewer?.updateLocation()
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
package com.pitchedapps.frost.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import ca.allanwang.kau.internal.KauBaseActivity
|
||||
import ca.allanwang.kau.utils.bindView
|
||||
import com.pitchedapps.frost.R
|
||||
import com.pitchedapps.frost.utils.L
|
||||
import com.pitchedapps.frost.views.FrostVideoView
|
||||
|
||||
/**
|
||||
* Created by Allan Wang on 2017-06-01.
|
||||
*/
|
||||
class VideoActivity : KauBaseActivity() {
|
||||
|
||||
val container: ViewGroup by bindView(R.id.video_container)
|
||||
val video: FrostVideoView by bindView(R.id.video)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.view_video)
|
||||
container.setOnTouchListener { _, event ->
|
||||
val y = video.shouldParentAcceptTouch(event)
|
||||
L.d("Video SPAT $y")
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
video.pause()
|
||||
super.onStop()
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.pitchedapps.frost.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.PointF
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.CoordinatorLayout
|
||||
@ -10,6 +11,7 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.webkit.ValueCallback
|
||||
import android.webkit.WebChromeClient
|
||||
import android.widget.FrameLayout
|
||||
import ca.allanwang.kau.internal.KauBaseActivity
|
||||
import ca.allanwang.kau.swipe.kauSwipeOnCreate
|
||||
import ca.allanwang.kau.swipe.kauSwipeOnDestroy
|
||||
@ -20,9 +22,11 @@ import com.pitchedapps.frost.R
|
||||
import com.pitchedapps.frost.contracts.ActivityWebContract
|
||||
import com.pitchedapps.frost.contracts.FileChooserContract
|
||||
import com.pitchedapps.frost.contracts.FileChooserDelegate
|
||||
import com.pitchedapps.frost.contracts.VideoViewerContract
|
||||
import com.pitchedapps.frost.enums.OverlayContext
|
||||
import com.pitchedapps.frost.facebook.*
|
||||
import com.pitchedapps.frost.utils.*
|
||||
import com.pitchedapps.frost.views.FrostVideoViewer
|
||||
import com.pitchedapps.frost.web.FrostWebView
|
||||
import io.reactivex.disposables.Disposable
|
||||
import okhttp3.HttpUrl
|
||||
@ -95,9 +99,10 @@ class WebOverlayBasicActivity : WebOverlayActivityBase(true)
|
||||
*/
|
||||
class WebOverlayActivity : WebOverlayActivityBase(false)
|
||||
|
||||
open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : KauBaseActivity(),
|
||||
ActivityWebContract, FileChooserContract by FileChooserDelegate() {
|
||||
open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseActivity(),
|
||||
ActivityWebContract, VideoViewerContract, FileChooserContract by FileChooserDelegate() {
|
||||
|
||||
override val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper)
|
||||
val toolbar: Toolbar by bindView(R.id.overlay_toolbar)
|
||||
val frostWeb: FrostWebView by bindView(R.id.overlay_frost_webview)
|
||||
val coordinator: CoordinatorLayout by bindView(R.id.overlay_main_content)
|
||||
@ -122,7 +127,7 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : KauBas
|
||||
finish()
|
||||
return
|
||||
}
|
||||
setContentView(R.layout.activity_web_overlay)
|
||||
setFrameContentView(R.layout.activity_web_overlay)
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
@ -219,4 +224,13 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : KauBas
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------
|
||||
* Video Contract
|
||||
* ----------------------------------------------------
|
||||
*/
|
||||
override var videoViewer: FrostVideoViewer? = null
|
||||
override val lowerVideoPadding: PointF = PointF(0f, 0f)
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.pitchedapps.frost.contracts
|
||||
|
||||
import android.app.Activity
|
||||
import android.widget.FrameLayout
|
||||
import ca.allanwang.kau.utils.inflate
|
||||
import com.pitchedapps.frost.R
|
||||
import com.pitchedapps.frost.utils.L
|
||||
import com.pitchedapps.frost.views.FrostVideoContainerContract
|
||||
import com.pitchedapps.frost.views.FrostVideoViewer
|
||||
|
||||
/**
|
||||
* Created by Allan Wang on 2017-11-10.
|
||||
*/
|
||||
interface VideoViewerContract : FrameWrapper, FrostVideoContainerContract {
|
||||
|
||||
var videoViewer: FrostVideoViewer?
|
||||
|
||||
fun showVideo(url: String)
|
||||
= showVideo(url, false)
|
||||
|
||||
/**
|
||||
* Create new viewer and reuse existing one
|
||||
* The url will be formatted upon loading
|
||||
*/
|
||||
fun showVideo(url: String, repeat: Boolean) {
|
||||
if (videoViewer != null)
|
||||
videoViewer?.setVideo(url, repeat)
|
||||
else
|
||||
videoViewer = FrostVideoViewer.showVideo(url, repeat, this)
|
||||
}
|
||||
|
||||
fun videoOnStop() = videoViewer?.pause()
|
||||
|
||||
fun videoOnBackPress() = videoViewer?.onBackPressed() ?: false
|
||||
|
||||
override val videoContainer: FrameLayout
|
||||
get() = frameWrapper
|
||||
|
||||
override fun onVideoFinished() {
|
||||
L.d("Video view released")
|
||||
videoViewer = null
|
||||
}
|
||||
}
|
||||
|
||||
interface FrameWrapper {
|
||||
|
||||
val frameWrapper: FrameLayout
|
||||
|
||||
fun Activity.setFrameContentView(layoutRes: Int) {
|
||||
setContentView(R.layout.activity_frame_wrapper)
|
||||
frameWrapper.inflate(layoutRes, true)
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,7 @@ package com.pitchedapps.frost.facebook
|
||||
*/
|
||||
const val HTTPS_FACEBOOK_COM = "https://facebook.com"
|
||||
const val FACEBOOK_COM = "facebook.com"
|
||||
const val FB_URL_BASE = "https://m.facebook.com/"
|
||||
const val FB_URL_BASE = "https://m.$FACEBOOK_COM/"
|
||||
fun PROFILE_PICTURE_URL(id: Long) = "https://graph.facebook.com/$id/picture?type=large"
|
||||
|
||||
const val USER_AGENT_FULL = "Mozilla/5.0 (Linux; Android 4.4.2; en-us; SAMSUNG SM-G900T Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.6 Chrome/28.0.1500.94 Mobile Safari/537.36"
|
||||
|
@ -31,7 +31,7 @@ class FbUrlFormatter(url: String) {
|
||||
var cleanedUrl = url
|
||||
discardable.forEach { cleanedUrl = cleanedUrl.replace(it, "", true) }
|
||||
converter.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v, true) }
|
||||
if (cleanedUrl != url) cleanedUrl = cleanedUrl.replaceFirst("&", "?")
|
||||
if (cleanedUrl != url && !cleanedUrl.contains("?")) cleanedUrl = cleanedUrl.replaceFirst("&", "?")
|
||||
cleanedUrl = URLDecoder.decode(cleanedUrl, StandardCharsets.UTF_8.name())
|
||||
val qm = cleanedUrl.indexOf("?")
|
||||
if (qm > -1) {
|
||||
@ -70,6 +70,8 @@ class FbUrlFormatter(url: String) {
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val VIDEO_REDIRECT = "/video_redirect/?src="
|
||||
/**
|
||||
* Items here are explicitly removed from the url
|
||||
* Taken from FaceSlim
|
||||
@ -82,7 +84,7 @@ class FbUrlFormatter(url: String) {
|
||||
"https://m.facebook.com/l.php?u=",
|
||||
"http://touch.facebook.com/l.php?u=",
|
||||
"https://touch.facebook.com/l.php?u=",
|
||||
"/video_redirect/?src="
|
||||
VIDEO_REDIRECT
|
||||
)
|
||||
|
||||
val misc = arrayOf("&" to "&")
|
||||
|
70
app/src/main/kotlin/com/pitchedapps/frost/utils/Animator.kt
Normal file
70
app/src/main/kotlin/com/pitchedapps/frost/utils/Animator.kt
Normal file
@ -0,0 +1,70 @@
|
||||
package com.pitchedapps.frost.utils
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ValueAnimator
|
||||
import android.view.animation.Interpolator
|
||||
|
||||
/**
|
||||
* Created by Allan Wang on 2017-11-10.
|
||||
*/
|
||||
class ProgressAnimator private constructor(private vararg val values: Float) {
|
||||
|
||||
companion object {
|
||||
inline fun ofFloat(crossinline builder: ProgressAnimator.() -> Unit) = ofFloat(0f, 1f) { builder() }
|
||||
|
||||
fun ofFloat(vararg values: Float, builder: ProgressAnimator.() -> Unit) = ProgressAnimator(*values).apply {
|
||||
builder()
|
||||
build()
|
||||
}
|
||||
}
|
||||
|
||||
private val animators: MutableList<(Float) -> Unit> = mutableListOf()
|
||||
private val startActions: MutableList<() -> Unit> = mutableListOf()
|
||||
private val endActions: MutableList<() -> Unit> = mutableListOf()
|
||||
|
||||
var duration: Long = -1L
|
||||
var interpolator: Interpolator? = null
|
||||
|
||||
/**
|
||||
* Add more changes to the [ValueAnimator] before running
|
||||
*/
|
||||
var extraConfigs: ValueAnimator.() -> Unit = {}
|
||||
|
||||
fun withAnimator(from: Float, to: Float, animator: (Float) -> Unit) = animators.add {
|
||||
val range = to - from
|
||||
animator(range * it + from)
|
||||
}
|
||||
|
||||
fun withAnimator(animator: (Float) -> Unit) = animators.add(animator)
|
||||
|
||||
fun withAnimatorInv(animator: (Float) -> Unit) = animators.add { animator(1f - it) }
|
||||
|
||||
fun withStartAction(action: () -> Unit) = startActions.add(action)
|
||||
|
||||
fun withEndAction(action: () -> Unit) = endActions.add(action)
|
||||
|
||||
fun build() {
|
||||
ValueAnimator.ofFloat(*values).apply {
|
||||
if (this@ProgressAnimator.duration > 0L)
|
||||
duration = this@ProgressAnimator.duration
|
||||
if (this@ProgressAnimator.interpolator != null)
|
||||
interpolator = this@ProgressAnimator.interpolator
|
||||
addUpdateListener {
|
||||
val progress = it.animatedValue as Float
|
||||
animators.forEach { it(progress) }
|
||||
}
|
||||
addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationStart(animation: Animator?) {
|
||||
startActions.forEach { it() }
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
endActions.forEach { it() }
|
||||
}
|
||||
})
|
||||
extraConfigs()
|
||||
start()
|
||||
}
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ import com.pitchedapps.frost.R
|
||||
import com.pitchedapps.frost.activities.*
|
||||
import com.pitchedapps.frost.dbflow.CookieModel
|
||||
import com.pitchedapps.frost.facebook.*
|
||||
import com.pitchedapps.frost.facebook.FbUrlFormatter.Companion.VIDEO_REDIRECT
|
||||
import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
@ -200,6 +201,9 @@ fun Context.resolveActivityForUri(uri: Uri): Boolean {
|
||||
inline val String?.isFacebookUrl
|
||||
get() = this != null && this.contains(FACEBOOK_COM)
|
||||
|
||||
inline val String?.isVideoUrl
|
||||
get() = this != null && this.startsWith(VIDEO_REDIRECT)
|
||||
|
||||
fun Context.frostChangelog() = showChangelog(R.xml.frost_changelog, Prefs.textColor) {
|
||||
theme()
|
||||
if (System.currentTimeMillis() - Prefs.installDate > 2592000000) { //show after 1 month
|
||||
|
@ -8,10 +8,12 @@ import android.util.AttributeSet
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import ca.allanwang.kau.utils.AnimHolder
|
||||
import ca.allanwang.kau.utils.dpToPx
|
||||
import ca.allanwang.kau.utils.scaleXY
|
||||
import com.devbrackets.android.exomedia.ui.widget.VideoView
|
||||
import com.pitchedapps.frost.utils.L
|
||||
import com.pitchedapps.frost.utils.ProgressAnimator
|
||||
|
||||
/**
|
||||
* Created by Allan Wang on 2017-10-13.
|
||||
@ -29,10 +31,10 @@ class FrostVideoView @JvmOverloads constructor(
|
||||
private inline val v
|
||||
get() = videoViewImpl
|
||||
|
||||
var backgroundView: View? = null
|
||||
var onFinishedListener: () -> Unit = {}
|
||||
lateinit var viewerContract: FrostVideoViewerContract
|
||||
private lateinit var viewerContract: FrostVideoViewerContract
|
||||
lateinit var containerContract: FrostVideoContainerContract
|
||||
var repeat: Boolean = false
|
||||
|
||||
private val videoDimensions = PointF(0f, 0f)
|
||||
|
||||
@ -47,8 +49,8 @@ class FrostVideoView @JvmOverloads constructor(
|
||||
private val SWIPE_TO_CLOSE_HORIZONTAL_THRESHOLD = 2f.dpToPx
|
||||
private val SWIPE_TO_CLOSE_VERTICAL_THRESHOLD = 5f.dpToPx
|
||||
private val SWIPE_TO_CLOSE_OFFSET_THRESHOLD = 75f.dpToPx
|
||||
val ANIMATION_DURATION = 300L
|
||||
private val FAST_ANIMATION_DURATION = 100L
|
||||
const val ANIMATION_DURATION = 200L
|
||||
private const val FAST_ANIMATION_DURATION = 100L
|
||||
}
|
||||
|
||||
private var videoBounds = RectF()
|
||||
@ -59,19 +61,32 @@ class FrostVideoView @JvmOverloads constructor(
|
||||
if (videoDimensions.x <= 0f || videoDimensions.y <= 0f)
|
||||
return L.d("Attempted to toggle video expansion when points have not been finalized")
|
||||
field = value
|
||||
val origX = translationX
|
||||
val origY = translationY
|
||||
val origScale = scaleX
|
||||
if (field) {
|
||||
animate().scaleXY(1f).translationX(0f).translationY(0f).setDuration(ANIMATION_DURATION).withStartAction {
|
||||
backgroundView?.animate()?.alpha(1f)?.setDuration(ANIMATION_DURATION)
|
||||
viewerContract.onFade(1f, ANIMATION_DURATION)
|
||||
}.withEndAction {
|
||||
if (!isPlaying) showControls()
|
||||
ProgressAnimator.ofFloat {
|
||||
duration = ANIMATION_DURATION
|
||||
interpolator = AnimHolder.fastOutSlowInInterpolator(context)
|
||||
withAnimator { viewerContract.onExpand(it) }
|
||||
withAnimator(origScale, 1f) { scaleXY = it }
|
||||
withAnimator(origX, 0f) { translationX = it }
|
||||
withAnimator(origY, 0f) { translationY = it }
|
||||
withEndAction {
|
||||
if (!isPlaying) showControls()
|
||||
else viewerContract.onControlsHidden()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hideControls()
|
||||
val (scale, tX, tY) = mapBounds()
|
||||
animate().scaleXY(scale).translationX(tX).translationY(tY).setDuration(ANIMATION_DURATION).withStartAction {
|
||||
backgroundView?.animate()?.alpha(0f)?.setDuration(ANIMATION_DURATION)
|
||||
viewerContract.onFade(0f, ANIMATION_DURATION)
|
||||
ProgressAnimator.ofFloat {
|
||||
duration = ANIMATION_DURATION
|
||||
interpolator = AnimHolder.fastOutSlowInInterpolator(context)
|
||||
withAnimatorInv { viewerContract.onExpand(it) }
|
||||
withAnimator(origScale, scale) { scaleXY = it }
|
||||
withAnimator(origX, tX) { translationX = it }
|
||||
withAnimator(origY, tY) { translationY = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,16 +125,28 @@ class FrostVideoView @JvmOverloads constructor(
|
||||
if (isExpanded) showControls()
|
||||
}
|
||||
setOnCompletionListener {
|
||||
viewerContract.onVideoComplete()
|
||||
if (repeat) restart()
|
||||
else viewerContract.onVideoComplete()
|
||||
}
|
||||
setOnTouchListener(FrameTouchListener(context))
|
||||
v.setOnTouchListener(VideoTouchListener(context))
|
||||
setOnVideoSizedChangedListener { intrinsicWidth, intrinsicHeight ->
|
||||
val ratio = Math.min(width.toFloat() / intrinsicWidth, height.toFloat() / intrinsicHeight.toFloat())
|
||||
/**
|
||||
* Only remap if not expanded and if dimensions have changed
|
||||
*/
|
||||
val shouldRemap = !isExpanded
|
||||
&& (videoDimensions.x != ratio * intrinsicWidth || videoDimensions.y != ratio * intrinsicHeight)
|
||||
videoDimensions.set(ratio * intrinsicWidth, ratio * intrinsicHeight)
|
||||
if (shouldRemap) updateLocation()
|
||||
}
|
||||
}
|
||||
|
||||
fun setViewerContract(contract: FrostVideoViewerContract) {
|
||||
this.viewerContract = contract
|
||||
videoControls?.setVisibilityListener(viewerContract)
|
||||
}
|
||||
|
||||
fun jumpToStart() {
|
||||
pause()
|
||||
v.seekTo(0)
|
||||
@ -136,7 +163,7 @@ class FrostVideoView @JvmOverloads constructor(
|
||||
|
||||
override fun restart(): Boolean {
|
||||
videoUri ?: return false
|
||||
if (videoViewImpl.restart() && isExpanded) {
|
||||
if (videoViewImpl.restart() && isExpanded && !repeat) {
|
||||
videoControls?.showLoading(true)
|
||||
return true
|
||||
}
|
||||
@ -163,9 +190,11 @@ class FrostVideoView @JvmOverloads constructor(
|
||||
fun destroy() {
|
||||
stopPlayback()
|
||||
if (alpha > 0f)
|
||||
animate().alpha(0f).setDuration(FAST_ANIMATION_DURATION).withEndAction { onFinishedListener() }.withStartAction {
|
||||
viewerContract.onFade(0f, FAST_ANIMATION_DURATION)
|
||||
}.start()
|
||||
ProgressAnimator.ofFloat(alpha, 0f) {
|
||||
duration = FAST_ANIMATION_DURATION
|
||||
withAnimator { alpha = it }
|
||||
withEndAction { onFinishedListener() }
|
||||
}
|
||||
else
|
||||
onFinishedListener()
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import android.view.ViewTreeObserver
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import ca.allanwang.kau.utils.*
|
||||
import com.devbrackets.android.exomedia.listener.VideoControlsVisibilityListener
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||
import com.pitchedapps.frost.R
|
||||
import com.pitchedapps.frost.facebook.formattedFbUrl
|
||||
@ -34,18 +35,22 @@ class FrostVideoViewer @JvmOverloads constructor(
|
||||
val restarter: ImageView by bindView(R.id.video_restart)
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Matches VideoControls.CONTROL_VISIBILITY_ANIMATION_LENGTH
|
||||
*/
|
||||
private const val CONTROL_ANIMATION_DURATION = 300L
|
||||
|
||||
/**
|
||||
* Simplified binding to add video to layout, and remove it when finished
|
||||
* This is under the assumption that the container allows for overlays,
|
||||
* such as a FrameLayout
|
||||
*/
|
||||
fun showVideo(url: String, contract: FrostVideoContainerContract): FrostVideoViewer {
|
||||
fun showVideo(url: String, repeat: Boolean, contract: FrostVideoContainerContract): FrostVideoViewer {
|
||||
val container = contract.videoContainer
|
||||
val videoViewer = FrostVideoViewer(container.context)
|
||||
container.addView(videoViewer)
|
||||
videoViewer.bringToFront()
|
||||
L.d("Create video view", url)
|
||||
videoViewer.setVideo(url)
|
||||
videoViewer.setVideo(url, repeat)
|
||||
videoViewer.video.containerContract = contract
|
||||
videoViewer.video.onFinishedListener = { container.removeView(videoViewer); contract.onVideoFinished() }
|
||||
return videoViewer
|
||||
@ -56,11 +61,9 @@ class FrostVideoViewer @JvmOverloads constructor(
|
||||
inflate(R.layout.view_video, true)
|
||||
alpha = 0f
|
||||
background.setBackgroundColor(if (Prefs.bgColor.isColorDark) Prefs.bgColor.withMinAlpha(200) else Color.BLACK)
|
||||
video.backgroundView = background
|
||||
video.viewerContract = this
|
||||
video.setViewerContract(this)
|
||||
video.pause()
|
||||
toolbar.inflateMenu(R.menu.menu_video)
|
||||
toolbar.setBackgroundColor(Prefs.headerColor)
|
||||
context.setMenuIcons(toolbar.menu, Prefs.iconColor,
|
||||
R.id.action_pip to GoogleMaterial.Icon.gmd_picture_in_picture_alt,
|
||||
R.id.action_download to GoogleMaterial.Icon.gmd_file_download
|
||||
@ -77,12 +80,14 @@ class FrostVideoViewer @JvmOverloads constructor(
|
||||
video.restart()
|
||||
restarter.fadeOut { restarter.gone() }
|
||||
}
|
||||
// toolbar.setOnTouchListener { _, event -> video.shouldParentAcceptTouch(event) }
|
||||
}
|
||||
|
||||
fun setVideo(url: String) {
|
||||
fun setVideo(url: String, repeat: Boolean = false) {
|
||||
val formattedUrl = url.formattedFbUrl
|
||||
L.d("Load video view; repeat: $repeat", url)
|
||||
animate().alpha(1f).setDuration(FrostVideoView.ANIMATION_DURATION).start()
|
||||
video.setVideoURI(Uri.parse(url.formattedFbUrl))
|
||||
video.setVideoURI(Uri.parse(formattedUrl))
|
||||
video.repeat = repeat
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,10 +111,9 @@ class FrostVideoViewer @JvmOverloads constructor(
|
||||
* -------------------------------------------------------------
|
||||
*/
|
||||
|
||||
override fun onFade(alpha: Float, duration: Long) {
|
||||
toolbar.visible().animate().alpha(alpha).setDuration(duration).withEndAction {
|
||||
if (alpha == 0f) toolbar.gone()
|
||||
}
|
||||
override fun onExpand(progress: Float) {
|
||||
toolbar.goneIf(progress == 0f).alpha = progress
|
||||
background.alpha = progress
|
||||
}
|
||||
|
||||
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
|
||||
@ -134,11 +138,26 @@ class FrostVideoViewer @JvmOverloads constructor(
|
||||
})
|
||||
}
|
||||
|
||||
override fun onControlsShown() {
|
||||
if (video.isExpanded)
|
||||
toolbar.fadeIn(duration = CONTROL_ANIMATION_DURATION, onStart = { toolbar.visible() })
|
||||
}
|
||||
|
||||
override fun onControlsHidden() {
|
||||
if (!toolbar.isGone)
|
||||
toolbar.fadeOut(duration = CONTROL_ANIMATION_DURATION) { toolbar.gone() }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface FrostVideoViewerContract {
|
||||
interface FrostVideoViewerContract : VideoControlsVisibilityListener {
|
||||
fun onSingleTapConfirmed(event: MotionEvent): Boolean
|
||||
fun onFade(alpha: Float, duration: Long)
|
||||
/**
|
||||
* Process of expansion
|
||||
* 1f represents an expanded view, 0f represents a minimized view
|
||||
*/
|
||||
fun onExpand(progress: Float)
|
||||
|
||||
fun onVideoComplete()
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.support.v4.widget.SwipeRefreshLayout
|
||||
import android.webkit.JavascriptInterface
|
||||
import com.pitchedapps.frost.activities.MainActivity
|
||||
import com.pitchedapps.frost.contracts.VideoViewerContract
|
||||
import com.pitchedapps.frost.dbflow.CookieModel
|
||||
import com.pitchedapps.frost.facebook.FbCookie
|
||||
import com.pitchedapps.frost.utils.*
|
||||
@ -36,9 +37,10 @@ class FrostJSI(val webView: FrostWebViewCore) {
|
||||
= if (url == null) false else webView.requestWebOverlay(url)
|
||||
|
||||
@JavascriptInterface
|
||||
fun loadVideo(url: String?) {
|
||||
fun loadVideo(url: String?, isGif: Boolean) {
|
||||
if (url != null)
|
||||
webView.post { activity?.showVideo(url) }
|
||||
webView.post { (context as? VideoViewerContract)?.showVideo(url, isGif)
|
||||
?: L.d("Could not load video; contract not implemented") }
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
@ -3,13 +3,12 @@ package com.pitchedapps.frost.web
|
||||
import com.pitchedapps.frost.activities.WebOverlayActivity
|
||||
import com.pitchedapps.frost.activities.WebOverlayActivityBase
|
||||
import com.pitchedapps.frost.activities.WebOverlayBasicActivity
|
||||
import com.pitchedapps.frost.contracts.VideoViewerContract
|
||||
import com.pitchedapps.frost.facebook.FB_URL_BASE
|
||||
import com.pitchedapps.frost.facebook.FbItem
|
||||
import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
|
||||
import com.pitchedapps.frost.facebook.formattedFbUrl
|
||||
import com.pitchedapps.frost.utils.L
|
||||
import com.pitchedapps.frost.utils.isFacebookUrl
|
||||
import com.pitchedapps.frost.utils.launchWebOverlay
|
||||
import com.pitchedapps.frost.utils.*
|
||||
|
||||
/**
|
||||
* Created by Allan Wang on 2017-08-15.
|
||||
@ -26,6 +25,12 @@ import com.pitchedapps.frost.utils.launchWebOverlay
|
||||
*/
|
||||
fun FrostWebViewCore.requestWebOverlay(url: String): Boolean {
|
||||
if (url == "#") return false
|
||||
if (url.isVideoUrl && context is VideoViewerContract) {
|
||||
L.i("Found video", url)
|
||||
(context as VideoViewerContract).showVideo(url)
|
||||
return true
|
||||
}
|
||||
if (!Prefs.overlayEnabled) return false
|
||||
if (context is WebOverlayActivityBase) {
|
||||
L.v("Check web request from overlay", url)
|
||||
//already overlay; manage user agent
|
||||
@ -73,7 +78,8 @@ fun FrostWebViewCore.requestWebOverlay(url: String): Boolean {
|
||||
val messageWhitelist = setOf(FbItem.MESSAGES, FbItem.CHAT, FbItem.FEED_MOST_RECENT, FbItem.FEED_TOP_STORIES).map { it.url }.toSet()
|
||||
|
||||
val String.shouldUseBasicAgent
|
||||
get() = (messageWhitelist.any { contains(it) }) || this == FB_URL_BASE
|
||||
get() = !contains("story.php") //we will use basic agent for anything that isn't a comment section
|
||||
// get() = (messageWhitelist.any { contains(it) }) || this == FB_URL_BASE
|
||||
|
||||
/**
|
||||
* The following components should never be launched in a new overlay
|
||||
|
@ -106,11 +106,11 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient
|
||||
injectBackgroundColor()
|
||||
webCore.jsInject(
|
||||
JsActions.LOGIN_CHECK,
|
||||
JsAssets.CLICK_A.maybe(Prefs.overlayEnabled),
|
||||
JsAssets.CLICK_A,
|
||||
JsAssets.TEXTAREA_LISTENER,
|
||||
CssHider.ADS.maybe(!Prefs.showFacebookAds && IS_FROST_PRO),
|
||||
JsAssets.CONTEXT_A,
|
||||
JsAssets.MEDIA.maybe(webCore.baseEnum != null),
|
||||
JsAssets.MEDIA,
|
||||
JsAssets.HEADER_BADGES.maybe(webCore.baseEnum != null)
|
||||
)
|
||||
}
|
||||
|
@ -2,4 +2,5 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/frame_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true" />
|
@ -2,9 +2,9 @@
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/container"
|
||||
android:paddingBottom="@dimen/kau_activity_vertical_margin"
|
||||
android:paddingEnd="@dimen/kau_activity_horizontal_margin"
|
||||
android:paddingStart="@dimen/kau_activity_horizontal_margin"
|
||||
@ -17,7 +17,6 @@
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="@dimen/kau_activity_vertical_margin"
|
||||
android:text="@string/select_facebook_account"
|
||||
android:textColor="@android:color/white"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@ -32,21 +31,10 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_select_account"
|
||||
app:layout_constraintVertical_bias="0.3"
|
||||
tools:layout_editor_absoluteX="0dp"
|
||||
tools:layout_editor_absoluteY="0dp" />
|
||||
|
||||
<!--<android.support.v7.widget.AppCompatTextView-->
|
||||
<!--android:layout_width="wrap_content"-->
|
||||
<!--android:layout_height="wrap_content"-->
|
||||
<!--android:layout_gravity="center_horizontal"-->
|
||||
<!--android:text="@string/select_facebook_account"-->
|
||||
<!--app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!--app:layout_constraintHorizontal_bias="0.5"-->
|
||||
<!--app:layout_constraintStart_toStartOf="parent"-->
|
||||
<!--app:layout_constraintTop_toBottomOf="@userId/selector_recycler"-->
|
||||
<!--tools:layout_editor_absoluteX="8dp"-->
|
||||
<!--tools:layout_editor_absoluteY="0dp" />-->
|
||||
</android.support.constraint.ConstraintLayout>
|
@ -14,16 +14,10 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="false" />
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/video_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
|
||||
<com.pitchedapps.frost.views.FrostVideoView
|
||||
android:id="@+id/video"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
android:background="@android:color/transparent"
|
||||
android:theme="@style/FrostTheme.Video"
|
||||
app:useDefaultControls="true"
|
||||
@ -38,5 +32,10 @@
|
||||
|
||||
</com.pitchedapps.frost.views.FrostVideoView>
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/video_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@drawable/exomedia_default_controls_interactive_background"
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
|
||||
</merge>
|
@ -6,6 +6,14 @@
|
||||
<item text="" />
|
||||
-->
|
||||
|
||||
<version title="v1.6.3" />
|
||||
<item text="Allow for truly full screen videos" />
|
||||
<item text="Support pip video everywhere" />
|
||||
<item text="Support gifs" />
|
||||
<item text="" />
|
||||
<item text="" />
|
||||
<item text="" />
|
||||
|
||||
<version title="v1.6.2" />
|
||||
<item text="Fix search update from Facebook" />
|
||||
<item text="Fix url parsing errors again" />
|
||||
|
@ -48,4 +48,13 @@ class FbUrlTest {
|
||||
assertFbFormat("${FB_URL_BASE}relative", "$FB_URL_BASE/relative")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun video() {
|
||||
//note that the video numbers have been changed to maintain privacy
|
||||
val url = "/video_redirect/?src=https%3A%2F%2Fvideo-yyz1-1.xx.fbcdn.net%2Fv%2Ft42.1790-2%2F2349078999904_n.mp4%3Fefg%3DeyJ87J9%26oh%3Df5777784%26oe%3D56FD4&source=media_collage&id=1735049&refid=8&_ft_=qid.6484464%3Amf_story_key.-43172431214%3Atop_level_post_id.102773&__tn__=FEH-R"
|
||||
val expected = "https://video-yyz1-1.xx.fbcdn.net/v/t42.1790-2/2349078999904_n.mp4?efg=eyJ87J9&oh=f5777784&oe=56FD4?source&id=1735049&_ft_=qid.6484464:mf_story_key.-43172431214:top_level_post_id.102773&__tn__=FEH-R"
|
||||
assertFbFormat(expected, url)
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -7,7 +7,7 @@ buildscript {
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.0-rc1'
|
||||
classpath 'com.android.tools.build:gradle:3.0.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${KOTLIN}"
|
||||
classpath 'io.fabric.tools:gradle:1.+'
|
||||
classpath 'com.github.triplet.gradle:play-publisher:1.2.0'
|
||||
|
@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## v1.6.3
|
||||
* Allow for truly full screen videos
|
||||
* Support pip video everywhere
|
||||
* Support gifs
|
||||
|
||||
## v1.6.2
|
||||
* Fix search update from Facebook
|
||||
* Fix url parsing errors again
|
||||
|
@ -45,4 +45,4 @@ JUNIT=4.12
|
||||
TEST_RULE=0.5
|
||||
TEST_RUNNER=1.0.0
|
||||
|
||||
android.enableAapt2=false
|
||||
#android.enableAapt2=false
|
Loading…
Reference in New Issue
Block a user