From 2de1bde4cdfd2661fbdf429893e5ba37bd996f8b Mon Sep 17 00:00:00 2001 From: Ivan Agosto Date: Thu, 28 Mar 2024 02:54:14 +0000 Subject: [PATCH] Feature/update video view --- app/build.gradle | 13 +++-- app/src/main/AndroidManifest.xml | 27 ++++++---- .../org/libre/agosto/p2play/MainActivity.kt | 6 +-- .../agosto/p2play/ReproductorActivity.kt | 8 ++- .../p2play/adapters/CommentariesAdapter.kt | 9 ++++ .../agosto/p2play/adapters/VideosAdapter.kt | 38 ++++++++------ .../org/libre/agosto/p2play/ajax/Client.kt | 3 -- .../libre/agosto/p2play/helpers/mapSeconds.kt | 20 ++++++++ .../agosto/p2play/models/CommentaryModel.kt | 9 +++- .../agosto/p2play/models/StreamingModel.kt | 25 +++++++++ .../libre/agosto/p2play/models/VideoModel.kt | 42 ++++++++++----- app/src/main/res/drawable/live_shape.xml | 14 +++++ app/src/main/res/drawable/round_text.xml | 14 +++++ app/src/main/res/layout/view_video.xml | 51 +++++++++++++++++-- app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values/colors.xml | 3 ++ app/src/main/res/values/strings.xml | 2 +- build.gradle | 4 +- gradle.properties | 3 ++ gradle/wrapper/gradle-wrapper.properties | 2 +- 20 files changed, 226 insertions(+), 68 deletions(-) create mode 100644 app/src/main/java/org/libre/agosto/p2play/helpers/mapSeconds.kt create mode 100644 app/src/main/java/org/libre/agosto/p2play/models/StreamingModel.kt create mode 100644 app/src/main/res/drawable/live_shape.xml create mode 100644 app/src/main/res/drawable/round_text.xml diff --git a/app/build.gradle b/app/build.gradle index cfda8bc..53b0094 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,14 +6,13 @@ plugins { } android { - compileSdkVersion 30 + compileSdkVersion 32 defaultConfig { applicationId "org.libre.agosto.p2play" minSdkVersion 26 - //noinspection OldTargetApi - targetSdkVersion 28 - versionCode 8 - versionName "0.5.2" + targetSdkVersion 32 + versionCode 9 + versionName "0.6.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { @@ -22,7 +21,6 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - buildToolsVersion '30.0.2' compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -31,6 +29,7 @@ android { checkReleaseBuilds false abortOnError false } + namespace 'org.libre.agosto.p2play' } dependencies { @@ -40,7 +39,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'com.google.android.material:material:1.4.0' + implementation 'com.google.android.material:material:1.6.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.5.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e83f1ca..1078c0e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + @@ -13,10 +12,12 @@ android:supportsRtl="true" android:theme="@style/Theme.P2play"> + android:theme="@style/Theme.P2play.NoActionBar" + android:exported="false" /> + android:theme="@style/Theme.P2play.NoActionBar" + android:exported="true"> @@ -25,22 +26,26 @@ + android:theme="@style/Theme.P2play.NoActionBar" + android:exported="false" /> + android:theme="@style/Theme.P2play.NoActionBar" + android:exported="false" /> - - - + android:theme="@style/Theme.P2play.NoActionBar" + android:exported="false" /> + + + + android:theme="@style/Theme.P2play" + android:exported="false"/> \ No newline at end of file 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 5d05638..7efe98b 100644 --- a/app/src/main/java/org/libre/agosto/p2play/MainActivity.kt +++ b/app/src/main/java/org/libre/agosto/p2play/MainActivity.kt @@ -50,8 +50,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte .setAction("Action", null).show() } */ - - val toggle = ActionBarDrawerToggle(this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) drawer_layout.addDrawerListener(toggle) toggle.syncState() @@ -376,6 +374,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte myMenu.findItem(R.id.action_logout).isVisible = true } + } else { + nav_view.menu.findItem(R.id.ml).isVisible = false } } @@ -394,7 +394,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte this.refresh() ManagerSingleton.Toast(getString(R.string.logout_msg), this) - + setSideData() } private fun loadMore(){ 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 dae39e9..c5df116 100644 --- a/app/src/main/java/org/libre/agosto/p2play/ReproductorActivity.kt +++ b/app/src/main/java/org/libre/agosto/p2play/ReproductorActivity.kt @@ -1,8 +1,6 @@ package org.libre.agosto.p2play import android.annotation.SuppressLint -import android.app.Activity -import android.content.DialogInterface import android.content.Intent import android.content.pm.ActivityInfo import android.graphics.Bitmap @@ -96,7 +94,7 @@ class ReproductorActivity : AppCompatActivity() { userImg.setOnClickListener { val intent = Intent(this, ChannelActivity::class.java) - intent.putExtra("channel", video.getAccount()) + intent.putExtra("channel", video.getChannel()) startActivity(intent) } } @@ -105,7 +103,7 @@ class ReproductorActivity : AppCompatActivity() { AsyncTask.execute { if (Looper.myLooper() == null) Looper.prepare() - val res = this._actions.subscribe(ManagerSingleton.token.token, video.getAccount()) + val res = this._actions.subscribe(ManagerSingleton.token.token, video.getChannel()) if (res == 1) { runOnUiThread { ManagerSingleton.Toast(getString(R.string.subscribeMsg), this) @@ -119,7 +117,7 @@ class ReproductorActivity : AppCompatActivity() { AsyncTask.execute { if (Looper.myLooper() == null) Looper.prepare() - val res = this._actions.unSubscribe(ManagerSingleton.token.token, video.getAccount()) + val res = this._actions.unSubscribe(ManagerSingleton.token.token, video.getChannel()) if (res == 1) { runOnUiThread { ManagerSingleton.Toast(getString(R.string.unSubscribeMsg), this) diff --git a/app/src/main/java/org/libre/agosto/p2play/adapters/CommentariesAdapter.kt b/app/src/main/java/org/libre/agosto/p2play/adapters/CommentariesAdapter.kt index be36410..b1b679c 100644 --- a/app/src/main/java/org/libre/agosto/p2play/adapters/CommentariesAdapter.kt +++ b/app/src/main/java/org/libre/agosto/p2play/adapters/CommentariesAdapter.kt @@ -1,6 +1,7 @@ package org.libre.agosto.p2play.adapters import android.content.Context +import android.content.Intent import androidx.recyclerview.widget.RecyclerView import android.text.Html import android.view.LayoutInflater @@ -9,6 +10,7 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import com.squareup.picasso.Picasso +import kotlinx.android.synthetic.main.view_video.view.userImg import org.libre.agosto.p2play.* import org.libre.agosto.p2play.models.CommentaryModel @@ -42,6 +44,7 @@ class CommentariesAdapter(private val myDataset: ArrayList) : // create a new view val view = LayoutInflater.from(parent.context) .inflate(R.layout.view_commentary, parent, false) as View + // set the view's size, margins, paddings and layout parameters return ViewHolder(view) } @@ -63,6 +66,12 @@ class CommentariesAdapter(private val myDataset: ArrayList) : holder.commentary.text = Html.fromHtml(myDataset[position].commentary) + // TODO: Support for view and account (is different than a video channel) + // holder.userImg.setOnClickListener { + // val intent = Intent(holder.context, ChannelActivity::class.java) + // intent.putExtra("channel", myDataset[position].getAccount()) + // holder.context.startActivity(intent) + // } } // Return the size of your dataset (invoked by the layout manager) diff --git a/app/src/main/java/org/libre/agosto/p2play/adapters/VideosAdapter.kt b/app/src/main/java/org/libre/agosto/p2play/adapters/VideosAdapter.kt index 169fa9f..de04ae0 100644 --- a/app/src/main/java/org/libre/agosto/p2play/adapters/VideosAdapter.kt +++ b/app/src/main/java/org/libre/agosto/p2play/adapters/VideosAdapter.kt @@ -10,6 +10,7 @@ import android.widget.ImageView import android.widget.TextView import com.squareup.picasso.Picasso import org.libre.agosto.p2play.* +import org.libre.agosto.p2play.helpers.mapSeconds import org.libre.agosto.p2play.models.VideoModel import java.io.Serializable @@ -27,6 +28,8 @@ class VideosAdapter(private val myDataset: ArrayList) : val tittle: TextView val description: TextView val context: Context + val duration: TextView + val isLive: TextView init { // Define click listener for the ViewHolder's View @@ -35,6 +38,8 @@ class VideosAdapter(private val myDataset: ArrayList) : thumb = view.findViewById(R.id.thumb) userImg = view.findViewById(R.id.userImg) context = view.context + duration = view.findViewById(R.id.duration) + isLive = view.findViewById(R.id.isLive) } } @@ -52,16 +57,17 @@ class VideosAdapter(private val myDataset: ArrayList) : // - get element from your dataset at this position // - replace the contents of the view with that element holder.tittle.text = myDataset[position].name + holder.tittle.setOnClickListener { + this.launchChannelActivity(myDataset[position] as Serializable, holder.context) + } Picasso.get().load("https://"+ManagerSingleton.url+myDataset[position].thumbUrl).into(holder.thumb) holder.thumb.setOnClickListener { - val intent = Intent(holder.context, ReproductorActivity::class.java) - intent.putExtra("video", myDataset[position] as Serializable) - holder.context.startActivity(intent) + this.launchChannelActivity(myDataset[position] as Serializable, holder.context) } holder.userImg.setOnClickListener { val intent = Intent(holder.context, ChannelActivity::class.java) - intent.putExtra("channel", myDataset[position].getAccount()) + intent.putExtra("channel", myDataset[position].getChannel()) holder.context.startActivity(intent) } @@ -71,20 +77,16 @@ class VideosAdapter(private val myDataset: ArrayList) : Picasso.get().load(R.drawable.default_avatar).into(holder.userImg) val viewsText = holder.context.getString(R.string.view_text) - var timeText = holder.context.getString(R.string.timeSec_text) - var timeString = myDataset[position].duration.toString() val seconds = myDataset[position].duration.toInt(); - if(seconds > 60 && seconds < (60 * 60)){ - timeText = holder.context.getString(R.string.timeMin_text) - timeString = (seconds / 60).toString() + ":" + (seconds % 60).toString() - } - else if(seconds > (60 * 60)){ - timeText = holder.context.getString(R.string.timeHrs_text) - timeString = (seconds / 60 / 60).toString() + ":" + (seconds / 60 % 60).toString() - } + val timeString = mapSeconds(seconds) - holder.description.text = myDataset[position].username+" - "+myDataset[position].views+" "+viewsText+" - "+timeString+" "+timeText + holder.duration.text = timeString + holder.description.text = myDataset[position].username+" - "+myDataset[position].views+" "+viewsText + + if (myDataset[position].isLive) { + holder.isLive.visibility = View.VISIBLE + } } // Return the size of your dataset (invoked by the layout manager) @@ -101,5 +103,9 @@ class VideosAdapter(private val myDataset: ArrayList) : notifyItemRangeInserted(lastPos, newItems.size) } - + private fun launchChannelActivity (data: Serializable, context: Context) { + val intent = Intent(context, ReproductorActivity::class.java) + intent.putExtra("video", data) + context.startActivity(intent) + } } \ No newline at end of file diff --git a/app/src/main/java/org/libre/agosto/p2play/ajax/Client.kt b/app/src/main/java/org/libre/agosto/p2play/ajax/Client.kt index 2a948f5..8a16998 100644 --- a/app/src/main/java/org/libre/agosto/p2play/ajax/Client.kt +++ b/app/src/main/java/org/libre/agosto/p2play/ajax/Client.kt @@ -10,8 +10,6 @@ import java.net.HttpURLConnection import java.net.URL open class Client { - - protected fun _newCon(uri: String, method: String, token: String = ""): HttpURLConnection { val url = URL("https://${ManagerSingleton.url}/api/v1/$uri") val con = url.openConnection() as HttpURLConnection @@ -67,5 +65,4 @@ open class Client { return keys } - } \ No newline at end of file diff --git a/app/src/main/java/org/libre/agosto/p2play/helpers/mapSeconds.kt b/app/src/main/java/org/libre/agosto/p2play/helpers/mapSeconds.kt new file mode 100644 index 0000000..fd99d08 --- /dev/null +++ b/app/src/main/java/org/libre/agosto/p2play/helpers/mapSeconds.kt @@ -0,0 +1,20 @@ +package org.libre.agosto.p2play.helpers + +fun mapSeconds (inputSeconds: Int): String { + val seconds = (inputSeconds % 60) + var minutes = inputSeconds / 60 + var hours = 0 + + if (minutes > 60) { + hours = minutes / 60 + minutes = minutes % 60 + } + + var result = minutes.toString().padStart(2, '0') + ":" + seconds.toString().padStart(2, '0') + + if (hours > 0) { + result = hours.toString().padStart(2, '0') + ":" + result + } + + return result +} \ No newline at end of file diff --git a/app/src/main/java/org/libre/agosto/p2play/models/CommentaryModel.kt b/app/src/main/java/org/libre/agosto/p2play/models/CommentaryModel.kt index 55543c2..cf83884 100644 --- a/app/src/main/java/org/libre/agosto/p2play/models/CommentaryModel.kt +++ b/app/src/main/java/org/libre/agosto/p2play/models/CommentaryModel.kt @@ -11,7 +11,8 @@ class CommentaryModel ( var userImageUrl: String = "", var commentary: String = "", var userHost: String = "", - var replies: Int = 0 + var replies: Int = 0, + var nameChannel: String = "" ) { fun parseCommentary(data: JsonReader) { data.beginObject() @@ -46,6 +47,7 @@ class CommentaryModel ( } "uuid" -> this.userUuid = data.nextString() "host" -> this.userHost = data.nextString() + "name" -> this.nameChannel = data.nextString() else -> data.skipValue() } } @@ -56,4 +58,9 @@ class CommentaryModel ( } data.endObject() } + + fun getAccount(): String { + return "$nameChannel@$userHost" + } + } \ No newline at end of file diff --git a/app/src/main/java/org/libre/agosto/p2play/models/StreamingModel.kt b/app/src/main/java/org/libre/agosto/p2play/models/StreamingModel.kt new file mode 100644 index 0000000..5438b5f --- /dev/null +++ b/app/src/main/java/org/libre/agosto/p2play/models/StreamingModel.kt @@ -0,0 +1,25 @@ +package org.libre.agosto.p2play.models + +import android.util.JsonReader + +class StreamingModel( + var playlistUrl: String = "", + var segmentsSha256Url: String = "", + // TODO: Download Files +) { + fun parse(data: JsonReader) { + data.beginObject() + while (data.hasNext()) { + val key = data.nextName() + when (key.toString()) { + "playlistUrl"->{ + this.playlistUrl = data.nextString() + } + "segmentsSha256Url"->{ + this.segmentsSha256Url = data.nextString() + } + else -> data.skipValue() + } + } + } +} \ 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 6059a94..5062faa 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 @@ -5,21 +5,23 @@ import android.util.JsonToken import java.io.Serializable class VideoModel( - var id: Int = 0, - var uuid: String = "", - 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 = "", - var nameChannel: String = "" + var id: Int = 0, + var uuid: String = "", + 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 = "", + var nameChannel: String = "", + var isLive: Boolean = false, + var streamingData: StreamingModel? = null ):Serializable { - fun getAccount(): String { + fun getChannel(): String { return "$nameChannel@$userHost" } @@ -55,6 +57,18 @@ class VideoModel( "views"->{ this.views = data.nextInt() } + "isLive"-> { + this.isLive = data.nextBoolean() + } + "streamingPlaylists"-> { + data.beginArray() + if (data.hasNext()) { + val streamingData = StreamingModel() + streamingData.parse(data) + this.streamingData = streamingData + } + data.endArray() + } "channel"->{ data.beginObject() while (data.hasNext()){ diff --git a/app/src/main/res/drawable/live_shape.xml b/app/src/main/res/drawable/live_shape.xml new file mode 100644 index 0000000..fd5f4ca --- /dev/null +++ b/app/src/main/res/drawable/live_shape.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/round_text.xml b/app/src/main/res/drawable/round_text.xml new file mode 100644 index 0000000..be16090 --- /dev/null +++ b/app/src/main/res/drawable/round_text.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/view_video.xml b/app/src/main/res/layout/view_video.xml index da37fc6..db6d5d6 100644 --- a/app/src/main/res/layout/view_video.xml +++ b/app/src/main/res/layout/view_video.xml @@ -14,11 +14,54 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> - + android:layout_height="match_parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + + + + + + minutos horas Inicia session + En vivo Te has desconectado diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 5d7a871..9d801f7 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -10,6 +10,9 @@ #FF3C9100 #ec020e #262626 + + #88000000 + #ffffff #f16805 #9F4200 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index af45e67..502467a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,7 +9,6 @@ Loading… - https://gitlab.com/agosto182/p2play/ https://personaljournal.ca/p2play/ @@ -60,6 +59,7 @@ hours Log In P2Play + Live You are now disconnected diff --git a/build.gradle b/build.gradle index 3c4e1cc..95cf88a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.6.20' + ext.kotlin_version = '1.6.21' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:8.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle.properties b/gradle.properties index ded9a9d..1974226 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,6 +9,9 @@ org.gradle.jvmargs=-Xmx1536m android.enableJetifier=true android.useAndroidX=true +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1bfc49c..24a0581 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon Mar 18 13:17:32 CST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists