39 Commits
v0.3 ... v0.5.2

Author SHA1 Message Date
ffbc491f4c update metadata 2024-03-19 22:04:26 -06:00
da1d3e301e Fix error getting local videos 2024-03-19 21:42:26 -06:00
6784b5ebbe Update fastlane descriptions 2024-03-18 19:24:57 -06:00
e70108a7ae Update README 2024-03-18 18:53:06 -06:00
2b7d92ac37 Merge branch 'updateAndroidSDK' into 'master'
Update android sdk

See merge request agosto182/p2play!11
2024-03-19 00:45:04 +00:00
4d337074fb Update android sdk 2024-03-19 00:45:04 +00:00
cd27342c74 Merge branch 'master' into 'master'
updated strings

See merge request agosto182/p2play!10
2024-03-18 17:23:49 +00:00
ab1bb48dcc updated strings 2024-03-18 17:23:49 +00:00
0a648ef4bb Merge branch 'master' into 'master'
Add Italian translation

See merge request agosto182/p2play!9
2020-06-26 21:00:36 +00:00
3e41ddd367 Add Italian translation 2020-06-26 21:00:36 +00:00
9c90983ff4 Merge branch 'patch-1' into 'master'
Update README.md

See merge request agosto182/p2play!8
2020-02-17 00:59:25 +00:00
dad366eebf Update README.md 2020-01-11 13:42:03 +00:00
14640a825f Merge branch 'development' into 'master'
0.5.1 version

See merge request agosto182/p2play!7
2019-12-13 15:56:33 +00:00
8fbfd57f78 Update new version 2019-12-13 09:55:42 -06:00
a66acfbcea Most liked videos 2019-12-13 09:53:10 -06:00
d410be7d4e Fastlane spanish lang 2019-11-01 09:13:26 -06:00
a26efeba63 Fastlane changes 2019-11-01 08:17:48 -06:00
49b7841a97 Fastlane added 2019-10-30 12:01:48 -06:00
7d6f364223 Merge branch 'development' into 'master'
P2play version 0.5

See merge request agosto182/p2play!6
2019-10-27 17:15:33 +00:00
390b1a7add Warning fixed and upgraded app version 2019-10-24 14:34:14 -05:00
904319674d Readme upgraded 2019-10-24 13:52:17 -05:00
c26ab0b8a2 Saving video views in history 2019-10-24 13:46:23 -05:00
9167977c7c Timeout up to 60 sec 2019-10-19 14:02:13 -05:00
8394484eb0 New logo p2play 2019-10-18 12:35:15 -05:00
4946a55215 Reordered menu, added history videos 2019-10-18 11:14:44 -05:00
9638468191 Kotlin core updated 2019-10-17 20:41:32 -05:00
b763ed2088 gradle updated 2019-03-18 20:59:38 -06:00
5c966fe81c But of profile image on logout fixed 2019-03-18 20:58:42 -06:00
23dfb98a67 Merge branch 'development' into 'master'
Development

See merge request agosto182/p2play!5
2019-02-27 15:22:19 +00:00
22a2772a3c Prerelease 0.4 2019-02-27 09:21:11 -06:00
abcf2f0e6e Report and share videos works 2019-02-24 20:53:40 -06:00
398265c6ed Channel view maked and working 2019-02-24 10:34:12 -06:00
743c3147c1 Models parse funcion added and channel model added 2019-02-23 15:14:56 -06:00
d360a1849e Show more fixed 2019-02-17 18:42:08 -06:00
90f2ab6e7d Trending videos added 2019-02-17 18:34:38 -06:00
d680eb77b8 Linting ajax files 2019-02-17 17:29:52 -06:00
90aac608be Option for show full description 2019-02-17 17:13:12 -06:00
2abdcb8375 Full screen bugs fixed 2019-02-17 14:29:33 -06:00
a6f3a4b6b4 Commentaries with html parsed 2019-02-16 00:33:54 -06:00
92 changed files with 1665 additions and 693 deletions

View File

@ -1,8 +1,12 @@
# P2Play # P2Play
P2Play is an Android Application for Peertube. P2Play is an unoficial Peertube android application.
[What is Peertube?](https://github.com/Chocobozzz/PeerTube/) [What is Peertube?](https://github.com/Chocobozzz/PeerTube/)
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/org.libre.agosto.p2play/)
## Screenshots ## Screenshots
![screenshot](screenshots/screenshot.png) ![screenshot](screenshots/screenshot.png)
@ -23,47 +27,50 @@ Comming soon!
## Features ## Features
- Show recent, popular and local list of videos. - Show recent, popular and local list of videos.
- Reproduce videos (very simple) - Reproduce videos
- Login and register in your instance - Login and register in your instance
- Pull to refresh
- Show uploaded videos - Show uploaded videos
- Subscribe to accounts - Subscribe to accounts
- Show your subscripcion videos - Show your subscripcion videos
- Show your history
- Rate videos - Rate videos
- Show and make commentaries - Show and make commentaries
- Splash screen - Splash screen
- Search videos - Search videos
- Infinite scroll - Infinite scroll
## What to do? (in next version)
- Share videos - Share videos
- Report videos - Report videos
- Peertube profiles - Peertube profiles
- History of videos watched
- Notifications ## What to do? (on incomming updates)
- Playlists
- Manage subscriptions
- Better commentaries
- New video player
## Demostrations ## Demostrations
Demostration P2play Beta 0.2: https://peertube.video/videos/watch/730fa68e-32c4-4cdb-a7bb-1a819c9d3a46 **Dead links**
Demostration P2Play Beta 0.1: https://peertube.video/videos/watch/2eb7b953-0b1b-4019-9300-817539f5f4e8 ~~Demostration P2play Beta 0.2: https://peertube.video/videos/watch/730fa68e-32c4-4cdb-a7bb-1a819c9d3a46~~
[Spanish] Demostracion P2Play Beta 0.1: https://peertube.video/videos/watch/d6a7da26-d3dd-43aa-ad5c-7d032603c848 ~~Demostration P2Play Beta 0.1: https://peertube.video/videos/watch/2eb7b953-0b1b-4019-9300-817539f5f4e8~~
~~[Spanish] Demostracion P2Play Beta 0.1: https://peertube.video/videos/watch/d6a7da26-d3dd-43aa-ad5c-7d032603c848~~
## Contact ## Contact
You can follow our accounts for get news and contact with the developers. You can follow our accounts to get news and contact with the developer(s).
- GNU Social: https://gnusocial.ml/p2play - WriteFreely (ActivityPub): https://personaljournal.ca/p2play/
- Peertube Channel: https://peertube.video/video-channels/90df4e5f-c834-4720-a5d7-c9faa0af0af5/videos
## About ## About
P2Play is made in Android Studio with Kotlin code. P2Play is made in Android Studio with Kotlin languaje.
![kotlin](https://weblizar.com/blog/wp-content/uploads/2017/11/Kotlin-A-New-Programming-Platform-For-Android-Developers.png) ![kotlin](https://weblizar.com/blog/wp-content/uploads/2017/11/Kotlin-A-New-Programming-Platform-For-Android-Developers.png)
### Developers ### Developers
- Ivan Agosto: [https://gnusocial.ml/agosto182](https://gnusocial.ml/agosto182) - Ivan Agosto: [https://mast.lat/@agosto182](https://mast.lat/@agosto182)
## License ## License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

View File

@ -1,17 +1,19 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' plugins {
id "com.android.application"
apply plugin: 'kotlin-android-extensions' id "kotlin-android"
id "kotlin-android-extensions"
}
android { android {
compileSdkVersion 27 compileSdkVersion 30
defaultConfig { defaultConfig {
applicationId "mx.agosto182.p2play" applicationId "org.libre.agosto.p2play"
minSdkVersion 21 minSdkVersion 26
targetSdkVersion 27 //noinspection OldTargetApi
versionCode 4 targetSdkVersion 28
versionName "0.3" versionCode 8
versionName "0.5.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
@ -20,10 +22,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
buildToolsVersion '28.0.3' buildToolsVersion '30.0.2'
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_6 targetCompatibility JavaVersion.VERSION_1_8
} }
lintOptions { lintOptions {
checkReleaseBuilds false checkReleaseBuilds false
@ -33,11 +35,11 @@ android {
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.0' implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation 'com.android.support.constraint:constraint-layout:2.0.4'
implementation 'com.android.support:support-v4:27.1.0' implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:design:27.1.0' implementation 'com.android.support:design:28.0.0'
implementation 'com.squareup.picasso:picasso:2.71828' implementation 'com.squareup.picasso:picasso:2.71828'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2'

View File

@ -7,11 +7,13 @@
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_p2play" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_p2play" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/P2playTheme"> android:theme="@style/P2playTheme">
<activity android:name=".ChannelActivity"
android:theme="@style/P2playTheme.noBar" />
<activity <activity
android:name=".SplashActivity" android:name=".SplashActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"> android:theme="@style/Theme.AppCompat.Light.NoActionBar">
@ -27,8 +29,9 @@
android:theme="@style/P2playTheme.NoActionBar" /> android:theme="@style/P2playTheme.NoActionBar" />
<activity <activity
android:name=".ReproductorActivity" android:name=".ReproductorActivity"
android:configChanges="orientation|screenSize"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:configChanges="orientation|screenSize"/> android:theme="@style/P2playTheme.noBar" />
<activity android:name=".LoginActivity" /> <activity android:name=".LoginActivity" />
<activity android:name=".RegisterActivity" /> <activity android:name=".RegisterActivity" />
<activity android:name=".AboutActivity" /> <activity android:name=".AboutActivity" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,149 @@
package org.libre.agosto.p2play
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.View
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_channel.*
import org.libre.agosto.p2play.adapters.VideosAdapter
import org.libre.agosto.p2play.ajax.Actions
import org.libre.agosto.p2play.ajax.Channels
import org.libre.agosto.p2play.ajax.Videos
import org.libre.agosto.p2play.models.ChannelModel
import org.libre.agosto.p2play.models.VideoModel
class ChannelActivity : AppCompatActivity() {
private lateinit var channelId: String
private lateinit var channel: ChannelModel
private var isSubcribed: Boolean = false
private val _channel = Channels()
private val _videos = Videos()
private val _actions = Actions()
private lateinit var recyclerView: RecyclerView
private lateinit var viewAdapter: RecyclerView.Adapter<VideosAdapter.ViewHolder>
private lateinit var viewManager: RecyclerView.LayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_channel)
channelId = this.intent.extras?.getString("channel")!!
viewManager = LinearLayoutManager(this)
subcriptionBtn.setOnClickListener {
subscribeAction()
}
}
override fun onResume() {
super.onResume()
getChannel()
getSubscription()
getVideos()
if(ManagerSingleton.user.status == 1) {
subcriptionBtn.visibility = View.VISIBLE
getSubscription()
}
}
private fun getChannel() {
AsyncTask.execute {
channel = _channel.getChannelInfo(channelId)
runOnUiThread {
usernameProfile.text = channel.name
hostTxt.text = channel.host
subcriptionsTxt.text = channel.followers.toString()
if(channel.channelImg != "")
Picasso.get().load("https://${ManagerSingleton.url}${channel.channelImg}").into(channelImg)
}
}
}
private fun subscribe() {
AsyncTask.execute {
val res = _actions.subscribe(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if(res == 1){
subcriptionBtn.text = getString(R.string.unSubscribeBtn)
ManagerSingleton.Toast(getString(R.string.subscribeMsg), this)
getSubscription()
}
else {
ManagerSingleton.Toast(getString(R.string.errorMsg), this)
}
}
}
}
private fun unSubscribe() {
AsyncTask.execute {
val res = _actions.unSubscribe(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if(res == 1){
subcriptionBtn.text = getString(R.string.subscribeBtn)
ManagerSingleton.Toast(getString(R.string.unSubscribeMsg), this)
getSubscription()
}
else {
ManagerSingleton.Toast(getString(R.string.errorMsg), this)
}
}
}
}
private fun subscribeAction() {
if(isSubcribed)
unSubscribe()
else
subscribe()
}
private fun getSubscription() {
AsyncTask.execute {
isSubcribed = _actions.getSubscription(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if(isSubcribed){
subcriptionBtn.text = getText(R.string.unSubscribeBtn)
}
else {
subcriptionBtn.text = getText(R.string.subscribeBtn)
}
}
}
}
private fun getVideos() {
AsyncTask.execute {
val videos = _videos.channelVideos(channel.getAccount(), 0)
runOnUiThread {
initRecycler(videos)
}
}
}
// Generic function for set data to RecyclerView
private fun initRecycler(data: ArrayList<VideoModel>){
// val data = arrayListOf<VideoModel>()
viewAdapter = VideosAdapter(data)
recyclerView = findViewById<RecyclerView>(R.id.listVideosChannel).apply {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
setHasFixedSize(true)
// use a linear layout manager
layoutManager = viewManager
// specify an viewAdapter (see also next example)
adapter = viewAdapter
}
// swipeContainer.isRefreshing = false
}
}

View File

@ -35,7 +35,7 @@ class HostActivity : AppCompatActivity() {
if(lastHost!=host){ if(lastHost!=host){
_db.logout() _db.logout()
ManagerSingleton.logout() ManagerSingleton.logout()
getKeys(host) getKeys(host!!)
}else{ }else{
ManagerSingleton.url=host ManagerSingleton.url=host
startApp() startApp()

View File

@ -25,8 +25,8 @@ class LoginActivity : AppCompatActivity() {
_db = Database(this) _db = Database(this)
settings = PreferenceManager.getDefaultSharedPreferences(this) settings = PreferenceManager.getDefaultSharedPreferences(this)
client_id = settings.getString("client_id", "") client_id = settings.getString("client_id", "")!!
client_secret = settings.getString("client_secret", "") client_secret = settings.getString("client_secret", "")!!
registerActionBtn.setOnClickListener { startActivity(Intent(this, RegisterActivity::class.java)) } registerActionBtn.setOnClickListener { startActivity(Intent(this, RegisterActivity::class.java)) }
loginBtn.setOnClickListener { tryLogin() } loginBtn.setOnClickListener { tryLogin() }

View File

@ -60,7 +60,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Init RecyclerView // Init RecyclerView
this.initRecycler() this.initRecycler()
this.getLastVideos() this.getTrengindVideos()
swipeContainer.setOnRefreshListener { swipeContainer.setOnRefreshListener {
this.refresh() this.refresh()
@ -89,8 +89,9 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
adapter = viewAdapter adapter = viewAdapter
this.addOnScrollListener(object : RecyclerView.OnScrollListener() { this.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy) super.onScrolled(recyclerView, dx, dy)
// super.onScrolled(recyclerView!!, dx, dy)
if(!swipeContainer.isRefreshing){ if(!swipeContainer.isRefreshing){
if(!canScrollVertically(1)){ if(!canScrollVertically(1)){
@ -127,6 +128,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
when(section){ when(section){
"local" -> this.getLocalVideos() "local" -> this.getLocalVideos()
"popular" -> this.getPopularVideos() "popular" -> this.getPopularVideos()
"trending" -> this.getTrengindVideos()
"last" -> this.getLastVideos() "last" -> this.getLastVideos()
"sub" -> this.getSubscriptionVideos() "sub" -> this.getSubscriptionVideos()
"search" -> this.searchVideos() "search" -> this.searchVideos()
@ -182,6 +184,19 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
} }
} }
// Trending videos
private fun getTrengindVideos(){
swipeContainer.isRefreshing = true
section = "trending"
setTitle(R.string.title_trending)
AsyncTask.execute {
val videos = client.getTrendingVideos(this.pagination)
runOnUiThread {
this.addVideos(videos)
}
}
}
// Local videos // Local videos
private fun getLocalVideos(){ private fun getLocalVideos(){
swipeContainer.isRefreshing = true swipeContainer.isRefreshing = true
@ -208,10 +223,40 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
} }
} }
// Videos history of user
private fun getHistory(){
swipeContainer.isRefreshing = true
section = "my_videos"
setTitle(R.string.nav_history)
AsyncTask.execute {
val videos = client.videoHistory(ManagerSingleton.token.token, this.pagination)
runOnUiThread {
this.addVideos(videos)
}
}
}
// Most liked
private fun getMostLiked(){
swipeContainer.isRefreshing = true
section = "liked"
setTitle(R.string.nav_likes)
AsyncTask.execute {
val videos = client.getMostLikedVideos(this.pagination)
runOnUiThread {
this.addVideos(videos)
}
}
}
override fun onBackPressed() { override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) { if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START) drawer_layout.closeDrawer(GravityCompat.START)
} else { }
else if(!section.equals("trending")) {
this.getTrengindVideos()
}
else {
super.onBackPressed() super.onBackPressed()
} }
} }
@ -286,22 +331,18 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// item.isChecked = true // item.isChecked = true
when (item.itemId) { when (item.itemId) {
R.id.nav_subscriptions->{ R.id.nav_subscriptions -> getSubscriptionVideos()
getSubscriptionVideos() R.id.nav_popular -> getPopularVideos()
} R.id.nav_trending -> getTrengindVideos()
R.id.nav_popular-> { R.id.nav_recent -> getLastVideos()
getPopularVideos() R.id.nav_local -> getLocalVideos()
} R.id.nav_about -> {
R.id.nav_recent-> {
getLastVideos()
}
R.id.nav_local-> {
getLocalVideos()
}
R.id.nav_about-> {
val intent = Intent(this, AboutActivity::class.java) val intent = Intent(this, AboutActivity::class.java)
startActivity(intent) startActivity(intent)
} }
R.id.nav_history -> getHistory()
R.id.nav_myVideos -> getMyVideos()
R.id.nav_likes -> getMostLiked()
} }
drawer_layout.closeDrawer(GravityCompat.START) drawer_layout.closeDrawer(GravityCompat.START)
@ -315,17 +356,22 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
private fun setSideData(){ private fun setSideData(){
if(ManagerSingleton.user.status == 1){ if(ManagerSingleton.user.status == 1){
nav_view.menu.findItem(R.id.ml).isVisible = true
side_usernameTxt?.text = ManagerSingleton.user.username side_usernameTxt?.text = ManagerSingleton.user.username
side_emailTxt?.text = ManagerSingleton.user.email side_emailTxt?.text = ManagerSingleton.user.email
if(ManagerSingleton.user.avatar!="" && side_imageView != null) if(ManagerSingleton.user.avatar!="" && side_imageView != null) {
Picasso.get().load("https://"+ManagerSingleton.url+ManagerSingleton.user.avatar).into(side_imageView) Picasso.get().load("https://" + ManagerSingleton.url + ManagerSingleton.user.avatar).into(side_imageView)
side_imageView?.setOnClickListener {
getMyVideos()
drawer_layout.closeDrawer(GravityCompat.START)
} }
// side_imageView?.setOnClickListener {
// pagination = 0
// getMyVideos()
// drawer_layout.closeDrawer(GravityCompat.START)
// }
if(::myMenu.isInitialized){ if(::myMenu.isInitialized){
myMenu.findItem(R.id.action_login).isVisible = false myMenu.findItem(R.id.action_login).isVisible = false
myMenu.findItem(R.id.action_logout).isVisible = true myMenu.findItem(R.id.action_logout).isVisible = true
} }
} }
} }
@ -335,10 +381,10 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
myMenu.findItem(R.id.action_login).isVisible = true myMenu.findItem(R.id.action_login).isVisible = true
myMenu.findItem(R.id.action_logout).isVisible = false myMenu.findItem(R.id.action_logout).isVisible = false
} }
nav_view.menu.findItem(R.id.ml).isVisible = false
side_usernameTxt?.text = getString(R.string.nav_header_title) side_usernameTxt?.text = getString(R.string.nav_header_title)
side_emailTxt?.text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName side_emailTxt?.text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
side_imageView?.setImageResource(R.mipmap.ic_launcher_round) side_imageView?.setImageResource(R.drawable.default_avatar)
side_imageView?.setOnClickListener { } side_imageView?.setOnClickListener { }
_db.logout() _db.logout()
ManagerSingleton.logout() ManagerSingleton.logout()
@ -355,6 +401,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
when(section){ when(section){
"local" -> this.getLocalVideos() "local" -> this.getLocalVideos()
"popular" -> this.getPopularVideos() "popular" -> this.getPopularVideos()
"trending" -> this.getTrengindVideos()
"last" -> this.getLastVideos() "last" -> this.getLastVideos()
"sub" -> this.getSubscriptionVideos() "sub" -> this.getSubscriptionVideos()
"search" -> this.searchVideos() "search" -> this.searchVideos()
@ -364,6 +411,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
else else
this.getLastVideos() this.getLastVideos()
} }
"liked" -> this.getMostLiked()
} }
} }

View File

@ -12,7 +12,6 @@ object ManagerSingleton {
var videos_count: Int = 0 var videos_count: Int = 0
fun Toast(text: String?, context: Context) { fun Toast(text: String?, context: Context) {
if(context == null) { return }
android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show() android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show()
} }

View File

@ -22,8 +22,8 @@ class RegisterActivity : AppCompatActivity() {
setTitle(R.string.registerActionBtn) setTitle(R.string.registerActionBtn)
settings = PreferenceManager.getDefaultSharedPreferences(this) settings = PreferenceManager.getDefaultSharedPreferences(this)
client_id = settings.getString("client_id", "") client_id = settings.getString("client_id", "")!!
client_secret = settings.getString("client_secret", "") client_secret = settings.getString("client_secret", "")!!
registerBtn.setOnClickListener { registerUser() } registerBtn.setOnClickListener { registerUser() }
} }

View File

@ -1,6 +1,10 @@
package org.libre.agosto.p2play package org.libre.agosto.p2play
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.ActivityInfo
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.os.AsyncTask import android.os.AsyncTask
@ -8,30 +12,41 @@ import android.support.v7.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.os.Looper import android.os.Looper
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.view.WindowManager
import android.webkit.WebChromeClient import android.webkit.WebChromeClient
import android.widget.EditText
import android.widget.FrameLayout import android.widget.FrameLayout
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_reproductor.* import kotlinx.android.synthetic.main.activity_reproductor.*
import org.libre.agosto.p2play.adapters.CommentariesAdapter import org.libre.agosto.p2play.adapters.CommentariesAdapter
import org.libre.agosto.p2play.ajax.Actions import org.libre.agosto.p2play.ajax.Actions
import org.libre.agosto.p2play.ajax.Comments import org.libre.agosto.p2play.ajax.Comments
import org.libre.agosto.p2play.ajax.Videos
import org.libre.agosto.p2play.models.CommentaryModel import org.libre.agosto.p2play.models.CommentaryModel
import org.libre.agosto.p2play.models.VideoModel import org.libre.agosto.p2play.models.VideoModel
@Suppress("NAME_SHADOWING")
class ReproductorActivity : AppCompatActivity() { class ReproductorActivity : AppCompatActivity() {
lateinit var video:VideoModel lateinit var video: VideoModel
private val _actions: Actions = Actions() private val _actions: Actions = Actions()
private val client: Comments = Comments() private val client: Comments = Comments()
private val videos: Videos = Videos()
// Commentaries adapter values // Commentaries adapter values
private lateinit var recyclerView: RecyclerView private lateinit var recyclerView: RecyclerView
private lateinit var viewAdapter: RecyclerView.Adapter<*> private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewManager: RecyclerView.LayoutManager private lateinit var viewManager: RecyclerView.LayoutManager
@SuppressLint("SetJavaScriptEnabled", "SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_reproductor) setContentView(R.layout.activity_reproductor)
@ -46,24 +61,25 @@ class ReproductorActivity : AppCompatActivity() {
videoView.settings.domStorageEnabled = true videoView.settings.domStorageEnabled = true
try { try {
this.video = this.intent.extras.getSerializable("video") as VideoModel this.video = this.intent.extras?.getSerializable("video") as VideoModel
tittleVideoTxt.text = this.video.name tittleVideoTxt.text = this.video.name
viewsTxt.text = this.video.views.toString() + ' ' + getString(R.string.view_text) viewsTxt.text = "${this.video.views} ${getString(R.string.view_text)}"
userTxt.text = this.video.username userTxt.text = this.video.username
descriptionVideoTxt.text = this.video.description.toString() descriptionVideoTxt.text = this.video.description
hostTxt.text = this.video.userHost.toString() val haveDescription = this.video.description.endsWith("...")
if (haveDescription) {
showMoreBtn.visibility = View.VISIBLE
}
hostTxt.text = this.video.userHost
// Check if user had profile image // Check if user had profile image
if(this.video.userImageUrl!="") if (this.video.userImageUrl != "")
Picasso.get().load("https://"+ManagerSingleton.url+this.video.userImageUrl).into(userImg) Picasso.get().load("https://" + ManagerSingleton.url + this.video.userImageUrl).into(userImg)
// Load the video // Load the video
videoView.loadUrl("https://"+ManagerSingleton.url+this.video.embedUrl) videoView.loadUrl("https://" + ManagerSingleton.url + this.video.embedUrl)
} catch (err: Exception) {
}
catch (err:Exception){
err.printStackTrace() err.printStackTrace()
Log.d("Error", err?.message)
} }
viewManager = LinearLayoutManager(this) viewManager = LinearLayoutManager(this)
@ -75,14 +91,22 @@ class ReproductorActivity : AppCompatActivity() {
likeLayout.setOnClickListener { rate("like") } likeLayout.setOnClickListener { rate("like") }
dislikeLayout.setOnClickListener { rate("dislike") } dislikeLayout.setOnClickListener { rate("dislike") }
commentaryBtn.setOnClickListener { makeComment() } commentaryBtn.setOnClickListener { makeComment() }
showMoreBtn.setOnClickListener { getDescription() }
shareLayout.setOnClickListener { shareIntent() }
reportLayout.setOnClickListener { reportIntent() }
userImg.setOnClickListener {
val intent = Intent(this, ChannelActivity::class.java)
intent.putExtra("channel", video.getAccount())
startActivity(intent)
}
} }
private fun subscribe(){ private fun subscribe() {
val account = this.video.nameChannel+"@"+this.video.userHost
AsyncTask.execute { AsyncTask.execute {
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
Looper.prepare() Looper.prepare()
val res = this._actions.subscribe(ManagerSingleton.token.token, account) val res = this._actions.subscribe(ManagerSingleton.token.token, video.getAccount())
if (res == 1) { if (res == 1) {
runOnUiThread { runOnUiThread {
ManagerSingleton.Toast(getString(R.string.subscribeMsg), this) ManagerSingleton.Toast(getString(R.string.subscribeMsg), this)
@ -92,12 +116,11 @@ class ReproductorActivity : AppCompatActivity() {
} }
} }
private fun unSubscribe(){ private fun unSubscribe() {
val account = this.video.nameChannel+"@"+this.video.userHost
AsyncTask.execute { AsyncTask.execute {
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
Looper.prepare() Looper.prepare()
val res = this._actions.unSubscribe(ManagerSingleton.token.token, account) val res = this._actions.unSubscribe(ManagerSingleton.token.token, video.getAccount())
if (res == 1) { if (res == 1) {
runOnUiThread { runOnUiThread {
ManagerSingleton.Toast(getString(R.string.unSubscribeMsg), this) ManagerSingleton.Toast(getString(R.string.unSubscribeMsg), this)
@ -107,7 +130,7 @@ class ReproductorActivity : AppCompatActivity() {
} }
} }
private fun rate(rate: String){ private fun rate(rate: String) {
AsyncTask.execute { AsyncTask.execute {
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
Looper.prepare() Looper.prepare()
@ -115,11 +138,10 @@ class ReproductorActivity : AppCompatActivity() {
if (res == 1) { if (res == 1) {
runOnUiThread { runOnUiThread {
ManagerSingleton.Toast(getString(R.string.rateMsg), this) ManagerSingleton.Toast(getString(R.string.rateMsg), this)
if(rate=="like"){ if (rate == "like") {
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike)) textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike))
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light)) textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
} } else if (rate == "dislike") {
else if(rate=="dislike"){
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.colorDislike)) textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.colorDislike))
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light)) textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
} }
@ -128,13 +150,13 @@ class ReproductorActivity : AppCompatActivity() {
} }
} }
private fun getRate(){ private fun getRate() {
AsyncTask.execute { AsyncTask.execute {
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
Looper.prepare() Looper.prepare()
val rate = this._actions.getRate(ManagerSingleton.token.token, this.video.id) val rate = this._actions.getRate(ManagerSingleton.token.token, this.video.id)
runOnUiThread { runOnUiThread {
when (rate){ when (rate) {
"like" -> { "like" -> {
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike)) textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike))
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light)) textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
@ -152,8 +174,8 @@ class ReproductorActivity : AppCompatActivity() {
} }
} }
private fun getSubscription(){ private fun getSubscription() {
val account = this.video.nameChannel+"@"+this.video.userHost val account = this.video.nameChannel + "@" + this.video.userHost
AsyncTask.execute { AsyncTask.execute {
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
Looper.prepare() Looper.prepare()
@ -164,12 +186,11 @@ class ReproductorActivity : AppCompatActivity() {
} }
} }
private fun changeSubscribeBtn(subscribed: Boolean){ private fun changeSubscribeBtn(subscribed: Boolean) {
if(subscribed){ if (subscribed) {
subscribeBtn.text = getText(R.string.unSubscribeBtn) subscribeBtn.text = getText(R.string.unSubscribeBtn)
subscribeBtn.setOnClickListener { this.unSubscribe() } subscribeBtn.setOnClickListener { this.unSubscribe() }
} } else {
else{
subscribeBtn.text = getText(R.string.subscribeBtn) subscribeBtn.text = getText(R.string.subscribeBtn)
subscribeBtn.setOnClickListener { this.subscribe() } subscribeBtn.setOnClickListener { this.subscribe() }
} }
@ -202,7 +223,7 @@ class ReproductorActivity : AppCompatActivity() {
} }
private fun makeComment() { private fun makeComment() {
if(commentaryText.text.toString() == ""){ if (commentaryText.text.toString() == "") {
ManagerSingleton.Toast(getString(R.string.emptyCommentaryMsg), this) ManagerSingleton.Toast(getString(R.string.emptyCommentaryMsg), this)
return return
} }
@ -214,8 +235,7 @@ class ReproductorActivity : AppCompatActivity() {
ManagerSingleton.Toast(getString(R.string.makedCommentaryMsg), this) ManagerSingleton.Toast(getString(R.string.makedCommentaryMsg), this)
commentaryText.text.clear() commentaryText.text.clear()
this.getComments() this.getComments()
} } else {
else {
ManagerSingleton.Toast(getString(R.string.errorCommentaryMsg), this) ManagerSingleton.Toast(getString(R.string.errorCommentaryMsg), this)
} }
} }
@ -224,14 +244,70 @@ class ReproductorActivity : AppCompatActivity() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if(ManagerSingleton.user.status == 1) { if (ManagerSingleton.user.status == 1) {
this.getRate() this.getRate()
this.getSubscription() this.getSubscription()
actionsLayout.visibility = View.VISIBLE actionsLayout.visibility = View.VISIBLE
subscribeBtn.visibility = View.VISIBLE subscribeBtn.visibility = View.VISIBLE
commentaryLayout.visibility = View.VISIBLE commentaryLayout.visibility = View.VISIBLE
if(ManagerSingleton.user.avatar != ""){ if (ManagerSingleton.user.avatar != "") {
Picasso.get().load("https://"+ManagerSingleton.url+ManagerSingleton.user.avatar).into(userImgCom) Picasso.get().load("https://" + ManagerSingleton.url + ManagerSingleton.user.avatar).into(userImgCom)
}
}
}
fun getDescription() {
AsyncTask.execute {
val fullDescription = this.videos.fullDescription(this.video.id)
runOnUiThread {
descriptionVideoTxt.text = fullDescription
showMoreBtn.visibility = View.GONE
}
}
}
private fun shareIntent() {
val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, "${video.name} ${video.getVideoUrl()}")
type = "text/plain"
}
startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.shareBtn)))
}
private fun reportIntent() {
val builder = AlertDialog.Builder(this)
// Get the layout inflater
val dialog = layoutInflater.inflate(R.layout.report_dialog, null)
val inputReason = dialog.findViewById<EditText>(R.id.reportText)
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
builder.setView(dialog)
// Add action buttons
.setPositiveButton(R.string.reportBtn) { _, _ ->
val reason = inputReason.text.toString()
reportVideo(reason)
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.run { cancel() }
}
val alertDialog = builder.create()
alertDialog.show()
}
private fun reportVideo(reason: String){
AsyncTask.execute {
val res = _actions.reportVideo(video.id, reason, ManagerSingleton.token.token)
runOnUiThread {
if(res) {
ManagerSingleton.Toast(getText(R.string.reportDialogMsg).toString(), this)
}
else {
ManagerSingleton.Toast(getText(R.string.errorMsg).toString(), this)
}
} }
} }
} }
@ -243,6 +319,10 @@ class ReproductorActivity : AppCompatActivity() {
private var mOriginalSystemUiVisibility: Int = 0 private var mOriginalSystemUiVisibility: Int = 0
override fun getDefaultVideoPoster(): Bitmap? { override fun getDefaultVideoPoster(): Bitmap? {
AsyncTask.execute {
this@ReproductorActivity._actions.watchVideo(this@ReproductorActivity.video.id, ManagerSingleton.token.token)
}
return if (mCustomView == null) { return if (mCustomView == null) {
null null
} else BitmapFactory.decodeResource(this@ReproductorActivity.resources, 2130837573) } else BitmapFactory.decodeResource(this@ReproductorActivity.resources, 2130837573)
@ -250,12 +330,22 @@ class ReproductorActivity : AppCompatActivity() {
override fun onHideCustomView() { override fun onHideCustomView() {
try { try {
(this@ReproductorActivity.window.decorView as FrameLayout).removeView(this.mCustomView) this@ReproductorActivity.nonFullScreen.visibility = View.VISIBLE
this@ReproductorActivity.fullScreen.visibility = View.GONE
this@ReproductorActivity.fullScreen.removeView(this.mCustomView)
this.mCustomView = null this.mCustomView = null
this@ReproductorActivity.window.decorView.systemUiVisibility = this.mOriginalSystemUiVisibility
this@ReproductorActivity.requestedOrientation = this.mOriginalOrientation this.mCustomViewCallback!!.onCustomViewHidden()
this.mCustomViewCallback?.onCustomViewHidden()
this.mCustomViewCallback = null this.mCustomViewCallback = null
this@ReproductorActivity.requestedOrientation = this.mOriginalOrientation
// this@ReproductorActivity.window.decorView.systemUiVisibility = this.mOriginalSystemUiVisibility
val attrs = this@ReproductorActivity.window.attributes
attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_FULLSCREEN.inv()
attrs.flags = attrs.flags and WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON.inv()
window.attributes = attrs
this@ReproductorActivity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
} }
catch (err: Exception){ catch (err: Exception){
err.printStackTrace() err.printStackTrace()
@ -272,13 +362,25 @@ class ReproductorActivity : AppCompatActivity() {
this.mOriginalSystemUiVisibility = this@ReproductorActivity.window.decorView.systemUiVisibility this.mOriginalSystemUiVisibility = this@ReproductorActivity.window.decorView.systemUiVisibility
this.mOriginalOrientation = this@ReproductorActivity.requestedOrientation this.mOriginalOrientation = this@ReproductorActivity.requestedOrientation
this.mCustomViewCallback = paramCustomViewCallback this.mCustomViewCallback = paramCustomViewCallback
(this@ReproductorActivity.window.decorView as FrameLayout).addView(this.mCustomView, FrameLayout.LayoutParams(-1, -1)) val match_parent = WindowManager.LayoutParams.MATCH_PARENT
this@ReproductorActivity.window.decorView.systemUiVisibility = 3846
this@ReproductorActivity.nonFullScreen.visibility = View.GONE
this@ReproductorActivity.fullScreen.visibility = View.VISIBLE
this@ReproductorActivity.fullScreen.addView(paramView, FrameLayout.LayoutParams(match_parent, match_parent))
val attrs = this@ReproductorActivity.window.attributes
attrs.flags = attrs.flags or WindowManager.LayoutParams.FLAG_FULLSCREEN
attrs.flags = attrs.flags or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
window.attributes = attrs
this@ReproductorActivity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE
this@ReproductorActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
} }
catch (err: Exception){ catch (err: Exception){
err.printStackTrace() err.printStackTrace()
} }
} }
} }
} }

View File

@ -25,7 +25,7 @@ class SplashActivity : AppCompatActivity() {
settings = PreferenceManager.getDefaultSharedPreferences(this) settings = PreferenceManager.getDefaultSharedPreferences(this)
ManagerSingleton.nfsw = settings.getBoolean("show_nfsw", false) ManagerSingleton.nfsw = settings.getBoolean("show_nfsw", false)
ManagerSingleton.videos_count = settings.getString("videos_count", "15").toInt() ManagerSingleton.videos_count = settings.getString("videos_count", "15")!!.toInt()
val host = settings.getString("hostP2play","") val host = settings.getString("hostP2play","")
@ -59,8 +59,8 @@ class SplashActivity : AppCompatActivity() {
if (token.status == 1 && user.status == 1) { if (token.status == 1 && user.status == 1) {
val client_id = settings.getString("client_id", "") val client_id = settings.getString("client_id", "")!!
val client_secret = settings.getString("client_secret", "") val client_secret = settings.getString("client_secret", "")!!
val newToken = client.refreshToken(token, client_id, client_secret) val newToken = client.refreshToken(token, client_id, client_secret)

View File

@ -6,6 +6,7 @@ import android.content.Intent
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.AsyncTask import android.os.AsyncTask
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.Html
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -13,16 +14,14 @@ import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import org.libre.agosto.p2play.MainActivity import org.libre.agosto.p2play.*
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.ReproductorActivity
import org.libre.agosto.p2play.models.CommentaryModel import org.libre.agosto.p2play.models.CommentaryModel
import org.libre.agosto.p2play.models.VideoModel import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStream import java.io.InputStream
import java.io.Serializable import java.io.Serializable
import java.net.URL import java.net.URL
@Suppress("DEPRECATION")
class CommentariesAdapter(private val myDataset: ArrayList<CommentaryModel>) : class CommentariesAdapter(private val myDataset: ArrayList<CommentaryModel>) :
RecyclerView.Adapter<CommentariesAdapter.ViewHolder>() { RecyclerView.Adapter<CommentariesAdapter.ViewHolder>() {
@ -62,10 +61,16 @@ class CommentariesAdapter(private val myDataset: ArrayList<CommentaryModel>) :
// - replace the contents of the view with that element // - replace the contents of the view with that element
holder.username.text = myDataset[position].username holder.username.text = myDataset[position].username
// holder.userImg.setOnClickListener {
// val intent = Intent(holder.context, ChannelActivity::class.java)
// intent.putExtra("channel", myDataset[position])
// holder.context.startActivity(intent)
// }
if(myDataset[position].userImageUrl!="") if(myDataset[position].userImageUrl!="")
Picasso.get().load("https://"+ManagerSingleton.url+myDataset[position].userImageUrl).into(holder.userImg); Picasso.get().load("https://"+ManagerSingleton.url+myDataset[position].userImageUrl).into(holder.userImg);
holder.commentary.text = myDataset[position].commentary holder.commentary.text = Html.fromHtml(myDataset[position].commentary)
} }

View File

@ -13,10 +13,7 @@ import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import org.libre.agosto.p2play.MainActivity import org.libre.agosto.p2play.*
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.ReproductorActivity
import org.libre.agosto.p2play.models.VideoModel import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStream import java.io.InputStream
import java.io.Serializable import java.io.Serializable
@ -69,6 +66,13 @@ class VideosAdapter(private val myDataset: ArrayList<VideoModel>) :
intent.putExtra("video", myDataset[position] as Serializable) intent.putExtra("video", myDataset[position] as Serializable)
holder.context.startActivity(intent) holder.context.startActivity(intent)
} }
holder.userImg.setOnClickListener {
val intent = Intent(holder.context, ChannelActivity::class.java)
intent.putExtra("channel", myDataset[position].getAccount())
holder.context.startActivity(intent)
}
if(myDataset[position].userImageUrl!="") if(myDataset[position].userImageUrl!="")
Picasso.get().load("https://"+ManagerSingleton.url+myDataset[position].userImageUrl).into(holder.userImg) Picasso.get().load("https://"+ManagerSingleton.url+myDataset[position].userImageUrl).into(holder.userImg)
else else

View File

@ -6,7 +6,7 @@ import java.io.InputStreamReader
class Actions: Client() { class Actions: Client() {
fun subscribe(token: String, account: String):Int{ fun subscribe(token: String, account: String):Int{
var con=this._newCon("users/me/subscriptions","POST", token) val con = this._newCon("users/me/subscriptions","POST", token)
val params:String= "uri=$account" val params:String= "uri=$account"
con.outputStream.write(params.toByteArray()) con.outputStream.write(params.toByteArray())
var response = 0 var response = 0
@ -21,11 +21,12 @@ class Actions: Client() {
response = -1 response = -1
} }
con.disconnect()
return response return response
} }
fun unSubscribe(token: String, account: String):Int{ fun unSubscribe(token: String, account: String):Int{
var con=this._newCon("users/me/subscriptions/$account","DELETE", token) val con = this._newCon("users/me/subscriptions/$account","DELETE", token)
var response = 0 var response = 0
try { try {
@ -38,17 +39,18 @@ class Actions: Client() {
response = -1 response = -1
} }
con.disconnect()
return response return response
} }
fun getSubscription(token: String, account: String): Boolean{ fun getSubscription(token: String, account: String): Boolean{
var con=this._newCon("users/me/subscriptions/exist?uris=$account","GET", token) val con = this._newCon("users/me/subscriptions/exist?uris=$account","GET", token)
var isSubscribed = false var isSubscribed = false
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
data.beginObject() data.beginObject()
while (data.hasNext()){ while (data.hasNext()){
val key = data.nextName() val key = data.nextName()
@ -61,6 +63,7 @@ class Actions: Client() {
} }
} }
} }
data.close()
} }
} }
catch (err: Exception){ catch (err: Exception){
@ -68,12 +71,13 @@ class Actions: Client() {
isSubscribed = false isSubscribed = false
} }
con.disconnect()
return isSubscribed return isSubscribed
} }
fun rate(token: String, id_video: Int, rate: String):Int{ fun rate(token: String, id_video: Int, rate: String):Int{
var con=this._newCon("videos/$id_video/rate","PUT", token) val con = this._newCon("videos/$id_video/rate","PUT", token)
val params:String= "rating=$rate" val params = "rating=$rate"
con.outputStream.write(params.toByteArray()) con.outputStream.write(params.toByteArray())
var response = 0 var response = 0
@ -87,17 +91,18 @@ class Actions: Client() {
response = -1 response = -1
} }
con.disconnect()
return response return response
} }
fun getRate(token: String, id_video: Int):String{ fun getRate(token: String, id_video: Int):String{
var con=this._newCon("users/me/videos/$id_video/rating","GET", token) val con = this._newCon("users/me/videos/$id_video/rating","GET", token)
var rating = "none" var rating = "none"
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
data.beginObject() data.beginObject()
while (data.hasNext()){ while (data.hasNext()){
val key = data.nextName() val key = data.nextName()
@ -110,6 +115,7 @@ class Actions: Client() {
} }
} }
} }
con.disconnect()
} }
} }
catch (err: Exception){ catch (err: Exception){
@ -117,7 +123,43 @@ class Actions: Client() {
rating = "none" rating = "none"
} }
con.disconnect()
return rating return rating
} }
fun reportVideo(videoId: Int, reason: String, token: String): Boolean {
val con = this._newCon("videos/$videoId/abuse", "POST", token)
val params = "reason=$reason"
con.outputStream.write(params.toByteArray())
var response = false
try {
if(con.responseCode == 200){
response = true
}
} catch (err: Exception) {
err.printStackTrace()
response = false
}
return response
}
fun watchVideo(videoId: Int, token: String): Boolean {
val con = this._newCon("videos/$videoId/watching", "PUT", token)
val params = "currentTime=1"
con.outputStream.write(params.toByteArray())
var response = false
try {
if(con.responseCode == 204){
response = true
}
} catch (err: Exception) {
err.printStackTrace()
response = false
}
return response
}
} }

View File

@ -10,19 +10,19 @@ import org.libre.agosto.p2play.models.UserModel
import java.io.InputStreamReader import java.io.InputStreamReader
class Auth: Client() { class Auth: Client() {
val stockParams = "grant_type=password" private val stockParams = "grant_type=password"
fun login(username: String, password: String, client_id: String, client_secret: String): TokenModel{ fun login(username: String, password: String, client_id: String, client_secret: String): TokenModel{
var con = this._newCon("users/token","POST") val con = this._newCon("users/token","POST")
val params:String= "$stockParams&username=$username&password=$password&client_id=$client_id&client_secret=$client_secret" val params = "$stockParams&username=$username&password=$password&client_id=$client_id&client_secret=$client_secret"
con.outputStream.write(params.toByteArray()) con.outputStream.write(params.toByteArray())
var token = TokenModel() val token = TokenModel()
try { try {
if(con.responseCode==200){ if(con.responseCode==200){
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
data.beginObject() data.beginObject()
while(data.hasNext()){ while(data.hasNext()){
@ -35,6 +35,7 @@ class Auth: Client() {
} }
data.endObject() data.endObject()
data.close()
token.status = 1 token.status = 1
} }
@ -47,12 +48,13 @@ class Auth: Client() {
token.status = 0 token.status = 0
} }
con.disconnect()
return token return token
} }
fun register(username: String, password: String, email: String): Int{ fun register(username: String, password: String, email: String): Int{
var con = this._newCon("users/register","POST") val con = this._newCon("users/register","POST")
val params:String= "username=$username&password=$password&email=$email" val params = "username=$username&password=$password&email=$email"
con.outputStream.write(params.toByteArray()) con.outputStream.write(params.toByteArray())
var response = 0 var response = 0
@ -67,20 +69,21 @@ class Auth: Client() {
response = -1 response = -1
} }
con.disconnect()
return response return response
} }
fun refreshToken(token: TokenModel, client_id: String, client_secret: String): TokenModel{ fun refreshToken(token: TokenModel, client_id: String, client_secret: String): TokenModel{
var con = this._newCon("users/token", "POST", token.token) val con = this._newCon("users/token", "POST", token.token)
val params:String = "refresh_token=${token.refresh_token}&response_type=code&grant_type=refresh_token&client_id=$client_id&client_secret=$client_secret" val params = "refresh_token=${token.refresh_token}&response_type=code&grant_type=refresh_token&client_id=$client_id&client_secret=$client_secret"
con.outputStream.write(params.toByteArray()) con.outputStream.write(params.toByteArray())
var token = TokenModel() // val token = TokenModel()
try { try {
if(con.responseCode==200){ if(con.responseCode==200){
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
data.beginObject() data.beginObject()
while(data.hasNext()){ while(data.hasNext()){
@ -93,6 +96,7 @@ class Auth: Client() {
} }
data.endObject() data.endObject()
data.close()
token.status = 1 token.status = 1
} }
@ -105,19 +109,19 @@ class Auth: Client() {
token.status = 0 token.status = 0
} }
con.disconnect()
return token return token
} }
fun me(token: String): UserModel{ fun me(token: String): UserModel{
var con = this._newCon("users/me","GET", token) val con = this._newCon("users/me","GET", token)
val user = UserModel()
var user = UserModel()
try { try {
if(con.responseCode==200){ if(con.responseCode==200){
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
data.beginObject() data.beginObject()
while(data.hasNext()){ while(data.hasNext()){
@ -159,6 +163,7 @@ class Auth: Client() {
} }
data.endObject() data.endObject()
data.close()
user.status = 1 user.status = 1
} }
@ -171,6 +176,7 @@ class Auth: Client() {
user.status = 0 user.status = 0
} }
con.disconnect()
return user return user
} }

View File

@ -0,0 +1,35 @@
package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import android.util.JsonToken
import org.libre.agosto.p2play.models.ChannelModel
import org.libre.agosto.p2play.models.CommentaryModel
import java.io.InputStreamReader
class Channels: Client() {
private fun parseChannel(data: JsonReader): ChannelModel{
val channel = ChannelModel()
data.close()
return channel
}
fun getChannelInfo(account: String): ChannelModel {
val con = this._newCon("video-channels/$account", "GET")
var channel = ChannelModel()
try {
if(con.responseCode == 200){
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
channel.parseChannel(data)
data.close()
}
}catch (err: Exception) {
err.printStackTrace()
}
return channel
}
}

View File

@ -1,11 +1,11 @@
package org.libre.agosto.p2play.ajax package org.libre.agosto.p2play.ajax
import android.content.SharedPreferences
import android.util.JsonReader import android.util.JsonReader
import android.util.Log import android.util.Log
import org.libre.agosto.p2play.ManagerSingleton import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.models.HostModel import org.libre.agosto.p2play.models.HostModel
import java.io.InputStreamReader import java.io.InputStreamReader
import java.io.Reader
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL
@ -13,22 +13,22 @@ open class Client {
protected fun _newCon(uri: String, method: String, token: String = ""): HttpURLConnection { protected fun _newCon(uri: String, method: String, token: String = ""): HttpURLConnection {
var url = URL("https://"+ManagerSingleton.url+"/api/v1/"+uri) val url = URL("https://${ManagerSingleton.url}/api/v1/$uri")
var con = url.openConnection() as HttpURLConnection val con = url.openConnection() as HttpURLConnection
con.setRequestProperty("User-Agent", "P2play/0.1") con.setRequestProperty("User-Agent", "P2play/0.5.3")
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
con.setRequestProperty("Accept", "*/*") con.setRequestProperty("Accept", "*/*")
if(token != ""){ if(token != ""){
con.setRequestProperty("Authorization", "Bearer ${token}") con.setRequestProperty("Authorization", "Bearer $token")
} }
con.requestMethod=method con.requestMethod=method
con.connectTimeout=10000 con.connectTimeout=60000
con.readTimeout=10000 con.readTimeout=60000
if(method.equals("POST")) if(method == "POST")
con.doOutput=true con.doOutput=true
Log.d("Petition", url.toString()) Log.d("Petition", url.toString())
@ -36,12 +36,12 @@ open class Client {
} }
fun getKeys():HostModel{ fun getKeys():HostModel{
var con=this._newCon("oauth-clients/local","GET") val con = this._newCon("oauth-clients/local","GET")
var keys = HostModel("","") val keys = HostModel("","")
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
data.beginObject() data.beginObject()
while (data.hasNext()) { while (data.hasNext()) {
val key = data.nextName() val key = data.nextName()
@ -57,13 +57,14 @@ open class Client {
} }
} }
} }
data.close()
} }
Log.d("Key",keys.client_id)
return keys
} catch(err:Exception){ } catch(err:Exception){
Log.d("Error",err.message) err.printStackTrace()
return keys
} }
con.disconnect()
return keys
} }

View File

@ -8,8 +8,8 @@ import java.io.InputStreamReader
class Comments: Client() { class Comments: Client() {
fun parseCommentaries(data: JsonReader): ArrayList<CommentaryModel> { private fun parseCommentaries(data: JsonReader): ArrayList<CommentaryModel> {
var commentaries = arrayListOf<CommentaryModel>() val commentaries = arrayListOf<CommentaryModel>()
data.beginObject() data.beginObject()
while (data.hasNext()){ while (data.hasNext()){
when(data.nextName()) { when(data.nextName()) {
@ -17,47 +17,7 @@ class Comments: Client() {
data.beginArray() data.beginArray()
while (data.hasNext()) { while (data.hasNext()) {
val comment = CommentaryModel() val comment = CommentaryModel()
data.beginObject() comment.parseCommentary(data)
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
"id" -> comment.id = data.nextInt()
"threadId" -> comment.threadId = data.nextInt()
"text" -> comment.commentary = data.nextString()
"totalReplies" -> comment.replies = data.nextInt()
"account" -> {
data.beginObject()
while (data.hasNext()){
val acKey = data.nextName()
when(acKey.toString()){
"displayName"-> comment.username=data.nextString()
"avatar"-> {
if(data.peek() == JsonToken.BEGIN_OBJECT){
data.beginObject()
while (data.hasNext()){
val avKey = data.nextName()
when(avKey){
"path"-> comment.userImageUrl = data.nextString()
else-> data.skipValue()
}
}
data.endObject()
}
else
data.skipValue()
}
"uuid" -> comment.userUuid = data.nextString()
"host" -> comment.userHost = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
}
else -> data.skipValue()
}
}
data.endObject()
commentaries.add(comment) commentaries.add(comment)
} }
data.endArray() data.endArray()
@ -76,37 +36,42 @@ class Comments: Client() {
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
commentaries = parseCommentaries(data) commentaries = parseCommentaries(data)
data.close()
} }
} catch(err:Exception){ } catch(err:Exception){
err?.printStackTrace() err.printStackTrace()
Log.d("TypeErr",err?.message ,err.cause)
Log.d("Error","fallo la coneccion")
} }
con.disconnect()
return commentaries return commentaries
} }
fun makeCommentary(token: String, videoId: Int, text: String): Boolean { fun makeCommentary(token: String, videoId: Int, text: String): Boolean {
val con = this._newCon("videos/$videoId/comment-threads", "POST", token) val con = this._newCon("videos/$videoId/comment-threads", "POST", token)
val params:String= "text=$text" val params = "text=$text"
con.outputStream.write(params.toByteArray()) con.outputStream.write(params.toByteArray())
var response: Boolean
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
return true con.disconnect()
response = true
} }
else{ else{
Log.d("Status", con.responseMessage) Log.d("Status", con.responseMessage)
response = false
} }
} }
catch (err: Exception){ catch (err: Exception){
err.printStackTrace() err.printStackTrace()
response = false
} }
return false con.disconnect()
return response
} }
} }

View File

@ -1,8 +1,6 @@
package org.libre.agosto.p2play.ajax package org.libre.agosto.p2play.ajax
import android.util.JsonReader import android.util.JsonReader
import android.util.JsonToken
import android.util.Log
import org.libre.agosto.p2play.ManagerSingleton import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.models.VideoModel import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStreamReader import java.io.InputStreamReader
@ -10,7 +8,7 @@ import java.io.InputStreamReader
class Videos: Client() { class Videos: Client() {
private fun parseVideos(data: JsonReader): ArrayList<VideoModel>{ private fun parseVideos(data: JsonReader): ArrayList<VideoModel>{
var videos = arrayListOf<VideoModel>() val videos = arrayListOf<VideoModel>()
data.beginObject() data.beginObject()
while (data.hasNext()){ while (data.hasNext()){
when(data.nextName()){ when(data.nextName()){
@ -18,68 +16,7 @@ class Videos: Client() {
data.beginArray() data.beginArray()
while (data.hasNext()) { while (data.hasNext()) {
val video = VideoModel() val video = VideoModel()
data.beginObject() video.parseVideo(data)
while (data.hasNext()){
val key = data.nextName()
when (key.toString()) {
"id"-> video.id = data.nextInt()
"name"->{
video.name= data.nextString()
}
"description"->{
if(data.peek() == JsonToken.STRING)
video.description = data.nextString()
else
data.skipValue()
}
"duration"->{
video.duration = data.nextInt()
}
"thumbnailPath"->{
video.thumbUrl = data.nextString()
}
"embedPath"->{
video.embedUrl = data.nextString()
}
"views"->{
video.views = data.nextInt()
}
"channel"->{
data.beginObject()
while (data.hasNext()){
val acKey = data.nextName()
when(acKey.toString()){
"displayName"-> video.username=data.nextString()
"avatar"-> {
if(data.peek() == JsonToken.BEGIN_OBJECT){
data.beginObject()
while (data.hasNext()){
val avKey = data.nextName()
when(avKey){
"path"-> video.userImageUrl = data.nextString()
else-> data.skipValue()
}
}
data.endObject()
}
else
data.skipValue()
}
"uuid" -> video.userUuid = data.nextString()
"host" -> video.userHost = data.nextString()
"name" -> video.nameChannel = data.nextString()
else-> data.skipValue()
}
}
data.endObject()
}
else->{
data.skipValue()
}
}
}
data.endObject()
videos.add(video) videos.add(video)
} }
data.endArray() data.endArray()
@ -92,23 +29,24 @@ class Videos: Client() {
return videos return videos
} }
private fun getVideos(start:Int, sort:String = "-publishedAt", filter:String = ""):ArrayList<VideoModel>{ private fun getVideos(start:Int, sort:String = "-publishedAt", isLocal:Boolean = false):ArrayList<VideoModel>{
val nsfw = ManagerSingleton.nfsw val nsfw = ManagerSingleton.nfsw
val count = ManagerSingleton.videos_count val count = ManagerSingleton.videos_count
var params = "start=$start&count=$count&sort=$sort&nsfw=$nsfw" var params = "start=$start&count=$count&sort=$sort&nsfw=$nsfw&isLocal=$isLocal"
if(filter != "")
params+="&filter=$filter" val con = this._newCon("videos?$params","GET")
var con=this._newCon("videos?$params","GET")
var videos = arrayListOf<VideoModel>() var videos = arrayListOf<VideoModel>()
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
videos = parseVideos(data) videos = parseVideos(data)
data.close()
} }
} catch(err:Exception){ } catch(err:Exception){
err?.printStackTrace() err.printStackTrace()
} }
con.disconnect()
return videos return videos
} }
@ -120,41 +58,75 @@ class Videos: Client() {
return this.getVideos(start,"-views") return this.getVideos(start,"-views")
} }
fun getTrendingVideos(start:Int = 0): ArrayList<VideoModel>{
return this.getVideos(start,"-trending")
}
fun getLocalVideos(start:Int = 0): ArrayList<VideoModel>{ fun getLocalVideos(start:Int = 0): ArrayList<VideoModel>{
return this.getVideos(start,"-publishedAt", "local") return this.getVideos(start,"-publishedAt", true)
} }
fun myVideos(token: String, start: Int = 0): ArrayList<VideoModel>{ fun myVideos(token: String, start: Int = 0): ArrayList<VideoModel>{
val count = ManagerSingleton.videos_count val count = ManagerSingleton.videos_count
val params = "start=$start&count=$count" val params = "start=$start&count=$count"
var con=this._newCon("users/me/videos?$params","GET", token) val con = this._newCon("users/me/videos?$params","GET", token)
var videos = arrayListOf<VideoModel>() var videos = arrayListOf<VideoModel>()
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
videos = parseVideos(data) videos = parseVideos(data)
data.close()
} }
} catch(err:Exception){ } catch(err:Exception){
err?.printStackTrace() err.printStackTrace()
} }
con.disconnect()
return videos return videos
} }
fun videoSubscriptions(token: String, start: Int = 0): ArrayList<VideoModel>{ fun videoSubscriptions(token: String, start: Int = 0): ArrayList<VideoModel>{
val count = ManagerSingleton.videos_count val count = ManagerSingleton.videos_count
val params = "start=$start&count=$count" val params = "start=$start&count=$count"
var con=this._newCon("users/me/subscriptions/videos?$params","GET", token) val con = this._newCon("users/me/subscriptions/videos?$params","GET", token)
var videos = arrayListOf<VideoModel>() var videos = arrayListOf<VideoModel>()
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
videos = parseVideos(data) videos = parseVideos(data)
data.close()
} else {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
print(data)
} }
} catch(err:Exception){ } catch(err:Exception){
err?.printStackTrace() err.printStackTrace()
} }
con.disconnect()
return videos
}
fun videoHistory(token: String, start: Int = 0): ArrayList<VideoModel>{
val count = ManagerSingleton.videos_count
val params = "start=$start&count=$count"
val con = this._newCon("users/me/history/videos?$params","GET", token)
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
}
} catch(err:Exception){
err.printStackTrace()
}
con.disconnect()
return videos return videos
} }
@ -162,17 +134,70 @@ class Videos: Client() {
val count = ManagerSingleton.videos_count val count = ManagerSingleton.videos_count
val nsfw = ManagerSingleton.nfsw val nsfw = ManagerSingleton.nfsw
val params = "search=$text&start=$start&count=$count&nsfw=$nsfw" val params = "search=$text&start=$start&count=$count&nsfw=$nsfw"
var con=this._newCon("search/videos?$params","GET") val con = this._newCon("search/videos?$params","GET")
var videos = arrayListOf<VideoModel>() var videos = arrayListOf<VideoModel>()
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {
var response = InputStreamReader(con.inputStream) val response = InputStreamReader(con.inputStream)
var data = JsonReader(response) val data = JsonReader(response)
videos = parseVideos(data) videos = parseVideos(data)
data.close()
} }
} catch(err:Exception){ } catch(err:Exception){
err?.printStackTrace() err.printStackTrace()
} }
con.disconnect()
return videos return videos
} }
fun fullDescription(videoId: Int): String{
val con = this._newCon("videos/$videoId/description","GET")
var description = ""
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while (data.hasNext()){
val name = data.nextName()
when(name){
"description" -> description = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
data.close()
}
} catch(err:Exception){
err.printStackTrace()
description = "Error!"
}
con.disconnect()
return description
}
fun channelVideos(account: String, start: Int): ArrayList<VideoModel> {
val count = ManagerSingleton.videos_count
val params = "start=$start&count=$count"
val con = this._newCon("video-channels/$account/videos?$params","GET")
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
}
} catch(err:Exception){
err.printStackTrace()
}
con.disconnect()
return videos
}
fun getMostLikedVideos(start:Int = 0): ArrayList<VideoModel>{
return this.getVideos(start,"-likes")
}
} }

View File

@ -0,0 +1,64 @@
package org.libre.agosto.p2play.models
import android.util.JsonReader
import android.util.JsonToken
class ChannelModel (
var id: Int = 0,
var url: String = "",
var nameChannel: String = "",
var followers: Int = 0,
var host: String = "",
var name: String = "",
var description: String = "",
var support: String = "",
var channelImg: String = ""
) {
fun getAccount(): String {
return "$nameChannel@$host"
}
fun parseChannel(data: JsonReader) {
data.beginObject()
while (data.hasNext()) {
when(data.nextName()){
"id" -> this.id = data.nextInt()
"url" -> this.url = data.nextString()
"name" -> this.nameChannel = data.nextString()
"host" -> this.host = data.nextString()
"followersCount" -> this.followers = data.nextInt()
"displayName" -> this.name = data.nextString()
"description" -> {
if(data.peek() == JsonToken.STRING)
this.description = data.nextString()
else
data.skipValue()
}
"support" -> {
if(data.peek() == JsonToken.STRING)
this.support = data.nextString()
else
data.skipValue()
}
"avatar" -> {
if(data.peek() == JsonToken.BEGIN_OBJECT){
data.beginObject()
while (data.hasNext()){
when(data.nextName()){
"path" -> this.channelImg = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
}
else
data.skipValue()
}
else -> data.skipValue()
}
}
data.endObject()
}
}

View File

@ -1,5 +1,8 @@
package org.libre.agosto.p2play.models package org.libre.agosto.p2play.models
import android.util.JsonReader
import android.util.JsonToken
class CommentaryModel ( class CommentaryModel (
var id: Int = 0, var id: Int = 0,
var threadId: Int = 0, var threadId: Int = 0,
@ -9,4 +12,48 @@ class CommentaryModel (
var commentary: String = "", var commentary: String = "",
var userHost: String = "", var userHost: String = "",
var replies: Int = 0 var replies: Int = 0
) ) {
fun parseCommentary(data: JsonReader) {
data.beginObject()
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
"id" -> this.id = data.nextInt()
"threadId" -> this.threadId = data.nextInt()
"text" -> this.commentary = data.nextString()
"totalReplies" -> this.replies = data.nextInt()
"account" -> {
data.beginObject()
while (data.hasNext()){
val acKey = data.nextName()
when(acKey.toString()){
"displayName"-> this.username=data.nextString()
"avatar"-> {
if(data.peek() == JsonToken.BEGIN_OBJECT){
data.beginObject()
while (data.hasNext()){
val avKey = data.nextName()
when(avKey){
"path"-> this.userImageUrl = data.nextString()
else-> data.skipValue()
}
}
data.endObject()
}
else
data.skipValue()
}
"uuid" -> this.userUuid = data.nextString()
"host" -> this.userHost = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
}
else -> data.skipValue()
}
}
data.endObject()
}
}

View File

@ -1,9 +1,12 @@
package org.libre.agosto.p2play.models package org.libre.agosto.p2play.models
import android.util.JsonReader
import android.util.JsonToken
import java.io.Serializable import java.io.Serializable
class VideoModel( class VideoModel(
var id: Int = 0, var id: Int = 0,
var uuid: String = "",
var name: String = "", var name: String = "",
var description: String = "", var description: String = "",
var thumbUrl: String = "", var thumbUrl: String = "",
@ -15,4 +18,78 @@ class VideoModel(
var userUuid: String = "", var userUuid: String = "",
var userHost: String = "", var userHost: String = "",
var nameChannel: String = "" var nameChannel: String = ""
):Serializable ):Serializable {
fun getAccount(): String {
return "$nameChannel@$userHost"
}
fun getVideoUrl(): String {
return "https://$userHost/videos/watch/$uuid"
}
fun parseVideo(data: JsonReader){
data.beginObject()
while (data.hasNext()){
val key = data.nextName()
when (key.toString()) {
"id"-> this.id = data.nextInt()
"uuid" -> this.uuid = data.nextString()
"name"->{
this.name= data.nextString()
}
"description"->{
if(data.peek() == JsonToken.STRING)
this.description = data.nextString()
else
data.skipValue()
}
"duration"->{
this.duration = data.nextInt()
}
"thumbnailPath"->{
this.thumbUrl = data.nextString()
}
"embedPath"->{
this.embedUrl = data.nextString()
}
"views"->{
this.views = data.nextInt()
}
"channel"->{
data.beginObject()
while (data.hasNext()){
val acKey = data.nextName()
when(acKey.toString()){
"displayName"-> this.username=data.nextString()
"avatar"-> {
if(data.peek() == JsonToken.BEGIN_OBJECT){
data.beginObject()
while (data.hasNext()){
val avKey = data.nextName()
when(avKey){
"path"-> this.userImageUrl = data.nextString()
else-> data.skipValue()
}
}
data.endObject()
}
else
data.skipValue()
}
"uuid" -> this.userUuid = data.nextString()
"host" -> this.userHost = data.nextString()
"name" -> this.nameChannel = data.nextString()
else-> data.skipValue()
}
}
data.endObject()
}
else->{
data.skipValue()
}
}
}
data.endObject()
}
}

View File

@ -1,34 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12.8716,3.5097L12,1.9603L11.1284,3.5097L2.1284,19.5097L1.2902,21L3,21L21,21L22.7098,21L21.8716,19.5097L12.8716,3.5097Z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:fillType="evenOdd"/>
<path
android:pathData="M12,17.75C12.6904,17.75 13.25,17.1904 13.25,16.5C13.25,15.8096 12.6904,15.25 12,15.25C11.3096,15.25 10.75,15.8096 10.75,16.5C10.75,17.1904 11.3096,17.75 12,17.75Z"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M12,9L12,9A1,1 0,0 1,13 10L13,13A1,1 0,0 1,12 14L12,14A1,1 0,0 1,11 13L11,10A1,1 0,0 1,12 9z"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
</vector>

View File

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M21,6h-7.59l3.29,-3.29L16,2l-4,4 -4,-4 -0.71,0.71L10.59,6L3,6c-1.1,0 -2,0.89 -2,2v12c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,8c0,-1.11 -0.9,-2 -2,-2zM21,20L3,20L3,8h18v12zM9,10v8l7,-4z"/>
</vector>

View File

@ -0,0 +1,29 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M20,15L20,18.0026C20,19.1057 19.1074,20 18.0049,20L5.9951,20C4.8932,20 4,19.1074 4,18.0049L4,5.9951C4,4.8932 4.8959,4 5.9974,4L9,4"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M13,4l7.0208,0l0,7.0191"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
android:pathData="M19,5L12,12"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M1,21h4L5,9L1,9v12zM23,10c0,-1.1 -0.9,-2 -2,-2h-6.31l0.95,-4.57 0.03,-0.32c0,-0.41 -0.17,-0.79 -0.44,-1.06L14.17,1 7.59,7.59C7.22,7.95 7,8.45 7,9v10c0,1.1 0.9,2 2,2h9c0.83,0 1.54,-0.5 1.84,-1.22l3.02,-7.05c0.09,-0.23 0.14,-0.47 0.14,-0.73v-1.91l-0.01,-0.01L23,10z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M16,6l2.29,2.29 -4.88,4.88 -4,-4L2,16.59 3.41,18l6,-6 4,4 6.3,-6.29L22,12V6z"/>
</vector>

View File

@ -27,7 +27,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="Logo" android:contentDescription="Logo"
app:srcCompat="@drawable/icon" /> app:srcCompat="@mipmap/ic_launcher" />
<Space <Space
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".ChannelActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorProfile"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingTop="20dp"
android:paddingBottom="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="@+id/channelImg"
android:layout_width="match_parent"
android:layout_height="70dp"
android:adjustViewBounds="false"
android:background="@android:color/transparent"
android:contentDescription="@string/app_name"
android:cropToPadding="false"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<TextView
android:id="@+id/usernameProfile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="@android:color/white" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/followersIndicator"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textStyle="bold" />
<TextView
android:id="@+id/subcriptionsTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="textStart"
android:textColor="@android:color/white" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/hostIndicator"
android:textAlignment="center"
android:textColor="@android:color/white"
android:textStyle="bold" />
<TextView
android:id="@+id/hostTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="textStart"
android:textColor="@android:color/white" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/subcriptionBtn"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/subscribeBtn"
android:textAlignment="center"
android:visibility="invisible" />
</LinearLayout>
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2"
tools:layout_editor_absoluteX="0dp">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Videos:"
android:textStyle="bold"
tools:layout_editor_absoluteX="176dp"
tools:layout_editor_absoluteY="214dp" />
</FrameLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/listVideosChannel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
</LinearLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>

View File

@ -6,7 +6,18 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".ReproductorActivity"> tools:context=".ReproductorActivity">
<RelativeLayout
android:id="@+id/fullScreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:visibility="gone" />
<ScrollView <ScrollView
android:id="@+id/nonFullScreen"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
@ -113,21 +124,61 @@
android:textAlignment="center" /> android:textAlignment="center" />
</LinearLayout> </LinearLayout>
<Button <LinearLayout
android:id="@+id/button4" android:id="@+id/reportLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_weight="1" android:layout_weight="1"
android:text="@string/shareBtn" android:orientation="vertical"
android:visibility="gone" /> android:visibility="visible">
<Button <ImageView
android:id="@+id/button3" android:id="@+id/imageViewAlert"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/dislikeBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_alert" />
<TextView
android:id="@+id/textViewAlert"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/reportBtn"
android:textAlignment="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/shareLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_weight="1" android:layout_weight="1"
android:text="@string/reportBtn" android:orientation="vertical"
android:visibility="gone" /> android:visibility="visible">
<ImageView
android:id="@+id/imageViewShare"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/dislikeBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_share" />
<TextView
android:id="@+id/textViewShare"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/shareBtn"
android:textAlignment="center" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -145,7 +196,7 @@
android:adjustViewBounds="false" android:adjustViewBounds="false"
android:cropToPadding="false" android:cropToPadding="false"
android:padding="5dp" android:padding="5dp"
android:scaleType="centerInside" android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" /> app:srcCompat="@drawable/default_avatar" />
<LinearLayout <LinearLayout
@ -180,7 +231,7 @@
android:layout_weight="1" android:layout_weight="1"
android:text="@string/subscribeBtn" android:text="@string/subscribeBtn"
android:textSize="10sp" android:textSize="10sp"
android:visibility="visible" /> android:visibility="invisible" />
</LinearLayout> </LinearLayout>
<TextView <TextView
@ -190,12 +241,15 @@
android:maxLength="1000" android:maxLength="1000"
android:maxLines="100" android:maxLines="100"
android:paddingLeft="5dp" android:paddingLeft="5dp"
android:text="@string/descriptionTxt" /> android:text="@string/descriptionTxt"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/descriptionVideoTxt" android:id="@+id/descriptionVideoTxt"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:autoLink="web" android:autoLink="web"
android:linksClickable="true" android:linksClickable="true"
android:maxLength="10000" android:maxLength="10000"
@ -203,6 +257,15 @@
android:paddingLeft="10dp" android:paddingLeft="10dp"
android:paddingRight="10dp" /> android:paddingRight="10dp" />
<Button
android:id="@+id/showMoreBtn"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/showMore"
android:visibility="gone" />
<View <View
android:id="@+id/divider" android:id="@+id/divider"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -211,14 +274,16 @@
<Space <Space
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="30dp" /> android:layout_height="10dp"
android:layout_weight="1" />
<TextView <TextView
android:id="@+id/commentariesTxt" android:id="@+id/commentariesTxt"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="5dp" android:paddingLeft="5dp"
android:text="@string/commentariesTxt" /> android:text="@string/commentariesTxt"
android:textStyle="bold" />
<Space <Space
android:layout_width="match_parent" android:layout_width="match_parent"
@ -268,7 +333,6 @@
android:id="@+id/listCommentaries" android:id="@+id/listCommentaries"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:scrollbars="none"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />

View File

@ -27,7 +27,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/app_name" android:contentDescription="@string/app_name"
app:srcCompat="@drawable/icon" /> app:srcCompat="@mipmap/ic_launcher" />
<Space <Space
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="10dp" >
<TextView
android:id="@+id/reportTxt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/reportDialog"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/reportText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine">
<requestFocus />
</EditText>
</LinearLayout>

View File

@ -19,6 +19,7 @@
android:layout_height="60dp" android:layout_height="60dp"
android:layout_weight="1" android:layout_weight="1"
android:contentDescription="@string/app_name" android:contentDescription="@string/app_name"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" /> app:srcCompat="@drawable/default_avatar" />
<LinearLayout <LinearLayout

View File

@ -34,7 +34,7 @@
android:clickable="false" android:clickable="false"
android:cropToPadding="false" android:cropToPadding="false"
android:padding="5dp" android:padding="5dp"
android:scaleType="centerInside" android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" /> app:srcCompat="@drawable/default_avatar" />
<LinearLayout <LinearLayout

View File

@ -4,18 +4,42 @@
tools:showIn="navigation_view"> tools:showIn="navigation_view">
<item <item
android:id="@+id/ai" android:id="@+id/ml"
android:icon="@android:color/darker_gray" android:icon="@android:color/darker_gray"
android:title="Videos"> android:title="@string/nav_menu_myLibrary"
android:visible="false">
<menu> <menu>
<item <item
android:id="@+id/nav_subscriptions" android:id="@+id/nav_myVideos"
android:icon="@drawable/ic_video_library_black_24dp" android:icon="@drawable/ic_video_library_black_24dp"
android:title="@string/title_myVideos" />
<item
android:id="@+id/nav_subscriptions"
android:icon="@drawable/ic_live_tv_black_24dp"
android:title="@string/nav_subscriptions" /> android:title="@string/nav_subscriptions" />
<item
android:id="@+id/nav_history"
android:icon="@drawable/ic_history_black_24dp"
android:title="@string/nav_history" />
</menu>
</item>
<item
android:id="@+id/ai"
android:icon="@android:color/darker_gray"
android:title="@string/nav_menu_videos">
<menu>
<item <item
android:id="@+id/nav_popular" android:id="@+id/nav_popular"
android:icon="@android:drawable/btn_star" android:icon="@android:drawable/btn_star"
android:title="@string/nav_popular" /> android:title="@string/nav_popular" />
<item
android:id="@+id/nav_trending"
android:icon="@drawable/ic_trending_up_black_24dp"
android:title="@string/nav_trending" />
<item
android:id="@+id/nav_likes"
android:icon="@drawable/ic_thumb_up_black_24dp"
android:title="@string/nav_likes" />
<item <item
android:id="@+id/nav_recent" android:id="@+id/nav_recent"
android:icon="@drawable/ic_add_circle_black_24dp" android:icon="@drawable/ic_add_circle_black_24dp"
@ -30,7 +54,7 @@
<item <item
android:id="@+id/aiao" android:id="@+id/aiao"
android:icon="@android:color/white" android:icon="@android:color/white"
android:title="More"> android:title="@string/nav_menu_more">
<menu> <menu>
<item <item
android:id="@+id/nav_about" android:id="@+id/nav_about"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" /> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" /> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 947 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -8,7 +8,7 @@
<!-- Start About strings --> <!-- Start About strings -->
<string name="aboutLabel">Sobre P2Play</string> <string name="aboutLabel">Sobre P2Play</string>
<string name="aboutText">P2Play es una aplicacion no-oficial de PeerTube. Tu puedes ver y cntribuir con el codigo en GitLab:</string> <string name="aboutText">P2Play es una aplicacion no-oficial de PeerTube. Tu puedes ver y cntribuir con el codigo en GitLab:</string>
<string name="aboutStatus">Puedes subscribirte a nuestro perfil en GNU Social:</string> <string name="aboutStatus">Puedes seguir nuestro blog:</string>
<string name="aboutLicense">Copyleft GNU GPLv3 License</string> <string name="aboutLicense">Copyleft GNU GPLv3 License</string>
<string name="aboutInstance">Sobre la instancia</string> <string name="aboutInstance">Sobre la instancia</string>
<string name="aboutInWeb">Para ver los terminos y mas visita la web:</string> <string name="aboutInWeb">Para ver los terminos y mas visita la web:</string>
@ -56,6 +56,10 @@
<string name="nav_local">Local</string> <string name="nav_local">Local</string>
<string name="nav_about">Sobre</string> <string name="nav_about">Sobre</string>
<string name="nav_subscriptions">Suscripciones</string> <string name="nav_subscriptions">Suscripciones</string>
<string name="nav_history">Historial</string>
<string name="nav_menu_myLibrary">Mi libreria</string>
<string name="nav_menu_videos">Videos</string>
<string name="nav_menu_more">Mas</string>
<!-- End Menu strings --> <!-- End Menu strings -->
<!-- Start MiniMenu strings --> <!-- Start MiniMenu strings -->
<string name="action_settings">Configuracion</string> <string name="action_settings">Configuracion</string>
@ -91,6 +95,14 @@
<string name="pref_hostname_title">Instancia Peertube</string> <string name="pref_hostname_title">Instancia Peertube</string>
<string name="pref_message_exit">Reinicia para aplicar los cambios</string> <string name="pref_message_exit">Reinicia para aplicar los cambios</string>
<string name="pref_videos_count_title">Videos por pagina</string> <string name="pref_videos_count_title">Videos por pagina</string>
<string name="showMore">Mostrar mas</string>
<string name="nav_trending">Tendencias</string>
<string name="title_trending">Tendencias</string>
<string name="followersIndicator">Seguidores:</string>
<string name="hostIndicator">Host:</string>
<string name="reportDialog">Razon para reportar:</string>
<string name="reportDialogMsg">Has reportado el video</string>
<string name="nav_likes">Mas gustados</string>
<!-- End Settings strings --> <!-- End Settings strings -->
</resources> </resources>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="comming">In arrivo!</string>
<string name="charging">Caricamento...</string>
<string name="aboutLabel">Informazioni su P2Play</string>
<string name="aboutText">P2Play è un\'applicazione Android non ufficiale per PeerTube. Puoi visualizzare e contribuire al codice su GitLab:</string>
<string name="aboutStatus">Puoi seguire il nostro blog:</string>
<string name="aboutLicense">Copyleft GNU GPLv3 License</string>
<string name="aboutInstance">Informazioni sull\'istanza</string>
<string name="aboutInWeb">Puoi vedere in termini ed altro sul web:</string>
<string name="hostInfoText">Scegliere l\'istanza</string>
<string name="okButton">Accetta</string>
<string name="errorMsg">Errore, prova di nuovo</string>
<string name="finallyMsg">Istanza salvata</string>
<string name="loginInfo">Accedere o registrare un nuovo account</string>
<string name="userTxt">Utente:</string>
<string name="passwordTxt">Password:</string>
<string name="loginBtn">Accedere ora</string>
<string name="registerActionBtn">Creare un account</string>
<string name="loginSuccess_msg">Accesso effettuato</string>
<string name="loginError_msg">È stato rilevato un errore</string>
<string name="loginFailed_msg">Credenziali invalide</string>
<string name="registerSuccess_msg">Registrazione effettuata</string>
<string name="registerError_msg">È stato rilevato un errore</string>
<string name="registerFailed_msg">Dati non validi</string>
<string name="registerBtn">Registrarsi ora</string>
<string name="emailTxt">Email:</string>
<string name="title_subscriptions">Iscrizioni</string>
<string name="title_recent">Recenti</string>
<string name="title_popular">Popolari</string>
<string name="title_trending">Di tendenza</string>
<string name="title_local">Video locali</string>
<string name="title_myVideos">I miei video</string>
<string name="view_text">visualizzazioni</string>
<string name="timeSec_text">secondi</string>
<string name="timeMin_text">minuti</string>
<string name="timeHrs_text">ore</string>
<string name="nav_header_title">Accedere</string>
<string name="nav_subscriptions">Iscrizioni</string>
<string name="logout_msg">Ti sei disconnesso</string>
<string name="nav_popular">Popolari</string>
<string name="nav_trending">Di tendenza</string>
<string name="nav_recent">Recenti</string>
<string name="nav_local">Locali</string>
<string name="nav_about">Informazioni</string>
<string name="nav_history">Cronologia</string>
<string name="nav_menu_myLibrary">La mia libreria</string>
<string name="nav_menu_videos">Video</string>
<string name="nav_menu_more">Di più</string>
<string name="nav_likes">Più piaciuti</string>
<string name="action_settings">Impostazioni</string>
<string name="action_login">Accedere</string>
<string name="action_logout">Uscire</string>
<string name="descriptionTxt">Descrizione:</string>
<string name="commentariesTxt">Commenti:</string>
<string name="commentHolder">Lascia un commento</string>
<string name="subscribeBtn">Iscriversi</string>
<string name="likeBtn">Mi piace</string>
<string name="dislikeBtn">Non mi piace</string>
<string name="shareBtn">Condividere</string>
<string name="reportBtn">Segnalare</string>
<string name="unSubscribeBtn">Annulla iscrizione</string>
<string name="commentaryText">Commentare</string>
<string name="showMore">Mostra di più</string>
<string name="subscribeMsg">Ti sei iscritto a questo canale</string>
<string name="rateMsg">Hai valutato il video</string>
<string name="unSubscribeMsg">Hai annullato l\'iscrizione a questo canale</string>
<string name="makedCommentaryMsg">Hai commentato questo video</string>
<string name="errorCommentaryMsg">È stato rilevato un errore, riprovare</string>
<string name="emptyCommentaryMsg">Per favore, lascia prima un commento</string>
<string name="title_activity_settings">Impostazioni</string>
<string name="pref_header_general">Generali</string>
<string name="pref_nfsw_title">Contenuti NSFW</string>
<string name="pref_nfsw_description">Se attivo, può mostrare contenuti sensibili o per adulti.</string>
<string name="pref_hostname_title">Istanza Peertube</string>
<string name="pref_message_exit">Riaprire l\'app per rendere effettive le modifiche</string>
<string name="pref_videos_count_title">Video per pagina</string>
<string name="followersIndicator">Seguaci:</string>
<string name="hostIndicator">Host:</string>
<string name="reportDialog">Motivo per la segnalazione di questo video:</string>
<string name="reportDialogMsg">Hai segnalato il video</string>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#E95921</color>
</resources>

View File

@ -6,16 +6,16 @@
<string name="navigation_drawer_close" translatable="false">Close navigation drawer</string> <string name="navigation_drawer_close" translatable="false">Close navigation drawer</string>
<string name="nav_header_desc" translatable="false">Navigation header</string> <string name="nav_header_desc" translatable="false">Navigation header</string>
<string name="comming">Coming soon!</string> <string name="comming">Coming soon!</string>
<string name="charging">Loading...</string> <string name="charging">Loading</string>
<!-- End Global string --> <!-- End Global string -->
<!-- Start About strings --> <!-- Start About strings -->
<string name="aboutGitUrl" translatable="false">https://gitlab.com/agosto182/p2play/</string> <string name="aboutGitUrl" translatable="false">https://gitlab.com/agosto182/p2play/</string>
<string name="aboutGnuUrl" translatable="false">https://gnusocial.ml/p2play</string> <string name="aboutGnuUrl" translatable="false">https://personaljournal.ca/p2play/</string>
<string name="aboutLabel">About P2Play</string> <string name="aboutLabel">About P2Play</string>
<string name="aboutText">P2Play is an Android application unnoficial of PeerTube. You can watch and contribute with the code on GitLab:</string> <string name="aboutText">P2Play is an unofficial Android application for PeerTube. You can watch and contribute with the code on GitLab:</string>
<string name="aboutStatus">You can subscribe to our profile on GNU Social:</string> <string name="aboutStatus">You can follow our blog:</string>
<string name="aboutLicense">Copyleft GNU GPLv3 License</string> <string name="aboutLicense">Copyleft GNU GPLv3 License</string>
<string name="aboutInstance">About instance</string> <string name="aboutInstance">About instance</string>
<string name="aboutInWeb">You can see terms and more on the web:</string> <string name="aboutInWeb">You can see terms and more on the web:</string>
@ -35,10 +35,10 @@
<string name="loginBtn">Login now</string> <string name="loginBtn">Login now</string>
<string name="registerActionBtn">Create new account</string> <string name="registerActionBtn">Create new account</string>
<!-- Toast msg --> <!-- Toast msg -->
<string name="loginSuccess_msg">You are logged</string> <string name="loginSuccess_msg">You are now logged in</string>
<string name="loginError_msg">An error has occurred</string> <string name="loginError_msg">An error has occurred</string>
<string name="loginFailed_msg">Invalid credentials</string> <string name="loginFailed_msg">Invalid credentials</string>
<string name="registerSuccess_msg">You are registered</string> <string name="registerSuccess_msg">You are now registered</string>
<string name="registerError_msg">An error has occurred</string> <string name="registerError_msg">An error has occurred</string>
<string name="registerFailed_msg">Invalid data</string> <string name="registerFailed_msg">Invalid data</string>
<!-- Register msg --> <!-- Register msg -->
@ -48,8 +48,9 @@
<!-- End Login strings --> <!-- End Login strings -->
<!-- Start Main strings --> <!-- Start Main strings -->
<string name="title_subscriptions">Subscriptions</string> <string name="title_subscriptions">Subscriptions</string>
<string name="title_recent">Recent videos</string> <string name="title_recent">Recent</string>
<string name="title_popular">Popular videos</string> <string name="title_popular">Popular</string>
<string name="title_trending">Trending</string>
<string name="title_local">Local videos</string> <string name="title_local">Local videos</string>
<string name="title_myVideos">My videos</string> <string name="title_myVideos">My videos</string>
<string name="view_text">views</string> <string name="view_text">views</string>
@ -59,14 +60,20 @@
<string name="nav_header_title">Log In</string> <string name="nav_header_title">Log In</string>
<string name="nav_header_subtitle" translatable="false">P2Play</string> <string name="nav_header_subtitle" translatable="false">P2Play</string>
<!-- Toast msg --> <!-- Toast msg -->
<string name="logout_msg">You are disconnected</string> <string name="logout_msg">You are now disconnected</string>
<!-- End Main strings --> <!-- End Main strings -->
<!-- Start Menu strings --> <!-- Start Menu strings -->
<string name="nav_subscriptions">Subscriptions</string> <string name="nav_subscriptions">Subscriptions</string>
<string name="nav_popular">Popular</string> <string name="nav_popular">Popular</string>
<string name="nav_trending">Trending</string>
<string name="nav_recent">Recent</string> <string name="nav_recent">Recent</string>
<string name="nav_local">Local</string> <string name="nav_local">Local</string>
<string name="nav_about">About</string> <string name="nav_about">About</string>
<string name="nav_history">History</string>
<string name="nav_menu_myLibrary">My Library</string>
<string name="nav_menu_videos">Videos</string>
<string name="nav_menu_more">More</string>
<string name="nav_likes">Most liked</string>
<!-- End Menu strings --> <!-- End Menu strings -->
<!-- Start MiniMenu strings --> <!-- Start MiniMenu strings -->
<string name="action_settings">Settings</string> <string name="action_settings">Settings</string>
@ -75,8 +82,8 @@
<!-- End MiniMenu strings --> <!-- End MiniMenu strings -->
<!-- Start Reproductor strings --> <!-- Start Reproductor strings -->
<string name="descriptionTxt">Description:</string> <string name="descriptionTxt">Description:</string>
<string name="commentariesTxt">Commentaries:</string> <string name="commentariesTxt">Comments:</string>
<string name="commentHolder">Make a commentary</string> <string name="commentHolder">Make a comment</string>
<!-- Actions --> <!-- Actions -->
<string name="subscribeBtn">Subscribe</string> <string name="subscribeBtn">Subscribe</string>
<string name="likeBtn">Like</string> <string name="likeBtn">Like</string>
@ -85,11 +92,12 @@
<string name="reportBtn">Report</string> <string name="reportBtn">Report</string>
<string name="unSubscribeBtn">Unsubscribe</string> <string name="unSubscribeBtn">Unsubscribe</string>
<string name="commentaryText">Comment</string> <string name="commentaryText">Comment</string>
<string name="showMore">Show more</string>
<!-- Messages --> <!-- Messages -->
<string name="subscribeMsg">You are subscribed to this channel</string> <string name="subscribeMsg">You have subscribed to this channel</string>
<string name="rateMsg">You are rated the video</string> <string name="rateMsg">You have rated the video</string>
<string name="unSubscribeMsg">You are unsubscribed to this channel</string> <string name="unSubscribeMsg">You have unsubscribed from this channel</string>
<string name="makedCommentaryMsg">You are commented this video</string> <string name="makedCommentaryMsg">You have commented on this video</string>
<string name="errorCommentaryMsg">An error has occurred, try again</string> <string name="errorCommentaryMsg">An error has occurred, try again</string>
<string name="emptyCommentaryMsg">Please make a comment first</string> <string name="emptyCommentaryMsg">Please make a comment first</string>
<!-- End Reproductor strings --> <!-- End Reproductor strings -->
@ -98,11 +106,18 @@
<!-- Example General settings --> <!-- Example General settings -->
<string name="pref_header_general">General</string> <string name="pref_header_general">General</string>
<string name="pref_nfsw_title">NFSW content</string> <string name="pref_nfsw_title">NFSW content</string>
<string name="pref_nfsw_description">If is active may show the adult and sensitive content.</string> <string name="pref_nfsw_description">When active, it may show adult and sensitive contents.</string>
<string name="pref_hostname_title">Peertube instance</string> <string name="pref_hostname_title">Peertube instance</string>
<string name="pref_hostname_error" translatable="false">-</string> <string name="pref_hostname_error" translatable="false">-</string>
<string name="pref_message_exit">Restart app to apply changes</string> <string name="pref_message_exit">Restart the app to apply changes</string>
<string name="pref_videos_count_title">Videos per page</string> <string name="pref_videos_count_title">Videos per page</string>
<!-- End Settings strings --> <!-- End Settings strings -->
<!-- Start Channel strings -->
<string name="followersIndicator">Followers:</string>
<string name="hostIndicator">Host:</string>
<!-- End Channel strings -->
<!-- Start Prompt string -->
<string name="reportDialog">Reason to report this video:</string>
<string name="reportDialogMsg">You reported the video</string>
<!-- End Prompt strings -->
</resources> </resources>

View File

@ -13,6 +13,12 @@
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
</style> </style>
<style name="P2playTheme.noBar" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorHeader</item>
<item name="colorPrimaryDark">@android:color/darker_gray</item>
<item name="colorAccent">@android:color/holo_orange_dark</item>
</style>
<style name="P2playTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.ActionBar" /> <style name="P2playTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.ActionBar" />
<style name="P2playTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" /> <style name="P2playTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

View File

@ -1,15 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.3.0' ext.kotlin_version = '1.6.20'
repositories { repositories {
google() google()
jcenter() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.3.1' classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
} }
@ -18,7 +17,7 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
google() google()
jcenter() mavenCentral()
} }
} }

BIN
docs/p2playv2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
docs/p2playv2.xcf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,6 @@
#Wed Jan 23 14:44:01 CST 2019 #Mon Mar 18 13:17:32 CST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip

286
gradlew vendored
View File

@ -1,78 +1,129 @@
#!/usr/bin/env sh #!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS="" DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
@ -89,84 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=$(save "$@") # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong JAVACMD=$( cygpath --unix "$JAVACMD" )
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")" # Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

43
gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS= set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@ -0,0 +1,6 @@
* Update dependecies
* Compile SDK updated to version 30
* Min SDK updated to version 26
* Target SDK updated to version 28
* Back to road baby
* Comming soon!

View File

@ -0,0 +1,20 @@
P2Play is an Unofficial Android client for Peertube.
What is Peertube? https://github.com/Chocobozzz/PeerTube/
Features
* Show recent, popular and local list of videos.
* Reproduce videos
* Login and register in your instance
* Show uploaded videos
* Subscribe to accounts
* Show your subscription videos
* Show your history
* Rate videos
* Show and make commentaries
* Splash screen
* Search videos
* Infinite scroll
* Share videos
* Report videos
* Peertube profiles

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1 @@
Unofficial client for Peertube

1
metadata/en-US/title.txt Normal file
View File

@ -0,0 +1 @@
P2Play - Peertube client

View File

@ -0,0 +1,20 @@
P2Play es una aplicacion no-oficial android para Peertube.
¿Que es Peertube? https://github.com/Chocobozzz/PeerTube/
Caracteristicas
* Show recent, popular and local list of videos.
* Reproduce videos
* Login and register in your instance
* Show uploaded videos
* Subscribe to accounts
* Show your subscription videos
* Show your history
* Rate videos
* Show and make commentaries
* Splash screen
* Search videos
* Infinite scroll
* Share videos
* Report videos
* Peertube profiles

View File

@ -0,0 +1 @@
Cliente no oficial de Peertube

1
metadata/es/title.txt Normal file
View File

@ -0,0 +1 @@
P2Play - Cliente peertube