diff --git a/P2Play.iml b/P2Play.iml index a79916e..c96a6e5 100644 --- a/P2Play.iml +++ b/P2Play.iml @@ -1,18 +1,15 @@ - + - - + - - - + diff --git a/README.md b/README.md index a64439d..72fef44 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,17 @@ Comming soon! - Login and register in your instance - Pull to refresh - Show uploaded videos +- Subscribe to accounts +- Show your subscripcion videos +- Rate videos ## What to do? (in next version) - Search videos - Show and make commentaries -- Subscribe to accounts -- Show your subscripcion videos -- Rate and share videos +- Share videos +- View Peertube profiles +- Splash screen ## Demostrations Demostration P2Play Beta 0.1: [https://peertube.video/videos/watch/2eb7b953-0b1b-4019-9300-817539f5f4e8](https://peertube.video/videos/watch/2eb7b953-0b1b-4019-9300-817539f5f4e8) diff --git a/app/app.iml b/app/app.iml index 534d63c..233e049 100644 --- a/app/app.iml +++ b/app/app.iml @@ -50,19 +50,19 @@ - - + + - + - + @@ -97,13 +97,6 @@ - - - - - - - @@ -111,32 +104,46 @@ - + + + + + + + + + + - + + - - + + + - + - + + + + - + @@ -145,36 +152,37 @@ - - + - - - + + + - + + + - - - + + + - + + - + + - - - + diff --git a/app/build.gradle b/app/build.gradle index 9e7dcdb..783ca36 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "org.libre.agosto.p2play" minSdkVersion 21 targetSdkVersion 27 - versionCode 1 - versionName "0.1" + versionCode 2 + versionName "0.1.5" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { @@ -20,7 +20,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - buildToolsVersion '27.0.3' + buildToolsVersion '28.0.2' compileOptions { sourceCompatibility JavaVersion.VERSION_1_6 targetCompatibility JavaVersion.VERSION_1_6 @@ -29,11 +29,11 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" - implementation 'com.android.support:appcompat-v7:27.1.1' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support:appcompat-v7:27.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.2' - implementation 'com.android.support:support-v4:27.1.1' - implementation 'com.android.support:design:27.1.1' + implementation 'com.android.support:support-v4:27.1.0' + implementation 'com.android.support:design:27.1.0' implementation 'com.squareup.picasso:picasso:2.71828' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a81cc54..0fd316f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,8 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_p2play" android:supportsRtl="true" - android:theme="@style/P2playTheme"> + android:theme="@style/P2playTheme" + android:hardwareAccelerated="true"> diff --git a/app/src/main/java/org/libre/agosto/p2play/MainActivity.kt b/app/src/main/java/org/libre/agosto/p2play/MainActivity.kt index 11617e0..b58ab01 100644 --- a/app/src/main/java/org/libre/agosto/p2play/MainActivity.kt +++ b/app/src/main/java/org/libre/agosto/p2play/MainActivity.kt @@ -29,6 +29,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte private lateinit var viewManager: RecyclerView.LayoutManager val client: Videos = Videos() private lateinit var lastItem: MenuItem + private lateinit var subItem: MenuItem lateinit var myMenu: Menu val _db = Database(this) var section: String = "" @@ -89,6 +90,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte "local" -> this.getLocalVideos() "popular" -> this.getPopularVideos() "last" -> this.getLastVideos() + "sub" -> this.getSubscriptionVideos() "my_videos" -> { if(ManagerSingleton.token.token != "") this.getMyVideos() @@ -98,6 +100,23 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte } } + fun getSubscriptionVideos(){ + if(ManagerSingleton.user.status != 1){ + ManagerSingleton.Toast("Inicia session primero") + startActivity(Intent(this, LoginActivity::class.java)) + return + } + swipeContainer.isRefreshing = true + section = "sub" + setTitle(R.string.title_subscriptions) + AsyncTask.execute { + val videos = client.videoSubscriptions(ManagerSingleton.token.token) + runOnUiThread { + this.setData(videos) + } + } + } + // Last videos fun getLastVideos(){ swipeContainer.isRefreshing = true @@ -202,6 +221,9 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte lastItem = item // item.isChecked = true when (item.itemId) { + R.id.nav_subscriptions->{ + getSubscriptionVideos() + } R.id.nav_popular-> { getPopularVideos() } diff --git a/app/src/main/java/org/libre/agosto/p2play/ReproductorActivity.kt b/app/src/main/java/org/libre/agosto/p2play/ReproductorActivity.kt index 47b2dc3..1877e22 100644 --- a/app/src/main/java/org/libre/agosto/p2play/ReproductorActivity.kt +++ b/app/src/main/java/org/libre/agosto/p2play/ReproductorActivity.kt @@ -1,14 +1,21 @@ package org.libre.agosto.p2play +import android.opengl.Visibility +import android.os.AsyncTask import android.support.v7.app.AppCompatActivity import android.os.Bundle +import android.os.Looper +import android.support.v4.content.ContextCompat import android.util.Log +import android.view.View import com.squareup.picasso.Picasso import kotlinx.android.synthetic.main.activity_reproductor.* +import org.libre.agosto.p2play.ajax.Actions import org.libre.agosto.p2play.models.VideoModel class ReproductorActivity : AppCompatActivity() { lateinit var video:VideoModel + private val _actions: Actions = Actions() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -17,6 +24,12 @@ class ReproductorActivity : AppCompatActivity() { videoView.settings.javaScriptEnabled = true videoView.settings.allowContentAccess = true + videoView.settings.javaScriptCanOpenWindowsAutomatically = true + videoView.settings.allowFileAccess = true + videoView.settings.allowFileAccessFromFileURLs = true + videoView.settings.allowUniversalAccessFromFileURLs = true + videoView.settings.domStorageEnabled = true + try { this.video = this.intent.extras.getSerializable("video") as VideoModel tittleVideoTxt.text = this.video.name @@ -34,6 +47,117 @@ class ReproductorActivity : AppCompatActivity() { Log.d("Error", err?.message) } - subscribeBtn.setOnClickListener { ManagerSingleton.Toast(getString(R.string.comming)) } + // subscribeBtn.setOnClickListener { ManagerSingleton.Toast(getString(R.string.comming)) } + subscribeBtn.setOnClickListener { subscribe() } + likeLayout.setOnClickListener { rate("like") } + dislikeLayout.setOnClickListener { rate("dislike") } + } + + fun subscribe(){ + val account = this.video.userUuid+"@"+this.video.userHost + AsyncTask.execute { + if (Looper.myLooper() == null) + Looper.prepare() + val res = this._actions.subscribe(ManagerSingleton.token.token, account) + if (res == 1) { + runOnUiThread { + ManagerSingleton.Toast(getString(R.string.subscribeMsg)) + this.changeSubscribeBtn(true) + } + } + } + } + + fun unSubscribe(){ + val account = this.video.userUuid+"@"+this.video.userHost + AsyncTask.execute { + if (Looper.myLooper() == null) + Looper.prepare() + val res = this._actions.unSubscribe(ManagerSingleton.token.token, account) + if (res == 1) { + runOnUiThread { + ManagerSingleton.Toast(getString(R.string.unSubscribeMsg)) + this.changeSubscribeBtn(false) + } + } + } + } + + fun rate(rate: String){ + AsyncTask.execute { + if (Looper.myLooper() == null) + Looper.prepare() + val res = this._actions.rate(ManagerSingleton.token.token, this.video.id, rate) + if (res == 1) { + runOnUiThread { + ManagerSingleton.Toast(getString(R.string.rateMsg)) + if(rate=="like"){ + likeLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorLike)) + dislikeLayout.background = null + } + else if(rate=="dislike"){ + dislikeLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorDislike)) + likeLayout.background = null + } + } + } + } + } + + fun getRate(){ + AsyncTask.execute { + if (Looper.myLooper() == null) + Looper.prepare() + val rate = this._actions.getRate(ManagerSingleton.token.token, this.video.id) + runOnUiThread { + when (rate){ + "like" -> { + likeLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorLike)) + dislikeLayout.background = null + } + "dislike" -> { + dislikeLayout.setBackgroundColor(ContextCompat.getColor(this, R.color.colorDislike)) + likeLayout.background = null + } + else -> { + likeLayout.background = null + dislikeLayout.background = null + } + } + } + } + } + + fun getSubscription(){ + val account = this.video.userUuid+"@"+this.video.userHost + AsyncTask.execute { + if (Looper.myLooper() == null) + Looper.prepare() + val isSubscribed = this._actions.getSubscription(ManagerSingleton.token.token, account) + runOnUiThread { + this.changeSubscribeBtn(isSubscribed) + } + } + } + + fun changeSubscribeBtn(subscribed: Boolean){ + if(subscribed){ + subscribeBtn.text = getText(R.string.unSubscribeBtn) + subscribeBtn.setOnClickListener { this.unSubscribe() } + } + else{ + subscribeBtn.text = getText(R.string.subscribeBtn) + subscribeBtn.setOnClickListener { this.subscribe() } + } + } + + override fun onResume() { + super.onResume() + if(ManagerSingleton.user.status == 1) { + this.getRate() + this.getSubscription() + actionsLayout.visibility = View.VISIBLE + subscribeBtn.visibility = View.VISIBLE + } } } diff --git a/app/src/main/java/org/libre/agosto/p2play/ajax/Actions.kt b/app/src/main/java/org/libre/agosto/p2play/ajax/Actions.kt new file mode 100644 index 0000000..93b81da --- /dev/null +++ b/app/src/main/java/org/libre/agosto/p2play/ajax/Actions.kt @@ -0,0 +1,123 @@ +package org.libre.agosto.p2play.ajax + +import android.util.JsonReader +import java.io.InputStreamReader + +class Actions: Client() { + + fun subscribe(token: String, account: String):Int{ + var con=this._newCon("users/me/subscriptions","POST", token) + val params:String= "uri=$account" + con.outputStream.write(params.toByteArray()) + var response = 0 + + try { + if (con.responseCode == 204) { + response = 1 + } + } + catch (err: Exception){ + err.printStackTrace() + response = -1 + } + + return response + } + + fun unSubscribe(token: String, account: String):Int{ + var con=this._newCon("users/me/subscriptions/$account","DELETE", token) + var response = 0 + + try { + if (con.responseCode == 204) { + response = 1 + } + } + catch (err: Exception){ + err.printStackTrace() + response = -1 + } + + return response + } + + fun getSubscription(token: String, account: String): Boolean{ + var con=this._newCon("users/me/subscriptions/exist?uris=$account","GET", token) + var isSubscribed = false + + try { + if (con.responseCode == 200) { + var response = InputStreamReader(con.inputStream) + var data = JsonReader(response) + data.beginObject() + while (data.hasNext()){ + val key = data.nextName() + when (key.toString()) { + account->{ + isSubscribed = data.nextBoolean() + } + else->{ + data.skipValue() + } + } + } + } + } + catch (err: Exception){ + err.printStackTrace() + isSubscribed = false + } + + return isSubscribed + } + + fun rate(token: String, id_video: Int, rate: String):Int{ + var con=this._newCon("videos/$id_video/rate","PUT", token) + val params:String= "rating=$rate" + con.outputStream.write(params.toByteArray()) + var response = 0 + + try { + if (con.responseCode == 204) { + response = 1 + } + } + catch (err: Exception){ + err.printStackTrace() + response = -1 + } + + return response + } + + fun getRate(token: String, id_video: Int):String{ + var con=this._newCon("users/me/videos/$id_video/rating","GET", token) + var rating = "none" + + try { + if (con.responseCode == 200) { + var response = InputStreamReader(con.inputStream) + var data = JsonReader(response) + data.beginObject() + while (data.hasNext()){ + val key = data.nextName() + when (key.toString()) { + "rating"->{ + rating = data.nextString() + } + else->{ + data.skipValue() + } + } + } + } + } + catch (err: Exception){ + err.printStackTrace() + rating = "none" + } + + return rating + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/libre/agosto/p2play/ajax/Auth.kt b/app/src/main/java/org/libre/agosto/p2play/ajax/Auth.kt index 6383f0d..bba67ec 100644 --- a/app/src/main/java/org/libre/agosto/p2play/ajax/Auth.kt +++ b/app/src/main/java/org/libre/agosto/p2play/ajax/Auth.kt @@ -1,7 +1,8 @@ package org.libre.agosto.p2play.ajax -import android.support.design.widget.Snackbar +// import android.support.design.widget.Snackbar import android.util.JsonReader +import android.util.JsonToken import android.util.Log import org.libre.agosto.p2play.ManagerSingleton import org.libre.agosto.p2play.models.TokenModel @@ -133,15 +134,20 @@ class Auth: Client() { when(l.toString()){ "followersCount" -> user.followers = data.nextInt() "avatar" -> { - data.beginObject() - while (data.hasNext()){ - val m = data.nextName() - when (m.toString()){ - "path" -> user.avatar = data.nextString() - else -> data.skipValue() + if(data.peek() == JsonToken.BEGIN_OBJECT) { + data.beginObject() + while (data.hasNext()) { + val m = data.nextName() + when (m.toString()) { + "path" -> user.avatar = data.nextString() + else -> data.skipValue() + } } + data.endObject() + } + else{ + data.skipValue() } - data.endObject() } else -> data.skipValue() } diff --git a/app/src/main/java/org/libre/agosto/p2play/ajax/Videos.kt b/app/src/main/java/org/libre/agosto/p2play/ajax/Videos.kt index 7f87afa..1b203e7 100644 --- a/app/src/main/java/org/libre/agosto/p2play/ajax/Videos.kt +++ b/app/src/main/java/org/libre/agosto/p2play/ajax/Videos.kt @@ -21,6 +21,7 @@ class Videos: Client() { while (data.hasNext()){ val key = data.nextName() when (key.toString()) { + "id"-> video.id = data.nextInt() "name"->{ video.name= data.nextString() } @@ -42,13 +43,13 @@ class Videos: Client() { "views"->{ video.views = data.nextInt() } - "account"->{ + "channel"->{ data.beginObject() while (data.hasNext()){ val acKey = data.nextName() when(acKey.toString()){ - "name"->video.username=data.nextString() - "avatar"->{ + "displayName"-> video.username=data.nextString() + "avatar"-> { if(data.peek() == JsonToken.BEGIN_OBJECT){ data.beginObject() while (data.hasNext()){ @@ -64,6 +65,8 @@ class Videos: Client() { data.skipValue() } + "uuid" -> video.userUuid = data.nextString() + "host" -> video.userHost = data.nextString() else-> data.skipValue() } } @@ -88,7 +91,9 @@ class Videos: Client() { } private fun getVideos(start:Int, count:Int, sort:String = "-publishedAt", filter:String = ""):ArrayList{ - val params = "start=$start&count=$count&sort=$sort&filter=$filter" + var params = "start=$start&count=$count&sort=$sort" + if(filter != "") + params+="&filter=$filter" var con=this._newCon("videos?$params","GET") var videos = arrayListOf() try { @@ -133,4 +138,21 @@ class Videos: Client() { } return videos } + + fun videoSubscriptions(token: String): ArrayList{ + var con=this._newCon("users/me/subscriptions/videos","GET", token) + var videos = arrayListOf() + try { + if (con.responseCode == 200) { + var response = InputStreamReader(con.inputStream) + var data = JsonReader(response) + videos = parseVideos(data) + } + } catch(err:Exception){ + err?.printStackTrace() + Log.d("TypeErr",err?.message ,err.cause) + Log.d("Error","fallo la coneccion") + } + return videos + } } \ No newline at end of file diff --git a/app/src/main/java/org/libre/agosto/p2play/models/VideoModel.kt b/app/src/main/java/org/libre/agosto/p2play/models/VideoModel.kt index 0513e56..22f7333 100644 --- a/app/src/main/java/org/libre/agosto/p2play/models/VideoModel.kt +++ b/app/src/main/java/org/libre/agosto/p2play/models/VideoModel.kt @@ -3,12 +3,15 @@ package org.libre.agosto.p2play.models import java.io.Serializable class VideoModel( - var name:String="", - var description:String="", - var thumbUrl:String="", - var userImageUrl:String="", - var embedUrl:String="", - var duration:Number=0, - var username:String="", - var views:Number=0 + var id: Int = 0, + var name: String = "", + var description: String = "", + var thumbUrl: String = "", + var userImageUrl: String = "", + var embedUrl: String = "", + var duration: Number = 0, + var username: String = "", + var views: Number = 0, + var userUuid: String = "", + var userHost: String = "" ):Serializable \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_dislike.xml b/app/src/main/res/drawable/ic_dislike.xml new file mode 100644 index 0000000..af897f3 --- /dev/null +++ b/app/src/main/res/drawable/ic_dislike.xml @@ -0,0 +1,21 @@ + + + + diff --git a/app/src/main/res/drawable/ic_like.xml b/app/src/main/res/drawable/ic_like.xml new file mode 100644 index 0000000..f1ad7c0 --- /dev/null +++ b/app/src/main/res/drawable/ic_like.xml @@ -0,0 +1,21 @@ + + + + diff --git a/app/src/main/res/drawable/ic_video_library_black_24dp.xml b/app/src/main/res/drawable/ic_video_library_black_24dp.xml new file mode 100644 index 0000000..f808aee --- /dev/null +++ b/app/src/main/res/drawable/ic_video_library_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_reproductor.xml b/app/src/main/res/layout/activity_reproductor.xml index 21f44ad..3eeb428 100644 --- a/app/src/main/res/layout/activity_reproductor.xml +++ b/app/src/main/res/layout/activity_reproductor.xml @@ -45,38 +45,78 @@ android:textSize="12sp" /> -