Compare commits

...

56 Commits

Author SHA1 Message Date
Ivan Agosto 3141500c53 Add download video option 2024-06-05 12:28:06 -06:00
Ivan Agosto f86d66fdab Merge branch 'account-activity' into 'master'
Account activity

See merge request agosto182/p2play!18
2024-06-05 18:27:38 +00:00
Ivan Agosto de2f130826 Account activity 2024-06-05 18:27:38 +00:00
Ivan Agosto 7d865cd181 Merge branch 'feature/removve-kotlin-extensions' into 'master'
Feature/removve kotlin extensions

See merge request agosto182/p2play!17
2024-05-26 21:47:25 +00:00
Ivan Agosto c4c5737344 Feature/removve kotlin extensions 2024-05-26 21:47:25 +00:00
Ivan Agosto ff995e383d Add view manager helper 2024-05-14 18:39:45 -06:00
Ivan Agosto d3466f9cce Add reponsive views 2024-05-14 18:20:46 -06:00
Ivan Agosto f0fbd02cf4 Fix scroll on player activity 2024-05-11 14:26:13 -06:00
Ivan Agosto 3364f60d32 Update exo player with better UX 2024-05-11 13:51:16 -06:00
Ivan Agosto 0f8c3a7126 Release v0.7.0 2024-04-15 22:18:02 -06:00
Ivan Agosto d6aeadc489 Fix lint errors 2024-04-15 22:07:14 -06:00
Ivan Agosto 826bb79431 Merge branch 'feature/threads' into 'master'
Feature/threads

See merge request agosto182/p2play!16
2024-04-16 03:55:53 +00:00
Ivan Agosto 2484406cc7 Feature/threads 2024-04-16 03:55:53 +00:00
Ivan Agosto 0705d6dd80 Merge branch 'feature/playbackService' into 'master'
Feature/playback service

See merge request agosto182/p2play!15
2024-04-11 03:15:06 +00:00
Ivan Agosto dd54d214ff Feature/playback service 2024-04-11 03:15:06 +00:00
Ivan Agosto 48738f100a fix all lint errors 2024-04-06 18:03:23 -06:00
Ivan Agosto b6e1a979ca Fix lint errors automated 2024-04-06 14:38:04 -06:00
Ivan Agosto 96d8ae19c6 Fix buffer, forward and rewind video 2024-04-05 21:44:56 -06:00
Ivan Agosto 8856984dc3 Fix share and report icons color 2024-04-05 21:30:37 -06:00
Ivan Agosto 2ffb7daede Fix dialogs design 2024-04-05 21:30:22 -06:00
Ivan Agosto f0b5ba10e8 Fix for wrong pagination 2024-04-05 18:47:08 -06:00
Ivan Agosto 4d2644674e Add 2fa login support 2024-04-05 18:46:57 -06:00
Ivan Agosto 6a8d3baccb Update setting view 2024-03-31 16:59:57 -06:00
Ivan Agosto ac191c04d3 Updates of descriptions and screenshots 2024-03-28 19:06:38 -06:00
Ivan Agosto 15aaae2fa1 Fix video preview sizes 2024-03-28 18:41:49 -06:00
Ivan Agosto 42be7c4f77 Merge branch 'feature/add-exo-player' into 'master'
Feature/add exo player

See merge request agosto182/p2play!14
2024-03-28 23:58:25 +00:00
Ivan Agosto e022fe5e96 Add fullscreen to exoplayer 2024-03-28 17:29:32 -06:00
Ivan Agosto 1f90e21f68 Fix: Fullscreen bug 2024-03-27 21:31:41 -06:00
Ivan Agosto c104bf32da Merge branch 'master' into feature/add-exo-player 2024-03-27 20:57:17 -06:00
Ivan Agosto a3cd0b92ed Merge branch 'feature/update-video-view' into 'master'
Feature/update video view

See merge request agosto182/p2play!13
2024-03-28 02:54:14 +00:00
Ivan Agosto 2de1bde4cd Feature/update video view 2024-03-28 02:54:14 +00:00
Ivan Agosto 6f0b97dbc4 Exo player first integration 2024-03-27 20:44:52 -06:00
Ivan Agosto 2fcd3b21f8 Add isLive indicator 2024-03-25 19:57:49 -06:00
Ivan Agosto eeb20f1f9d Update function name to the correct one 2024-03-25 19:57:22 -06:00
Ivan Agosto 0d9bd5410a Update to sdk 32 2024-03-25 18:53:01 -06:00
Ivan Agosto 40b193a816 Update duration data to a floating text 2024-03-22 18:12:14 -06:00
Ivan Agosto c500ba9aa4 Merge branch 'androidx' into 'master'
Androidx

See merge request agosto182/p2play!12
2024-03-22 23:23:16 +00:00
Ivan Agosto 35aa0fcea1 Androidx 2024-03-22 23:23:16 +00:00
Ivan Agosto ba0a298ea9 Add new theme to Channel view 2024-03-22 17:20:42 -06:00
Ivan Agosto 815bafaee1 Update edittext to materialTextview 2024-03-22 16:55:52 -06:00
Ivan Agosto ef5c97dce1 Finish update to androidx 2024-03-22 12:28:39 -06:00
Ivan Agosto b6ef9b8aca Normalize theme 2024-03-21 17:47:54 -06:00
Ivan Agosto bf35a75877 Add material theme 2024-03-21 14:23:36 -06:00
Ivan Agosto 65e061fd25 First changes to androidx 2024-03-20 21:04:16 -06:00
Ivan Agosto ffbc491f4c update metadata 2024-03-19 22:04:26 -06:00
Ivan Agosto da1d3e301e Fix error getting local videos 2024-03-19 21:42:26 -06:00
Ivan Agosto 6784b5ebbe Update fastlane descriptions 2024-03-18 19:24:57 -06:00
Ivan Agosto e70108a7ae Update README 2024-03-18 18:53:06 -06:00
Ivan Agosto 2b7d92ac37 Merge branch 'updateAndroidSDK' into 'master'
Update android sdk

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

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

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

See merge request agosto182/p2play!8
2020-02-17 00:59:25 +00:00
Poussinou dad366eebf Update README.md 2020-01-11 13:42:03 +00:00
131 changed files with 4438 additions and 1629 deletions

2
.editorconfig Normal file
View File

@ -0,0 +1,2 @@
[*.{kt,kts}]
ktlint_code_style = intellij_idea

View File

@ -1,20 +1,20 @@
# P2Play
P2Play is an Android Application for Peertube.
P2Play is an unoficial Peertube android application.
[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
![screenshot](screenshots/screenshot.png)
![screenshot](screenshots/screenshot2.png)
![screenshot](screenshots/screenshot3.png)
![screenshot](screenshots/screenshot4.png)
![screenshot](screenshots/screenshot5.png)
![screenshot](screenshots/screenshot6.png)
## Documentation
Comming soon!
<img src="metadata/en-US/images/phoneScreenshots/1.jpg" alt="Screenshot" width="14%"/>
<img src="metadata/en-US/images/phoneScreenshots/2.jpg" alt="Screenshot" width="14%"/>
<img src="metadata/en-US/images/phoneScreenshots/3.jpg" alt="Screenshot" width="14%"/>
<img src="metadata/en-US/images/phoneScreenshots/4.jpg" alt="Screenshot" width="14%"/>
<img src="metadata/en-US/images/phoneScreenshots/5.jpg" alt="Screenshot" width="14%">/
<img src="metadata/en-US/images/phoneScreenshots/6.jpg" alt="Screenshot" width="14%"/>
## Realeases (apk's)
@ -37,33 +37,40 @@ Comming soon!
- Share videos
- Report videos
- Peertube profiles
- Day/Night theme
## What to do? (in next version)
## What to do? (on incomming updates)
- Playlists
- Manage subscriptions
- Better commentaries
- Account channels view
- Notifications
- Upload videos
## Demostrations
Demostration P2play Beta 0.2: https://peertube.video/videos/watch/730fa68e-32c4-4cdb-a7bb-1a819c9d3a46
P2play beta 0.6.0: https://fediverse.tv/w/suFPkm9zJstSrQU7WmVARv
Demostration P2Play Beta 0.1: https://peertube.video/videos/watch/2eb7b953-0b1b-4019-9300-817539f5f4e8
**Dead links**
[Spanish] Demostracion P2Play Beta 0.1: https://peertube.video/videos/watch/d6a7da26-d3dd-43aa-ad5c-7d032603c848
~~Demostration P2play Beta 0.2: https://peertube.video/videos/watch/730fa68e-32c4-4cdb-a7bb-1a819c9d3a46~~
~~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
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).
- WriteFreely (ActivityPub): https://personaljournal.ca/p2play/
- Peertube Channel: https://peertube.video/video-channels/90df4e5f-c834-4720-a5d7-c9faa0af0af5/videos
## 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)
### Developers
- Ivan Agosto: [https://nerdica.net/profile/agosto182](https://gnusocial.ml/agosto182)
- Ivan Agosto: [https://mast.lat/@agosto182](https://mast.lat/@agosto182)
## 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.

View File

@ -1,19 +1,19 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
plugins {
id "com.android.application"
id "kotlin-android"
}
android {
compileSdkVersion 27
defaultConfig {
applicationId "org.libre.agosto.p2play"
minSdkVersion 21
//noinspection OldTargetApi
targetSdkVersion 27
versionCode 7
versionName "0.5.1"
compileSdk 34
minSdkVersion 26
targetSdkVersion 32
versionCode 10
versionName "0.7.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
@ -21,26 +21,38 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildToolsVersion '28.0.3'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
buildFeatures {
viewBinding = true
}
lintOptions {
checkReleaseBuilds false
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
namespace 'org.libre.agosto.p2play'
lint {
abortOnError false
checkReleaseBuilds false
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'com.android.support:appcompat-v7:27.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:support-v4:27.1.0'
implementation 'com.android.support:design:27.1.0'
implementation 'com.squareup.picasso:picasso:2.71828'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.google.android.material:material:1.12.0'
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.activity:activity:1.8.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'androidx.media3:media3-exoplayer:1.3.1'
implementation 'androidx.media3:media3-exoplayer-dash:1.3.1'
implementation 'androidx.media3:media3-ui:1.3.1'
implementation 'androidx.media3:media3-exoplayer-hls:1.3.1'
implementation "androidx.media3:media3-session:1.3.1"
implementation 'com.google.code.gson:gson:2.8.8'
}

View File

@ -1,24 +0,0 @@
package org.libre.agosto.p2play
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
assertEquals("org.libre.agosto.p2play", appContext.packageName)
}
}

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.libre.agosto.p2play">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<application
android:allowBackup="true"
@ -11,33 +12,67 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/P2playTheme">
<activity android:name=".ChannelActivity"
android:theme="@style/P2playTheme.noBar"></activity>
android:theme="@style/Theme.P2play">
<activity
android:name=".AccountActivity"
android:exported="false"
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".SettingsActivity2"
android:exported="false"
android:label="@string/title_activity_settings"
android:theme="@style/Theme.P2play">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
<activity
android:name=".ChannelActivity"
android:exported="false"
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".SplashActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
android:exported="true"
android:theme="@style/Theme.P2play.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".HostActivity" />
<activity
android:name=".HostActivity"
android:exported="false"
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".MainActivity"
android:theme="@style/P2playTheme.NoActionBar" />
android:exported="false"
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".ReproductorActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:hardwareAccelerated="true"
android:theme="@style/P2playTheme.noBar" />
<activity android:name=".LoginActivity" />
<activity android:name=".RegisterActivity" />
<activity android:name=".AboutActivity" />
android:theme="@style/Theme.P2play.NoActionBar" />
<activity
android:name=".SettingsActivity"
android:label="@string/title_activity_settings" />
android:name=".LoginActivity"
android:exported="false" />
<activity
android:name=".RegisterActivity"
android:exported="false" />
<activity
android:name=".AboutActivity"
android:exported="false" />
<service
android:name=".services.PlaybackService"
android:exported="true"
android:foregroundServiceType="mediaPlayback">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
</intent-filter>
</service>
</application>
</manifest>

View File

@ -1,18 +1,19 @@
package org.libre.agosto.p2play
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.text.method.LinkMovementMethod
import kotlinx.android.synthetic.main.activity_about.*
import androidx.appcompat.app.AppCompatActivity
import org.libre.agosto.p2play.databinding.ActivityAboutBinding
class AboutActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_about)
val binding = ActivityAboutBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
aboutUrl.text = "https://"+ManagerSingleton.url+"/about/instance"
binding.aboutUrl.text = "https://" + ManagerSingleton.url + "/about/instance"
aboutLabel.text = aboutLabel.text.toString() + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
binding.aboutLabel.text = binding.aboutLabel.text.toString() + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
}
}

View File

@ -0,0 +1,68 @@
package org.libre.agosto.p2play
import android.os.AsyncTask
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.tabs.TabLayoutMediator
import com.squareup.picasso.Picasso
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.libre.agosto.p2play.ajax.Accounts
import org.libre.agosto.p2play.databinding.ActivityAccountBinding
import org.libre.agosto.p2play.databinding.ActivityMainBinding
import org.libre.agosto.p2play.fragmentAdapters.AccountAdapter
import org.libre.agosto.p2play.models.AccountModel
class AccountActivity : AppCompatActivity() {
private lateinit var binding: ActivityAccountBinding
private val client = Accounts()
private lateinit var accountId: String
private lateinit var adapter: AccountAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAccountBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
accountId = this.intent.extras?.getString("accountId")!!
supportActionBar?.setDisplayHomeAsUpEnabled(true)
binding.toolbar.setNavigationOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
adapter = AccountAdapter(supportFragmentManager, lifecycle)
binding.viewpager.adapter = adapter
adapter.accountId = accountId
TabLayoutMediator(binding.tabs, binding.viewpager, false, false) { tab, position ->
tab.text = adapter.get(position)
}.attach()
}
override fun onResume() {
super.onResume()
getChannelInfo()
}
private fun getChannelInfo() {
CoroutineScope(Dispatchers.IO).launch {
val account = client.get(accountId)
withContext(Dispatchers.Main) {
binding.collapsingToolbar.title = account.displayName
adapter.account = account
if (account.avatars.size > 0) {
Picasso.get().load("https://${ManagerSingleton.url}${account.avatars.last().path}").into(binding.profileImage)
}
}
}
}
}

View File

@ -1,90 +0,0 @@
package org.libre.agosto.p2play
import android.content.res.Configuration
import android.os.Bundle
import android.preference.PreferenceActivity
import android.support.annotation.LayoutRes
import android.support.v7.app.ActionBar
import android.support.v7.app.AppCompatDelegate
import android.support.v7.widget.Toolbar
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
/**
* A [android.preference.PreferenceActivity] which implements and proxies the necessary calls
* to be used with AppCompat.
*/
abstract class AppCompatPreferenceActivity : PreferenceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
delegate.installViewFactory()
delegate.onCreate(savedInstanceState)
super.onCreate(savedInstanceState)
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
delegate.onPostCreate(savedInstanceState)
}
val supportActionBar: ActionBar?
get() = delegate.supportActionBar
fun setSupportActionBar(toolbar: Toolbar?) {
delegate.setSupportActionBar(toolbar)
}
override fun getMenuInflater(): MenuInflater {
return delegate.menuInflater
}
override fun setContentView(@LayoutRes layoutResID: Int) {
delegate.setContentView(layoutResID)
}
override fun setContentView(view: View) {
delegate.setContentView(view)
}
override fun setContentView(view: View, params: ViewGroup.LayoutParams) {
delegate.setContentView(view, params)
}
override fun addContentView(view: View, params: ViewGroup.LayoutParams) {
delegate.addContentView(view, params)
}
override fun onPostResume() {
super.onPostResume()
delegate.onPostResume()
}
override fun onTitleChanged(title: CharSequence, color: Int) {
super.onTitleChanged(title, color)
delegate.setTitle(title)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
delegate.onConfigurationChanged(newConfig)
}
override fun onStop() {
super.onStop()
delegate.onStop()
}
override fun onDestroy() {
super.onDestroy()
delegate.onDestroy()
}
override fun invalidateOptionsMenu() {
delegate.invalidateOptionsMenu()
}
private val delegate: AppCompatDelegate by lazy {
AppCompatDelegate.create(this, null)
}
}

View File

@ -1,41 +1,44 @@
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 androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
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.databinding.ActivityChannelBinding
import org.libre.agosto.p2play.helpers.getViewManager
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 val channelService = Channels()
private val videosService = Videos()
private val actionsService = Actions()
private lateinit var recyclerView: RecyclerView
private lateinit var viewAdapter: RecyclerView.Adapter<VideosAdapter.ViewHolder>
private lateinit var viewManager: RecyclerView.LayoutManager
private lateinit var binding: ActivityChannelBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_channel)
binding = ActivityChannelBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
channelId = this.intent.extras.getString("channel")
channelId = this.intent.extras?.getString("channel")!!
viewManager = LinearLayoutManager(this)
viewManager = getViewManager(this, resources)
subcriptionBtn.setOnClickListener {
binding.subcriptionBtn.setOnClickListener {
subscribeAction()
}
}
@ -48,35 +51,35 @@ class ChannelActivity : AppCompatActivity() {
getVideos()
if (ManagerSingleton.user.status == 1) {
subcriptionBtn.visibility = View.VISIBLE
binding.subcriptionBtn.visibility = View.VISIBLE
getSubscription()
}
}
private fun getChannel() {
AsyncTask.execute {
channel = _channel.getChannelInfo(channelId)
channel = channelService.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)
binding.usernameProfile.text = channel.name
binding.hostTxt.text = channel.host
binding.subcriptionsTxt.text = channel.followers.toString()
if (channel.channelImg != "") {
Picasso.get().load("https://${ManagerSingleton.url}${channel.channelImg}").into(binding.channelImg)
}
}
}
}
private fun subscribe() {
AsyncTask.execute {
val res = _actions.subscribe(ManagerSingleton.token.token, channel.getAccount())
val res = actionsService.subscribe(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if (res == 1) {
subcriptionBtn.text = getString(R.string.unSubscribeBtn)
ManagerSingleton.Toast(getString(R.string.subscribeMsg), this)
binding.subcriptionBtn.text = getString(R.string.unSubscribeBtn)
ManagerSingleton.toast(getString(R.string.subscribeMsg), this)
getSubscription()
}
else {
ManagerSingleton.Toast(getString(R.string.errorMsg), this)
} else {
ManagerSingleton.toast(getString(R.string.errorMsg), this)
}
}
}
@ -84,36 +87,35 @@ class ChannelActivity : AppCompatActivity() {
private fun unSubscribe() {
AsyncTask.execute {
val res = _actions.unSubscribe(ManagerSingleton.token.token, channel.getAccount())
val res = actionsService.unSubscribe(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if (res == 1) {
subcriptionBtn.text = getString(R.string.subscribeBtn)
ManagerSingleton.Toast(getString(R.string.unSubscribeMsg), this)
binding.subcriptionBtn.text = getString(R.string.subscribeBtn)
ManagerSingleton.toast(getString(R.string.unSubscribeMsg), this)
getSubscription()
}
else {
ManagerSingleton.Toast(getString(R.string.errorMsg), this)
} else {
ManagerSingleton.toast(getString(R.string.errorMsg), this)
}
}
}
}
private fun subscribeAction() {
if(isSubcribed)
if (isSubcribed) {
unSubscribe()
else
} else {
subscribe()
}
}
private fun getSubscription() {
AsyncTask.execute {
isSubcribed = _actions.getSubscription(ManagerSingleton.token.token, channel.getAccount())
isSubcribed = actionsService.getSubscription(ManagerSingleton.token.token, channel.getAccount())
runOnUiThread {
if (isSubcribed) {
subcriptionBtn.text = getText(R.string.unSubscribeBtn)
}
else {
subcriptionBtn.text = getText(R.string.subscribeBtn)
binding.subcriptionBtn.text = getText(R.string.unSubscribeBtn)
} else {
binding.subcriptionBtn.text = getText(R.string.subscribeBtn)
}
}
}
@ -121,7 +123,7 @@ class ChannelActivity : AppCompatActivity() {
private fun getVideos() {
AsyncTask.execute {
val videos = _videos.channelVideos(channel.getAccount(), 0)
val videos = videosService.channelVideos(channel.getAccount(), 0)
runOnUiThread {
initRecycler(videos)
}

View File

@ -72,7 +72,6 @@ class Database(context:Context): SQLiteOpenHelper(context,"p2play",null,1) {
cursor.close()
return token
} catch (e: SQLiteException) {
db?.execSQL(dbTokens)
} catch (e: Exception) {
@ -103,7 +102,6 @@ class Database(context:Context): SQLiteOpenHelper(context,"p2play",null,1) {
cursor.close()
return user
} catch (e: SQLiteException) {
db?.execSQL(dbTokens)
} catch (e: Exception) {
@ -126,5 +124,4 @@ class Database(context:Context): SQLiteOpenHelper(context,"p2play",null,1) {
closeUsers()
closeTokens()
}
}

View File

@ -3,39 +3,41 @@ package org.libre.agosto.p2play
import android.content.Intent
import android.content.SharedPreferences
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.preference.PreferenceManager
import android.util.Log
import kotlinx.android.synthetic.main.activity_host.*
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import org.libre.agosto.p2play.ajax.Auth
import org.libre.agosto.p2play.ajax.Client
import org.libre.agosto.p2play.databinding.ActivityHostBinding
class HostActivity : AppCompatActivity() {
lateinit var settings: SharedPreferences
lateinit var editor: SharedPreferences.Editor
val client: Auth = Auth()
val _db = Database(this)
private val db = Database(this)
private lateinit var binding: ActivityHostBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
binding = ActivityHostBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
settings = PreferenceManager.getDefaultSharedPreferences(this)
editor = settings.edit()
button.setOnClickListener {
getKeys(hostText.text.toString())
binding.button.setOnClickListener {
getKeys(binding.hostText.text.toString())
}
val host = settings.getString("hostP2play", "")
val lastHost = settings.getString("last_host", "")
if (host != "") {
if (lastHost != host) {
_db.logout()
db.logout()
ManagerSingleton.logout()
getKeys(host)
getKeys(host!!)
} else {
ManagerSingleton.url = host
startApp()
@ -43,27 +45,26 @@ class HostActivity : AppCompatActivity() {
}
}
fun saveHost(host: String) {
editor.putString("last_host", host)
editor.putString("hostP2play", host)
editor.apply()
ManagerSingleton.Toast(getString(R.string.finallyMsg), this)
ManagerSingleton.toast(getString(R.string.finallyMsg), this)
ManagerSingleton.url = host
startApp()
}
private fun getKeys(hostText: String) {
button.isEnabled = false
binding.button.isEnabled = false
var host = hostText.toString()
host = host.replace("http://", "")
host = host.replace("https://", "")
host = host.replace("/", "")
ManagerSingleton.url = host
AsyncTask.execute {
if (Looper.myLooper()==null)
if (Looper.myLooper() == null) {
Looper.prepare()
}
val keys = client.getKeys()
if (keys.client_id != "") {
@ -71,11 +72,10 @@ class HostActivity : AppCompatActivity() {
editor.putString("client_secret", keys.client_secret)
editor.apply()
saveHost(host)
}
else{
} else {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.errorMsg), this)
button.isEnabled = true
ManagerSingleton.toast(getString(R.string.errorMsg), this)
binding.button.isEnabled = true
}
}
}

View File

@ -3,85 +3,113 @@ package org.libre.agosto.p2play
import android.content.Intent
import android.content.SharedPreferences
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.preference.PreferenceManager
import android.util.Log
import kotlinx.android.synthetic.main.activity_login.*
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import org.libre.agosto.p2play.ajax.Auth
import org.libre.agosto.p2play.databinding.ActivityLoginBinding
class LoginActivity : AppCompatActivity() {
private val _auth = Auth()
private val auth = Auth()
lateinit var settings: SharedPreferences
lateinit var client_id: String
lateinit var client_secret: String
private lateinit var _db: Database
lateinit var clientId: String
lateinit var clientSecret: String
private lateinit var db: Database
private var optCode: String? = null
private lateinit var binding: ActivityLoginBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
binding = ActivityLoginBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
setTitle(R.string.action_login)
_db = Database(this)
db = Database(this)
settings = PreferenceManager.getDefaultSharedPreferences(this)
client_id = settings.getString("client_id", "")
client_secret = settings.getString("client_secret", "")
clientId = settings.getString("client_id", "")!!
clientSecret = settings.getString("client_secret", "")!!
registerActionBtn.setOnClickListener { startActivity(Intent(this, RegisterActivity::class.java)) }
loginBtn.setOnClickListener { tryLogin() }
binding.registerActionBtn.setOnClickListener { startActivity(Intent(this, RegisterActivity::class.java)) }
binding.loginBtn.setOnClickListener { tryLogin() }
}
fun tryLogin() {
loginBtn.isEnabled = false;
val username = userText.text.toString()
val password = passwordText.text.toString()
binding.loginBtn.isEnabled = false
val username = binding.userText.text.toString()
val password = binding.passwordText.text.toString()
AsyncTask.execute {
if (Looper.myLooper()==null)
if (Looper.myLooper() == null) {
Looper.prepare()
}
val token = _auth.login(username, password, client_id, client_secret)
val token = auth.login(username, password, clientId, clientSecret, optCode)
// Log.d("token", token.token )
// Log.d("status", token.status.toString() )
when (token.status.toString()) {
"1" -> {
_db.newToken(token)
db.newToken(token)
ManagerSingleton.token = token
getUser()
}
"0" -> {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.loginError_msg), this)
ManagerSingleton.toast(getString(R.string.loginError_msg), this)
}
}
"-1" -> {
runOnUiThread {
loginBtn.isEnabled = true
ManagerSingleton.Toast(getString(R.string.loginFailed_msg), this)
}
binding.loginBtn.isEnabled = true
ManagerSingleton.toast(getString(R.string.loginFailed_msg), this)
}
}
"-2" -> {
// TODO: Start 2FA modal
runOnUiThread {
val builder = AlertDialog.Builder(this, R.style.Widget_Material3_MaterialCalendar_Fullscreen)
val dialog = layoutInflater.inflate(R.layout.two_factor_dialog, null)
val inputTwoFactor = dialog.findViewById<EditText>(R.id.twoFactorText)
builder.setView(dialog)
.setTitle(R.string.twoFactorLabel)
// Add action buttons
.setPositiveButton(R.string.loginBtn) { d, _ ->
this.optCode = inputTwoFactor.text.toString()
this.tryLogin()
d.dismiss()
}
.setNegativeButton("Cancel") { d, _ ->
dialog.run { d.cancel() }
binding.loginBtn.isEnabled = true
}
val alertDialog = builder.create()
alertDialog.show()
}
}
}
}
}
fun getUser() {
val user = _auth.me(ManagerSingleton.token.token)
val user = auth.me(ManagerSingleton.token.token)
if (user.status == 1) {
_db.newUser(user)
db.newUser(user)
ManagerSingleton.user = user
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.loginSuccess_msg), this)
ManagerSingleton.toast(getString(R.string.loginSuccess_msg), this)
finish()
}
}
else{
} else {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.loginError_msg), this)
ManagerSingleton.toast(getString(R.string.loginError_msg), this)
}
}
}

View File

@ -4,26 +4,24 @@ import android.content.Intent
import android.os.AsyncTask
import android.os.Bundle
import android.os.Handler
import android.support.design.widget.Snackbar
import android.support.design.widget.NavigationView
import android.support.v4.view.GravityCompat
import android.support.v7.app.ActionBarDrawerToggle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.widget.ImageView
import android.widget.SearchView
import android.widget.TextView
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.core.view.GravityCompat
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.navigation.NavigationView
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.content_main.*
import kotlinx.android.synthetic.main.nav_header_main.*
import org.libre.agosto.p2play.adapters.VideosAdapter
import org.libre.agosto.p2play.ajax.Videos
import org.libre.agosto.p2play.databinding.ActivityMainBinding
import org.libre.agosto.p2play.helpers.getViewManager
import org.libre.agosto.p2play.models.VideoModel
import org.libre.agosto.p2play.singletons.PlaybackSingleton
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var recyclerView: RecyclerView
@ -31,44 +29,47 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
private lateinit var viewManager: RecyclerView.LayoutManager
private val client: Videos = Videos()
private lateinit var lastItem: MenuItem
private lateinit var subItem: MenuItem
lateinit var myMenu: Menu
private val _db = Database(this)
private val db = Database(this)
var section: String = ""
var searchVal: String = ""
var pagination = 0
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
setSupportActionBar(binding.toolbar)
/* fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
} */
val toggle = ActionBarDrawerToggle(this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawer_layout.addDrawerListener(toggle)
val toggle = ActionBarDrawerToggle(this, binding.drawerLayout, binding.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
binding.drawerLayout.addDrawerListener(toggle)
toggle.syncState()
nav_view.setNavigationItemSelectedListener(this)
binding.navView.setNavigationItemSelectedListener(this)
viewManager = LinearLayoutManager(this)
viewManager = getViewManager(this, resources)
// Init RecyclerView
this.initRecycler()
this.getTrengindVideos()
swipeContainer.setOnRefreshListener {
binding.content.swipeContainer.setOnRefreshListener {
this.refresh()
}
binding.content.mini.miniPlayerImage.setOnClickListener { this.resumeVideo() }
binding.content.mini.miniPlayerTitle.setOnClickListener { this.resumeVideo() }
binding.content.mini.miniPlayerAuthor.setOnClickListener { this.resumeVideo() }
// binding.content.mini.setOnClickListener { this.resumeVideo() }
binding.content.mini.miniPlayPause.setOnClickListener { this.playPausePlayer() }
Handler().postDelayed({
// Title for nav_bar
side_emailTxt?.text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
binding.navView.getHeaderView(0).findViewById<TextView>(R.id.side_emailTxt).text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
}, 2000)
}
@ -89,10 +90,11 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
adapter = viewAdapter
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)
if(!swipeContainer.isRefreshing){
if (!binding.content.swipeContainer.isRefreshing) {
if (!canScrollVertically(1)) {
loadMore()
}
@ -100,11 +102,11 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
})
}
// swipeContainer.isRefreshing = false
binding.content.swipeContainer.isRefreshing = false
}
private fun addVideos(videos: ArrayList<VideoModel>) {
this.swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
try {
if (this.pagination == 0) {
@ -115,14 +117,14 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
(viewAdapter as VideosAdapter).addData(videos)
} catch (err: Exception) {
err.printStackTrace()
ManagerSingleton.Toast(getString(R.string.errorMsg), this)
ManagerSingleton.toast(getString(R.string.errorMsg), this)
}
this.swipeContainer.isRefreshing = false
binding.content.swipeContainer.isRefreshing = false
}
private fun refresh() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
this.pagination = 0
when (section) {
"local" -> this.getLocalVideos()
@ -132,21 +134,22 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
"sub" -> this.getSubscriptionVideos()
"search" -> this.searchVideos()
"my_videos" -> {
if(ManagerSingleton.token.token != "")
if (ManagerSingleton.token.token != "") {
this.getMyVideos()
else
} else {
this.getLastVideos()
}
}
}
}
private fun getSubscriptionVideos() {
if (ManagerSingleton.user.status != 1) {
ManagerSingleton.Toast("Inicia session primero", this)
ManagerSingleton.toast("Inicia session primero", this)
startActivity(Intent(this, LoginActivity::class.java))
return
}
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "sub"
setTitle(R.string.title_subscriptions)
AsyncTask.execute {
@ -159,7 +162,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Last videos
private fun getLastVideos() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "last"
setTitle(R.string.title_recent)
AsyncTask.execute {
@ -172,7 +175,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Popular videos
private fun getPopularVideos() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "popular"
setTitle(R.string.title_popular)
AsyncTask.execute {
@ -185,7 +188,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Trending videos
private fun getTrengindVideos() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "trending"
setTitle(R.string.title_trending)
AsyncTask.execute {
@ -198,7 +201,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Local videos
private fun getLocalVideos() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "local"
setTitle(R.string.title_local)
AsyncTask.execute {
@ -211,7 +214,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Videos of user
private fun getMyVideos() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "my_videos"
setTitle(R.string.title_myVideos)
AsyncTask.execute {
@ -224,7 +227,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Videos history of user
private fun getHistory() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "my_videos"
setTitle(R.string.nav_history)
AsyncTask.execute {
@ -237,7 +240,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// Most liked
private fun getMostLiked() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "liked"
setTitle(R.string.nav_likes)
AsyncTask.execute {
@ -249,13 +252,13 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
}
else if(!section.equals("trending")) {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
binding.drawerLayout.closeDrawer(GravityCompat.START)
} else if (!section.equals("trending")) {
// Hot fix
pagination = 0
this.getTrengindVideos()
}
else {
} else {
super.onBackPressed()
}
}
@ -281,10 +284,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
return true
}
})
myMenu = menu
setSideData()
return true
@ -302,7 +303,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) {
R.id.action_settings -> {
val intent = Intent(this, SettingsActivity::class.java)
val intent = Intent(this, SettingsActivity2::class.java)
startActivity(intent)
return true
}
@ -344,34 +345,55 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
R.id.nav_likes -> getMostLiked()
}
drawer_layout.closeDrawer(GravityCompat.START)
binding.drawerLayout.closeDrawer(GravityCompat.START)
return true
}
override fun onResume() {
super.onResume()
setSideData()
if (PlaybackSingleton.player != null && PlaybackSingleton.player!!.isPlaying) {
PlaybackSingleton.runMediaSession(this)
binding.content.mini.miniPlayerTitle.text = PlaybackSingleton.video!!.name
binding.content.mini.miniPlayerAuthor.text = PlaybackSingleton.video!!.username
Picasso.get().load("https://${ManagerSingleton.url}${PlaybackSingleton.video!!.thumbUrl}").into(binding.content.mini.miniPlayerImage)
binding.content.mini.miniPlayPause.setImageResource(R.drawable.ic_pause_24)
binding.content.mini.miniPlayer.visibility = View.VISIBLE
} else {
binding.content.mini.miniPlayer.visibility = View.GONE
}
}
override fun onDestroy() {
if (PlaybackSingleton.player != null) {
PlaybackSingleton.release()
}
super.onDestroy()
}
private fun setSideData() {
if (ManagerSingleton.user.status == 1) {
nav_view.menu.findItem(R.id.ml).isVisible = true
binding.navView.menu.findItem(R.id.ml).isVisible = true
side_usernameTxt?.text = ManagerSingleton.user.username
side_emailTxt?.text = ManagerSingleton.user.email
if(ManagerSingleton.user.avatar!="" && side_imageView != null) {
Picasso.get().load("https://" + ManagerSingleton.url + ManagerSingleton.user.avatar).into(side_imageView)
val headerView = binding.navView.getHeaderView(0)
headerView.findViewById<TextView>(R.id.side_usernameTxt).text = ManagerSingleton.user.username
headerView.findViewById<TextView>(R.id.side_emailTxt).text = ManagerSingleton.user.email
if (ManagerSingleton.user.avatar != "" && headerView.findViewById<ImageView>(R.id.side_imageView) != null) {
Picasso.get().load("https://" + ManagerSingleton.url + ManagerSingleton.user.avatar).into(headerView.findViewById<ImageView>(R.id.side_imageView))
}
headerView.findViewById<ImageView>(R.id.side_imageView).setOnClickListener {
pagination = 0
getMyVideos()
binding.drawerLayout.closeDrawer(GravityCompat.START)
}
// side_imageView?.setOnClickListener {
// pagination = 0
// getMyVideos()
// drawer_layout.closeDrawer(GravityCompat.START)
// }
if (::myMenu.isInitialized) {
myMenu.findItem(R.id.action_login).isVisible = false
myMenu.findItem(R.id.action_logout).isVisible = true
}
} else {
binding.navView.menu.findItem(R.id.ml).isVisible = false
}
}
@ -380,22 +402,23 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
myMenu.findItem(R.id.action_login).isVisible = true
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_emailTxt?.text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
side_imageView?.setImageResource(R.drawable.default_avatar)
side_imageView?.setOnClickListener { }
_db.logout()
val headerView = binding.navView.getHeaderView(0)
binding.navView.menu.findItem(R.id.ml).isVisible = false
headerView.findViewById<TextView>(R.id.side_usernameTxt).text = getString(R.string.nav_header_title)
headerView.findViewById<TextView>(R.id.side_emailTxt).text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
headerView.findViewById<ImageView>(R.id.side_imageView).setImageResource(R.drawable.default_avatar)
headerView.findViewById<ImageView>(R.id.side_imageView).setOnClickListener { }
db.logout()
ManagerSingleton.logout()
this.refresh()
ManagerSingleton.Toast(getString(R.string.logout_msg), this)
ManagerSingleton.toast(getString(R.string.logout_msg), this)
setSideData()
}
private fun loadMore() {
swipeContainer.isRefreshing = true
this.pagination += ManagerSingleton.videos_count
binding.content.swipeContainer.isRefreshing = true
this.pagination += ManagerSingleton.videosCount
when (section) {
"local" -> this.getLocalVideos()
@ -405,17 +428,18 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
"sub" -> this.getSubscriptionVideos()
"search" -> this.searchVideos()
"my_videos" -> {
if(ManagerSingleton.token.token != "")
if (ManagerSingleton.token.token != "") {
this.getMyVideos()
else
} else {
this.getLastVideos()
}
}
"liked" -> this.getMostLiked()
}
}
private fun searchVideos() {
swipeContainer.isRefreshing = true
binding.content.swipeContainer.isRefreshing = true
section = "search"
this.title = this.searchVal
AsyncTask.execute {
@ -426,4 +450,21 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
}
private fun resumeVideo() {
val intent = Intent(this, ReproductorActivity::class.java)
intent.putExtra("resume", true)
startActivity(intent)
}
private fun playPausePlayer() {
PlaybackSingleton.player?.let {
if (it.isPlaying) {
it.pause()
binding.content.mini.miniPlayPause.setImageResource(R.drawable.ic_play_arrow_24)
} else {
it.play()
binding.content.mini.miniPlayPause.setImageResource(R.drawable.ic_pause_24)
}
}
}
}

View File

@ -1,6 +1,7 @@
package org.libre.agosto.p2play
import android.content.Context
import android.content.SharedPreferences
import org.libre.agosto.p2play.models.TokenModel
import org.libre.agosto.p2play.models.UserModel
@ -9,14 +10,30 @@ object ManagerSingleton {
var user: UserModel = UserModel()
var token: TokenModel = TokenModel()
var nfsw: Boolean = false
var videos_count: Int = 0
fun Toast(text: String?, context: Context) {
var videosCount: Int = 0
lateinit var settings: SharedPreferences
lateinit var db: Database
fun toast(text: String?, context: Context) {
android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show()
}
fun logout() {
db.logout()
user = UserModel()
token = TokenModel()
}
fun reloadSettings() {
val host = settings.getString("hostP2play", "")
val lastHost = settings.getString("last_host", "")
if (host != "") {
if (lastHost != host) {
logout()
}
url = host
}
nfsw = settings.getBoolean("show_nsfw", false)
videosCount = settings.getString("videos_count", "15")!!.toInt()
}
}

View File

@ -2,53 +2,58 @@ package org.libre.agosto.p2play
import android.content.SharedPreferences
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.preference.PreferenceManager
import android.util.Log
import kotlinx.android.synthetic.main.activity_register.*
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import org.libre.agosto.p2play.ajax.Auth
import org.libre.agosto.p2play.databinding.ActivityRegisterBinding
class RegisterActivity : AppCompatActivity() {
private val _auth = Auth()
private val auth = Auth()
lateinit var settings: SharedPreferences
lateinit var client_id: String
lateinit var client_secret: String
lateinit var clientId: String
lateinit var clientSecret: String
private lateinit var binding: ActivityRegisterBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register)
binding = ActivityRegisterBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
setTitle(R.string.registerActionBtn)
settings = PreferenceManager.getDefaultSharedPreferences(this)
client_id = settings.getString("client_id", "")
client_secret = settings.getString("client_secret", "")
clientId = settings.getString("client_id", "")!!
clientSecret = settings.getString("client_secret", "")!!
registerBtn.setOnClickListener { registerUser() }
binding.registerBtn.setOnClickListener { registerUser() }
}
fun registerUser(){
registerBtn.isEnabled = false
val username = userText2.text.toString()
val password = passwordText2.text.toString()
val email = emailText.text.toString()
private fun registerUser() {
binding.registerBtn.isEnabled = false
val username = binding.userText2.text.toString()
val password = binding.passwordText2.text.toString()
val email = binding.emailText.text.toString()
AsyncTask.execute {
if (Looper.myLooper()==null)
if (Looper.myLooper() == null) {
Looper.prepare()
}
val res = _auth.register(username, password, email)
val res = auth.register(username, password, email)
Log.d("Res register", res.toString())
runOnUiThread {
when (res) {
1 -> {
ManagerSingleton.Toast(getString(R.string.registerSuccess_msg), this)
ManagerSingleton.toast(getString(R.string.registerSuccess_msg), this)
finish()
}
0 -> ManagerSingleton.Toast(getString(R.string.registerFailed_msg), this)
-1 -> ManagerSingleton.Toast(getString(R.string.registerError_msg), this)
0 -> ManagerSingleton.toast(getString(R.string.registerFailed_msg), this)
-1 -> ManagerSingleton.toast(getString(R.string.registerError_msg), this)
}
registerBtn.isEnabled = true
binding.registerBtn.isEnabled = true
}
}
}

View File

@ -1,43 +1,49 @@
package org.libre.agosto.p2play
import android.annotation.SuppressLint
import android.app.Activity
import android.content.DialogInterface
import android.app.DownloadManager
import android.content.Intent
import android.content.pm.ActivityInfo
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.view.View
import android.view.WindowManager
import android.webkit.WebChromeClient
import android.widget.EditText
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_reproductor.*
import org.libre.agosto.p2play.adapters.CommentariesAdapter
import org.libre.agosto.p2play.ajax.Actions
import org.libre.agosto.p2play.ajax.Comments
import org.libre.agosto.p2play.ajax.Videos
import org.libre.agosto.p2play.databinding.ActivityReproductorBinding
import org.libre.agosto.p2play.helpers.setFullscreen
import org.libre.agosto.p2play.models.CommentaryModel
import org.libre.agosto.p2play.models.DownloadFiles
import org.libre.agosto.p2play.models.VideoModel
import org.libre.agosto.p2play.singletons.PlaybackSingleton
@Suppress("NAME_SHADOWING")
class ReproductorActivity : AppCompatActivity() {
private val clientVideo: Videos = Videos()
lateinit var video: VideoModel
private val _actions: Actions = Actions()
lateinit var videoPlayback: VideoModel
private val actions: Actions = Actions()
private val client: Comments = Comments()
private val videos: Videos = Videos()
@ -46,11 +52,30 @@ class ReproductorActivity : AppCompatActivity() {
private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewManager: RecyclerView.LayoutManager
// Exoplayer
private lateinit var player: ExoPlayer
private lateinit var mediaControl: MediaController
// Fullscreen info
private var isFullscreen = false
// Resume info
private var isResume = false
private lateinit var binding: ActivityReproductorBinding
@SuppressLint("SetJavaScriptEnabled", "SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_reproductor)
binding = ActivityReproductorBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
val fullscreenButton = binding.exoPlayer.findViewById<ImageView>(R.id.exo_fullscreen_custom)
val fullscreenButton2 = binding.fullscreenPlayer.findViewById<ImageView>(R.id.exo_fullscreen_custom)
val videoView = binding.videoView
videoView.webChromeClient = WebClient()
videoView.settings.javaScriptEnabled = true
videoView.settings.allowContentAccess = true
@ -61,23 +86,31 @@ class ReproductorActivity : AppCompatActivity() {
videoView.settings.domStorageEnabled = true
try {
this.video = this.intent.extras.getSerializable("video") as VideoModel
tittleVideoTxt.text = this.video.name
viewsTxt.text = "${this.video.views} ${getString(R.string.view_text)}"
userTxt.text = this.video.username
descriptionVideoTxt.text = this.video.description
val resume = this.intent.extras?.getSerializable("resume")
if (resume == null) {
video = this.intent.extras?.getSerializable("video") as VideoModel
isResume = false
} else {
video = PlaybackSingleton.video!!
isResume = true
}
binding.tittleVideoTxt.text = this.video.name
binding.viewsTxt.text = "${this.video.views} ${getString(R.string.view_text)}"
binding.userTxt.text = this.video.username
binding.descriptionVideoTxt.text = this.video.description
val haveDescription = this.video.description.endsWith("...")
if (haveDescription) {
showMoreBtn.visibility = View.VISIBLE
binding.showMoreBtn.visibility = View.VISIBLE
}
hostTxt.text = this.video.userHost
binding.hostTxt.text = this.video.userHost
// Check if user had profile image
if (this.video.userImageUrl != "")
Picasso.get().load("https://" + ManagerSingleton.url + this.video.userImageUrl).into(userImg)
if (this.video.userImageUrl != "") {
Picasso.get().load("https://" + ManagerSingleton.url + this.video.userImageUrl).into(binding.userImg)
}
// Load the video
videoView.loadUrl("https://" + ManagerSingleton.url + this.video.embedUrl)
} catch (err: Exception) {
err.printStackTrace()
}
@ -87,29 +120,95 @@ class ReproductorActivity : AppCompatActivity() {
this.getComments()
subscribeBtn.setOnClickListener { subscribe() }
likeLayout.setOnClickListener { rate("like") }
dislikeLayout.setOnClickListener { rate("dislike") }
commentaryBtn.setOnClickListener { makeComment() }
showMoreBtn.setOnClickListener { getDescription() }
shareLayout.setOnClickListener { shareIntent() }
reportLayout.setOnClickListener { reportIntent() }
binding.subscribeBtn.setOnClickListener { subscribe() }
binding.likeLayout.setOnClickListener { rate("like") }
binding.dislikeLayout.setOnClickListener { rate("dislike") }
binding.commentBox.commentaryBtn.setOnClickListener { makeComment() }
binding.showMoreBtn.setOnClickListener { getDescription() }
binding.shareLayout.setOnClickListener { shareIntent() }
binding.reportLayout.setOnClickListener { reportIntent() }
fullscreenButton.setOnClickListener { toggleFullscreen() }
fullscreenButton2.setOnClickListener { toggleFullscreen() }
binding.downloadLayout!!.setOnClickListener { downloadVideo() }
userImg.setOnClickListener {
binding.userImg.setOnClickListener {
val intent = Intent(this, ChannelActivity::class.java)
intent.putExtra("channel", video.getAccount())
intent.putExtra("channel", video.getChannel())
startActivity(intent)
}
AsyncTask.execute {
videoPlayback = this.clientVideo.getVideo(this.video.uuid)
// TODO: Make this configurable
// val bufferSize = 1024 * 1024 // 1mb
// val allocator = DefaultAllocator(true, bufferSize)
// val loadControl = DefaultLoadControl.Builder()
// .setAllocator(allocator)
// .build()
runOnUiThread {
try {
if (PlaybackSingleton.player == null || !PlaybackSingleton.player!!.playWhenReady) {
PlaybackSingleton.player = ExoPlayer.Builder(this)
//.setSeekBackIncrementMs(10000)
//.setSeekForwardIncrementMs(10000)
//.setLoadControl(loadControl)
.build()
}
player = PlaybackSingleton.player!!
binding.exoPlayer.player = player
binding.exoPlayer
player.addListener(
object : Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) {
super.onPlaybackStateChanged(playbackState)
val controls = binding.exoPlayer.findViewById<LinearLayout>(R.id.exo_center_controls)
if (playbackState == Player.STATE_BUFFERING || playbackState == Player.STATE_IDLE) {
controls.visibility = View.INVISIBLE
} else if (playbackState == Player.STATE_READY) {
controls.visibility = View.VISIBLE
}
}
}
)
println("----- video --------")
println(videoPlayback.streamingData?.playlistUrl)
if (!isResume) {
val mediaItem = MediaItem.Builder()
.setUri(videoPlayback.streamingData?.playlistUrl!!)
.setMediaMetadata(
MediaMetadata.Builder()
.setArtist(videoPlayback.username)
.setTitle(videoPlayback.name)
.setArtworkUri(Uri.parse("https://${ManagerSingleton.url}${videoPlayback.thumbUrl}"))
.build(),
).build()
PlaybackSingleton.setData(mediaItem, video)
}
// Start the playback.
// TODO: Setting for autoplay
// player.play()
} catch (err: Exception) {
err.printStackTrace()
}
}
}
}
private fun subscribe() {
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val res = this._actions.subscribe(ManagerSingleton.token.token, video.getAccount())
}
val res = this.actions.subscribe(ManagerSingleton.token.token, video.getChannel())
if (res == 1) {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.subscribeMsg), this)
ManagerSingleton.toast(getString(R.string.subscribeMsg), this)
this.changeSubscribeBtn(true)
}
}
@ -118,12 +217,13 @@ class ReproductorActivity : AppCompatActivity() {
private fun unSubscribe() {
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val res = this._actions.unSubscribe(ManagerSingleton.token.token, video.getAccount())
}
val res = this.actions.unSubscribe(ManagerSingleton.token.token, video.getChannel())
if (res == 1) {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.unSubscribeMsg), this)
ManagerSingleton.toast(getString(R.string.unSubscribeMsg), this)
this.changeSubscribeBtn(false)
}
}
@ -132,18 +232,19 @@ class ReproductorActivity : AppCompatActivity() {
private fun rate(rate: String) {
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val res = this._actions.rate(ManagerSingleton.token.token, this.video.id, rate)
}
val res = this.actions.rate(ManagerSingleton.token.token, this.video.id, rate)
if (res == 1) {
runOnUiThread {
ManagerSingleton.Toast(getString(R.string.rateMsg), this)
ManagerSingleton.toast(getString(R.string.rateMsg), this)
if (rate == "like") {
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike))
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
binding.textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike))
binding.textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
} else if (rate == "dislike") {
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.colorDislike))
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
binding.textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.colorDislike))
binding.textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
}
}
}
@ -152,22 +253,23 @@ class ReproductorActivity : AppCompatActivity() {
private fun getRate() {
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
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 {
when (rate) {
"like" -> {
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike))
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
binding.textViewLike.setTextColor(ContextCompat.getColor(this, R.color.colorLike))
binding.textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
}
"dislike" -> {
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.colorDislike))
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
binding.textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.colorDislike))
binding.textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
}
else -> {
textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
binding.textViewLike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
binding.textViewDislike.setTextColor(ContextCompat.getColor(this, R.color.primary_dark_material_light))
}
}
}
@ -177,9 +279,10 @@ class ReproductorActivity : AppCompatActivity() {
private fun getSubscription() {
val account = this.video.nameChannel + "@" + this.video.userHost
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
val isSubscribed = this._actions.getSubscription(ManagerSingleton.token.token, account)
}
val isSubscribed = this.actions.getSubscription(ManagerSingleton.token.token, account)
runOnUiThread {
this.changeSubscribeBtn(isSubscribed)
}
@ -188,17 +291,17 @@ class ReproductorActivity : AppCompatActivity() {
private fun changeSubscribeBtn(subscribed: Boolean) {
if (subscribed) {
subscribeBtn.text = getText(R.string.unSubscribeBtn)
subscribeBtn.setOnClickListener { this.unSubscribe() }
binding.subscribeBtn.text = getText(R.string.unSubscribeBtn)
binding.subscribeBtn.setOnClickListener { this.unSubscribe() }
} else {
subscribeBtn.text = getText(R.string.subscribeBtn)
subscribeBtn.setOnClickListener { this.subscribe() }
binding.subscribeBtn.text = getText(R.string.subscribeBtn)
binding.subscribeBtn.setOnClickListener { this.subscribe() }
}
}
private fun setDataComments(data: ArrayList<CommentaryModel>) {
// Set data for RecyclerView
viewAdapter = CommentariesAdapter(data)
viewAdapter = CommentariesAdapter(data).setFragmentManager(supportFragmentManager)
recyclerView = findViewById<RecyclerView>(R.id.listCommentaries).apply {
// use this setting to improve performance if you know that changes
@ -223,20 +326,20 @@ class ReproductorActivity : AppCompatActivity() {
}
private fun makeComment() {
if (commentaryText.text.toString() == "") {
ManagerSingleton.Toast(getString(R.string.emptyCommentaryMsg), this)
if (binding.commentBox.commentaryText.text.toString() == "") {
ManagerSingleton.toast(getString(R.string.emptyCommentaryMsg), this)
return
}
val text = commentaryText.text.toString()
val text = binding.commentBox.commentaryText.text.toString()
AsyncTask.execute {
val res = this.client.makeCommentary(ManagerSingleton.token.token, this.video.id, text)
runOnUiThread {
if (res) {
ManagerSingleton.Toast(getString(R.string.makedCommentaryMsg), this)
commentaryText.text.clear()
ManagerSingleton.toast(getString(R.string.makedCommentaryMsg), this)
binding.commentBox.commentaryText.text?.clear()
this.getComments()
} else {
ManagerSingleton.Toast(getString(R.string.errorCommentaryMsg), this)
ManagerSingleton.toast(getString(R.string.errorCommentaryMsg), this)
}
}
}
@ -247,21 +350,23 @@ class ReproductorActivity : AppCompatActivity() {
if (ManagerSingleton.user.status == 1) {
this.getRate()
this.getSubscription()
actionsLayout.visibility = View.VISIBLE
subscribeBtn.visibility = View.VISIBLE
commentaryLayout.visibility = View.VISIBLE
binding.actionsLayout.visibility = View.VISIBLE
binding.subscribeBtn.visibility = View.VISIBLE
binding.commentBox.commentaryLayout.visibility = View.VISIBLE
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(binding.commentBox.userImgCom)
}
} else {
binding.commentBox.commentaryLayout.visibility = View.GONE
}
}
fun getDescription() {
private fun getDescription() {
AsyncTask.execute {
val fullDescription = this.videos.fullDescription(this.video.id)
runOnUiThread {
descriptionVideoTxt.text = fullDescription
showMoreBtn.visibility = View.GONE
binding.descriptionVideoTxt.text = fullDescription
binding.showMoreBtn.visibility = View.GONE
}
}
}
@ -285,6 +390,7 @@ class ReproductorActivity : AppCompatActivity() {
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
builder.setView(dialog)
.setTitle(R.string.reportDialog)
// Add action buttons
.setPositiveButton(R.string.reportBtn) { _, _ ->
val reason = inputReason.text.toString()
@ -299,19 +405,81 @@ class ReproductorActivity : AppCompatActivity() {
private fun reportVideo(reason: String) {
AsyncTask.execute {
val res = _actions.reportVideo(video.id, reason, ManagerSingleton.token.token)
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)
ManagerSingleton.toast(getText(R.string.reportDialogMsg).toString(), this)
} else {
ManagerSingleton.toast(getText(R.string.errorMsg).toString(), this)
}
}
}
}
private fun toggleFullscreen() {
if (isFullscreen) {
binding.nonFullScreen.visibility = View.VISIBLE
binding.fullScreenExo.visibility = View.GONE
binding.exoPlayer.player = player
binding.fullscreenPlayer.player = null
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
val attrs = 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
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
isFullscreen = false
} else {
val matchParent = WindowManager.LayoutParams.MATCH_PARENT
binding.nonFullScreen.visibility = View.GONE
binding.fullScreenExo.visibility = View.VISIBLE
binding.exoPlayer.player = null
binding.fullscreenPlayer.player = player
setFullscreen(window)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
isFullscreen = true
}
}
private fun downloadVideo() {
val downloadFile = videoPlayback.streamingData?.downloadFiles?.first()
if (downloadFile != null) {
val manager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
val request = DownloadManager.Request(Uri.parse(downloadFile.url))
val fileName = "${videoPlayback.name}-${downloadFile.resolution}.${downloadFile.url.split('.').last()}"
try {
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setTitle(fileName)
.setDescription(getString(R.string.downloadText))
.setDestinationInExternalPublicDir(
android.os.Environment.DIRECTORY_DOWNLOADS,
fileName
)
manager.enqueue(request)
ManagerSingleton.toast(getString(R.string.downloadStarted), this)
} catch (_: Exception) {
ManagerSingleton.toast(getString(R.string.downloadFailed), this)
}
} else {
ManagerSingleton.toast(getString(R.string.downloadFailed), this)
}
}
override fun onDestroy() {
if (!player.isPlaying) {
PlaybackSingleton.release()
}
super.onDestroy()
}
internal inner class WebClient : WebChromeClient() {
private var mCustomView: View? = null
private var mCustomViewCallback: WebChromeClient.CustomViewCallback? = null
@ -320,19 +488,21 @@ class ReproductorActivity : AppCompatActivity() {
override fun getDefaultVideoPoster(): Bitmap? {
AsyncTask.execute {
this@ReproductorActivity._actions.watchVideo(this@ReproductorActivity.video.id, ManagerSingleton.token.token)
this@ReproductorActivity.actions.watchVideo(this@ReproductorActivity.video.id, ManagerSingleton.token.token)
}
return if (mCustomView == null) {
null
} else BitmapFactory.decodeResource(this@ReproductorActivity.resources, 2130837573)
} else {
BitmapFactory.decodeResource(this@ReproductorActivity.resources, 2130837573)
}
}
override fun onHideCustomView() {
try {
this@ReproductorActivity.nonFullScreen.visibility = View.VISIBLE
this@ReproductorActivity.fullScreen.visibility = View.GONE
this@ReproductorActivity.fullScreen.removeView(this.mCustomView)
this@ReproductorActivity.binding.nonFullScreen.visibility = View.VISIBLE
this@ReproductorActivity.binding.fullScreen.visibility = View.GONE
this@ReproductorActivity.binding.fullScreen.removeView(this.mCustomView)
this.mCustomView = null
this.mCustomViewCallback!!.onCustomViewHidden()
@ -346,8 +516,7 @@ class ReproductorActivity : AppCompatActivity() {
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()
}
}
@ -362,23 +531,17 @@ class ReproductorActivity : AppCompatActivity() {
this.mOriginalSystemUiVisibility = this@ReproductorActivity.window.decorView.systemUiVisibility
this.mOriginalOrientation = this@ReproductorActivity.requestedOrientation
this.mCustomViewCallback = paramCustomViewCallback
val match_parent = WindowManager.LayoutParams.MATCH_PARENT
val matchParent = WindowManager.LayoutParams.MATCH_PARENT
this@ReproductorActivity.nonFullScreen.visibility = View.GONE
this@ReproductorActivity.fullScreen.visibility = View.VISIBLE
this@ReproductorActivity.binding.nonFullScreen.visibility = View.GONE
this@ReproductorActivity.binding.fullScreen.visibility = View.VISIBLE
this@ReproductorActivity.fullScreen.addView(paramView, FrameLayout.LayoutParams(match_parent, match_parent))
this@ReproductorActivity.binding.fullScreen.addView(paramView, FrameLayout.LayoutParams(matchParent, matchParent))
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
setFullscreen(this@ReproductorActivity.window)
this@ReproductorActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
}
}

View File

@ -1,161 +0,0 @@
package org.libre.agosto.p2play
import android.annotation.TargetApi
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.preference.ListPreference
import android.preference.Preference
import android.preference.PreferenceActivity
import android.preference.PreferenceFragment
import android.preference.PreferenceManager
import android.preference.RingtonePreference
import android.text.TextUtils
import android.util.Log
import android.view.MenuItem
/**
* A [PreferenceActivity] that presents a set of application settings. On
* handset devices, settings are presented as a single list. On tablets,
* settings are split by category, with category headers shown to the left of
* the list of settings.
*
* See [Android Design: Settings](http://developer.android.com/design/patterns/settings.html)
* for design guidelines and the [Settings API Guide](http://developer.android.com/guide/topics/ui/settings.html)
* for more information on developing a Settings UI.
*/
class SettingsActivity : AppCompatPreferenceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupActionBar()
}
override fun onBackPressed() {
super.onBackPressed()
ManagerSingleton.Toast(getString(R.string.pref_message_exit), this)
}
/**
* Set up the [android.app.ActionBar], if the API is available.
*/
private fun setupActionBar() {
supportActionBar?.setDisplayHomeAsUpEnabled(false)
}
/**
* {@inheritDoc}
*/
override fun onIsMultiPane(): Boolean {
return isXLargeTablet(this)
}
/**
* {@inheritDoc}
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
override fun onBuildHeaders(target: List<PreferenceActivity.Header>) {
loadHeadersFromResource(R.xml.pref_headers, target)
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
override fun isValidFragment(fragmentName: String): Boolean {
return PreferenceFragment::class.java.name == fragmentName
|| GeneralPreferenceFragment::class.java.name == fragmentName
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
class GeneralPreferenceFragment : PreferenceFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_general)
setHasOptionsMenu(true)
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("hostP2play"))
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if (id == android.R.id.home) {
startActivity(Intent(activity, SettingsActivity::class.java))
return true
}
return super.onOptionsItemSelected(item)
}
}
companion object {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private val sBindPreferenceSummaryToValueListener = Preference.OnPreferenceChangeListener { preference, value ->
val stringValue = value.toString()
if (preference is ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
val listPreference = preference
val index = listPreference.findIndexOfValue(stringValue)
// Set the summary to reflect the new value.
preference.setSummary(
if (index >= 0)
listPreference.entries[index]
else
null)
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.summary = stringValue
}
true
}
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private fun isXLargeTablet(context: Context): Boolean {
return context.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK >= Configuration.SCREENLAYOUT_SIZE_XLARGE
}
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
* @see .sBindPreferenceSummaryToValueListener
*/
private fun bindPreferenceSummaryToValue(preference: Preference) {
// Set the listener to watch for value changes.
preference.onPreferenceChangeListener = sBindPreferenceSummaryToValueListener
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.context)
.getString(preference.key, ""))
}
}
}

View File

@ -0,0 +1,31 @@
package org.libre.agosto.p2play
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceFragmentCompat
class SettingsActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_activity)
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment())
.commit()
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
override fun onDestroy() {
super.onDestroy()
ManagerSingleton.reloadSettings()
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
}

View File

@ -3,36 +3,34 @@ package org.libre.agosto.p2play
import android.content.Intent
import android.content.SharedPreferences
import android.os.AsyncTask
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.preference.PreferenceManager
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import org.libre.agosto.p2play.ajax.Auth
import java.lang.Exception
class SplashActivity : AppCompatActivity() {
lateinit var settings: SharedPreferences
lateinit var editor: SharedPreferences.Editor
val client: Auth = Auth()
val _db = Database(this)
val db = Database(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
settings = PreferenceManager.getDefaultSharedPreferences(this)
ManagerSingleton.settings = settings
ManagerSingleton.db = db
ManagerSingleton.nfsw = settings.getBoolean("show_nfsw", false)
ManagerSingleton.videos_count = settings.getString("videos_count", "15").toInt()
ManagerSingleton.reloadSettings()
val host = settings.getString("hostP2play", "")
val lastHost = settings.getString("last_host", "")
if (host != "") {
if (lastHost != host) {
_db.logout()
Handler().postDelayed({
startHostActivity()
}, 2000)
@ -40,8 +38,7 @@ class SplashActivity : AppCompatActivity() {
ManagerSingleton.url = host
checkUser()
}
}
else{
} else {
Handler().postDelayed({
startHostActivity()
}, 2000)
@ -49,42 +46,37 @@ class SplashActivity : AppCompatActivity() {
}
private fun checkUser() {
Log.d("was", "Chequed")
Log.d("was", "Checked")
try {
val token = _db.getToken()
val user = _db.getUser()
val token = db.getToken()
val user = db.getUser()
AsyncTask.execute {
if (Looper.myLooper() == null)
if (Looper.myLooper() == null) {
Looper.prepare()
}
if (token.status == 1 && user.status == 1) {
val client_id = settings.getString("client_id", "")
val client_secret = settings.getString("client_secret", "")
val clientId = settings.getString("client_id", "")!!
val clientSecret = settings.getString("client_secret", "")!!
val newToken = client.refreshToken(token, client_id, client_secret)
val newToken = client.refreshToken(token, clientId, clientSecret)
when (token.status.toString()) {
"1" -> {
_db.newToken(newToken)
db.newToken(newToken)
ManagerSingleton.token = newToken
ManagerSingleton.user = user
}
else -> _db.logout()
else -> ManagerSingleton.logout()
}
} else {
_db.logout()
ManagerSingleton.logout()
}
startApp()
Log.d("Aqui", "81")
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
Log.d("Aqui", "89")
Handler().postDelayed({
startApp()
}, 2000)

View File

@ -0,0 +1,130 @@
package org.libre.agosto.p2play.adapters
import android.content.Context
import android.content.Intent
import android.os.AsyncTask
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import org.libre.agosto.p2play.AccountActivity
import org.libre.agosto.p2play.ChannelActivity
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.ajax.Actions
import org.libre.agosto.p2play.models.ChannelModel
class ChannelAdapter(private val myDataset: ArrayList<ChannelModel>): RecyclerView.Adapter<ChannelAdapter.ViewHolder>() {
private val actionsService = Actions()
lateinit var parent: FragmentActivity
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
// Define click listener for the ViewHolder's View
val channelImage: ImageView = view.findViewById(R.id.channelImage)
val channelName: TextView = view.findViewById(R.id.channelName)
val channelDescription: TextView = view.findViewById(R.id.channelDescription)
val subscribeButton: Button = view.findViewById(R.id.subscribeBtn)
val context: Context = view.context
var isSubscribed: Boolean = false
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChannelAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.view_channel, parent, false) as View
return ViewHolder(view)
}
override fun getItemCount() = myDataset.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.channelName.text = myDataset[position].name
holder.channelDescription.text = myDataset[position].description
if (myDataset[position].channelImg != "") {
Picasso.get().load("https://${ManagerSingleton.url}${myDataset[position].channelImg}").into(holder.channelImage)
} else {
holder.channelImage.setImageResource(R.drawable.default_avatar)
}
if (ManagerSingleton.user.status == 1) {
getSubscription(myDataset[position], holder)
} else {
holder.subscribeButton.visibility = View.GONE
}
holder.subscribeButton.setOnClickListener {
this.subscribeAction(myDataset[position], holder)
}
holder.channelImage.setOnClickListener {
this.launchChannelActivity(myDataset[position].getAccount())
}
holder.channelName.setOnClickListener {
this.launchChannelActivity(myDataset[position].getAccount())
}
}
private fun getSubscription(channel: ChannelModel, holder: ViewHolder) {
AsyncTask.execute {
holder.isSubscribed = actionsService.getSubscription(ManagerSingleton.token.token, channel.getAccount())
parent.runOnUiThread {
if (holder.isSubscribed) {
holder.subscribeButton.text = parent.getText(R.string.unSubscribeBtn)
} else {
holder.subscribeButton.text = parent.getText(R.string.subscribeBtn)
}
}
}
}
private fun subscribe(channel: ChannelModel, holder: ViewHolder) {
AsyncTask.execute {
val res = actionsService.subscribe(ManagerSingleton.token.token, channel.getAccount())
parent.runOnUiThread {
if (res == 1) {
holder.subscribeButton.text = parent.getString(R.string.unSubscribeBtn)
ManagerSingleton.toast(parent.getString(R.string.subscribeMsg), parent)
getSubscription(channel, holder)
} else {
ManagerSingleton.toast(parent.getString(R.string.errorMsg), parent)
}
}
}
}
private fun unSubscribe(channel: ChannelModel, holder: ViewHolder) {
AsyncTask.execute {
val res = actionsService.unSubscribe(ManagerSingleton.token.token, channel.getAccount())
parent.runOnUiThread {
if (res == 1) {
holder.subscribeButton.text = parent.getString(R.string.subscribeBtn)
ManagerSingleton.toast(parent.getString(R.string.unSubscribeMsg), parent)
getSubscription(channel, holder)
} else {
ManagerSingleton.toast(parent.getString(R.string.errorMsg), parent)
}
}
}
}
private fun subscribeAction(channel: ChannelModel, holder: ViewHolder) {
if (holder.isSubscribed) {
unSubscribe(channel, holder)
} else {
subscribe(channel, holder)
}
}
private fun launchChannelActivity (channelId: String) {
val intent = Intent(parent, ChannelActivity::class.java)
intent.putExtra("channel", channelId)
parent.startActivity(intent)
}
}

View File

@ -1,30 +1,35 @@
package org.libre.agosto.p2play.adapters
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
import android.os.AsyncTask
import android.support.v7.widget.RecyclerView
import android.os.Bundle
import android.text.Html
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import org.libre.agosto.p2play.*
import org.libre.agosto.p2play.AccountActivity
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.dialogs.ThreadDialog
import org.libre.agosto.p2play.models.CommentaryModel
import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStream
import java.io.Serializable
import java.net.URL
@Suppress("DEPRECATION")
class CommentariesAdapter(private val myDataset: ArrayList<CommentaryModel>) :
RecyclerView.Adapter<CommentariesAdapter.ViewHolder>() {
private lateinit var fragmentManager: FragmentManager
fun setFragmentManager(manager: FragmentManager): CommentariesAdapter {
this.fragmentManager = manager
return this
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
@ -33,6 +38,7 @@ class CommentariesAdapter(private val myDataset: ArrayList<CommentaryModel>) :
val userImg: ImageView
val username: TextView
val commentary: TextView
val replyBtn: TextView
val context: Context
init {
@ -40,17 +46,20 @@ class CommentariesAdapter(private val myDataset: ArrayList<CommentaryModel>) :
username = view.findViewById(R.id.userTxt)
commentary = view.findViewById(R.id.userCommentary)
userImg = view.findViewById(R.id.userCommentImg)
replyBtn = view.findViewById(R.id.replyBtn)
context = view.context
}
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): CommentariesAdapter.ViewHolder {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): ViewHolder {
// create a new view
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.view_commentary, parent, false) as View
// set the view's size, margins, paddings and layout parameters
return ViewHolder(view)
}
@ -67,13 +76,43 @@ class CommentariesAdapter(private val myDataset: ArrayList<CommentaryModel>) :
// holder.context.startActivity(intent)
// }
if(myDataset[position].userImageUrl!="")
Picasso.get().load("https://"+ManagerSingleton.url+myDataset[position].userImageUrl).into(holder.userImg);
if (myDataset[position].userImageUrl != "") {
Picasso.get().load("https://" + ManagerSingleton.url + myDataset[position].userImageUrl).into(holder.userImg)
}
holder.commentary.text = Html.fromHtml(myDataset[position].commentary)
holder.replyBtn.setOnClickListener { this.initRepliesDialog(myDataset[position]) }
if (myDataset[position].replies > 0) {
holder.replyBtn.text = holder.itemView.context.getString(R.string.see_replies, myDataset[position].replies)
}
// TODO: Support for view and account (is different than a video channel)
holder.userImg.setOnClickListener {
val intent = Intent(holder.context, AccountActivity::class.java)
intent.putExtra("accountId", myDataset[position].getAccount())
holder.context.startActivity(intent)
}
}
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = myDataset.size
private fun initRepliesDialog(commentData: CommentaryModel) {
val dialog = ThreadDialog()
val bundle = Bundle()
bundle.putSerializable("comment", commentData as Serializable)
dialog.arguments = bundle
dialog.fragmentManager2 = this.fragmentManager
val transaction = fragmentManager.beginTransaction()
// For a polished look, specify a transition animation.
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
// To make it fullscreen, use the 'content' root view as the container
// for the fragment, which is always the root view for the activity.
transaction
.add(android.R.id.content, dialog)
.addToBackStack("comments")
.commit()
}
}

View File

@ -1,53 +1,42 @@
package org.libre.agosto.p2play.adapters
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
import android.os.AsyncTask
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import org.libre.agosto.p2play.*
import org.libre.agosto.p2play.AccountActivity
import org.libre.agosto.p2play.ChannelActivity
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.ReproductorActivity
import org.libre.agosto.p2play.helpers.mapSeconds
import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStream
import java.io.Serializable
import java.net.URL
import java.util.concurrent.TimeUnit
class VideosAdapter(private val myDataset: ArrayList<VideoModel>) :
RecyclerView.Adapter<VideosAdapter.ViewHolder>() {
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
// Each data item is just a string in this case that is shown in a TextView.
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view){
val thumb: ImageView
val userImg: ImageView
val tittle: TextView
val description: TextView
val context: Context
init {
// Define click listener for the ViewHolder's View
tittle = view.findViewById(R.id.tittleTxt)
description = view.findViewById(R.id.descriptionTxt)
thumb = view.findViewById(R.id.thumb)
userImg = view.findViewById(R.id.userImg)
context = view.context
}
class ViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val thumb: ImageView = view.findViewById(R.id.thumb)
val userImg: ImageView = view.findViewById(R.id.userImg)
val title: TextView = view.findViewById(R.id.tittleTxt)
val description: TextView = view.findViewById(R.id.descriptionTxt)
val context: Context = view.context
val duration: TextView = view.findViewById(R.id.duration)
val isLive: TextView = view.findViewById(R.id.isLive)
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): VideosAdapter.ViewHolder {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// create a new view
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.view_video, parent, false) as View
@ -59,40 +48,38 @@ class VideosAdapter(private val myDataset: ArrayList<VideoModel>) :
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.tittle.text = myDataset[position].name
holder.title.text = myDataset[position].name
holder.title.setOnClickListener {
this.launchChannelActivity(myDataset[position] as Serializable, holder.context)
}
Picasso.get().load("https://" + ManagerSingleton.url + myDataset[position].thumbUrl).into(holder.thumb)
holder.thumb.setOnClickListener {
val intent = Intent(holder.context, ReproductorActivity::class.java)
intent.putExtra("video", myDataset[position] as Serializable)
holder.context.startActivity(intent)
this.launchChannelActivity(myDataset[position] as Serializable, holder.context)
}
holder.userImg.setOnClickListener {
val intent = Intent(holder.context, ChannelActivity::class.java)
intent.putExtra("channel", myDataset[position].getAccount())
intent.putExtra("channel", myDataset[position].getChannel())
holder.context.startActivity(intent)
}
if(myDataset[position].userImageUrl!="")
if (myDataset[position].userImageUrl != "") {
Picasso.get().load("https://" + ManagerSingleton.url + myDataset[position].userImageUrl).into(holder.userImg)
else
} else {
Picasso.get().load(R.drawable.default_avatar).into(holder.userImg)
}
val viewsText = holder.context.getString(R.string.view_text)
var timeText = holder.context.getString(R.string.timeSec_text)
var timeString = myDataset[position].duration.toString()
val seconds = myDataset[position].duration.toInt();
if(seconds > 60 && seconds < (60 * 60)){
timeText = holder.context.getString(R.string.timeMin_text)
timeString = (seconds / 60).toString() + ":" + (seconds % 60).toString()
}
else if(seconds > (60 * 60)){
timeText = holder.context.getString(R.string.timeHrs_text)
timeString = (seconds / 60 / 60).toString() + ":" + (seconds / 60 % 60).toString()
}
val seconds = myDataset[position].duration.toInt()
val timeString = mapSeconds(seconds)
holder.description.text = myDataset[position].username+" - "+myDataset[position].views+" "+viewsText+" - "+timeString+" "+timeText
holder.duration.text = timeString
holder.description.text = myDataset[position].username + " - " + myDataset[position].views + " " + viewsText
if (myDataset[position].isLive) {
holder.isLive.visibility = View.VISIBLE
}
}
// Return the size of your dataset (invoked by the layout manager)
@ -109,5 +96,9 @@ class VideosAdapter(private val myDataset: ArrayList<VideoModel>) :
notifyItemRangeInserted(lastPos, newItems.size)
}
private fun launchChannelActivity(data: Serializable, context: Context) {
val intent = Intent(context, ReproductorActivity::class.java)
intent.putExtra("video", data)
context.startActivity(intent)
}
}

View File

@ -0,0 +1,58 @@
package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import com.google.gson.Gson
import org.libre.agosto.p2play.models.AccountModel
import org.libre.agosto.p2play.models.ChannelModel
import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStreamReader
class Accounts : Client() {
fun get(accountId: String): AccountModel {
val con = this.newCon("accounts/$accountId", "GET")
lateinit var account: AccountModel
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
account = Gson().fromJson(response, AccountModel::class.java)
}
} catch (err: Exception) {
err.printStackTrace()
}
return account
}
fun getChannels(accountId: String): ArrayList<ChannelModel> {
val con = this.newCon("accounts/$accountId/video-channels", "GET")
val channels = arrayListOf<ChannelModel>()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"data" -> {
data.beginArray()
while (data.hasNext()) {
val channel = ChannelModel()
channel.parseChannel(data)
channels.add(channel)
}
data.endArray()
}
else -> data.skipValue()
}
}
data.endObject()
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
return channels
}
}

View File

@ -6,7 +6,7 @@ import java.io.InputStreamReader
class Actions : Client() {
fun subscribe(token: String, account: String): Int {
val con = this._newCon("users/me/subscriptions","POST", token)
val con = this.newCon("users/me/subscriptions", "POST", token)
val params: String = "uri=$account"
con.outputStream.write(params.toByteArray())
var response = 0
@ -15,8 +15,7 @@ class Actions: Client() {
if (con.responseCode == 204) {
response = 1
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = -1
}
@ -26,15 +25,14 @@ class Actions: Client() {
}
fun unSubscribe(token: String, account: String): Int {
val con = this._newCon("users/me/subscriptions/$account","DELETE", token)
val con = this.newCon("users/me/subscriptions/$account", "DELETE", token)
var response = 0
try {
if (con.responseCode == 204) {
response = 1
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = -1
}
@ -44,7 +42,7 @@ class Actions: Client() {
}
fun getSubscription(token: String, account: String): Boolean {
val 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
try {
@ -65,8 +63,7 @@ class Actions: Client() {
}
data.close()
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
isSubscribed = false
}
@ -76,7 +73,7 @@ class Actions: Client() {
}
fun rate(token: String, id_video: Int, rate: String): Int {
val con = this._newCon("videos/$id_video/rate","PUT", token)
val con = this.newCon("videos/$id_video/rate", "PUT", token)
val params = "rating=$rate"
con.outputStream.write(params.toByteArray())
var response = 0
@ -85,8 +82,7 @@ class Actions: Client() {
if (con.responseCode == 204) {
response = 1
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = -1
}
@ -96,7 +92,7 @@ class Actions: Client() {
}
fun getRate(token: String, id_video: Int): String {
val 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"
try {
@ -117,8 +113,7 @@ class Actions: Client() {
}
con.disconnect()
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
rating = "none"
}
@ -128,7 +123,7 @@ class Actions: Client() {
}
fun reportVideo(videoId: Int, reason: String, token: String): Boolean {
val con = this._newCon("videos/$videoId/abuse", "POST", token)
val con = this.newCon("videos/$videoId/abuse", "POST", token)
val params = "reason=$reason"
con.outputStream.write(params.toByteArray())
@ -146,7 +141,7 @@ class Actions: Client() {
}
fun watchVideo(videoId: Int, token: String): Boolean {
val con = this._newCon("videos/$videoId/watching", "PUT", token)
val con = this.newCon("videos/$videoId/watching", "PUT", token)
val params = "currentTime=1"
con.outputStream.write(params.toByteArray())

View File

@ -4,7 +4,6 @@ package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import android.util.JsonToken
import android.util.Log
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.models.TokenModel
import org.libre.agosto.p2play.models.UserModel
import java.io.InputStreamReader
@ -12,15 +11,20 @@ import java.io.InputStreamReader
class Auth : Client() {
private val stockParams = "grant_type=password"
fun login(username: String, password: String, client_id: String, client_secret: String): TokenModel{
val con = this._newCon("users/token","POST")
fun login(username: String, password: String, client_id: String, client_secret: String, twoFactorCode: String? = null): TokenModel {
val con = this.newCon("users/token", "POST")
val params = "$stockParams&username=$username&password=$password&client_id=$client_id&client_secret=$client_secret"
if (twoFactorCode !== null) {
con.setRequestProperty("x-peertube-otp", twoFactorCode)
}
con.outputStream.write(params.toByteArray())
val token = TokenModel()
try {
if(con.responseCode==200){
when (con.responseCode) {
200 -> {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
@ -37,13 +41,16 @@ class Auth: Client() {
data.endObject()
data.close()
token.status = 1
}
else{
401 -> {
// User require 2FA code
token.status = -2
}
else -> {
Log.d("Status", con.responseMessage)
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
token.status = 0
}
@ -53,7 +60,7 @@ class Auth: Client() {
}
fun register(username: String, password: String, email: String): Int {
val con = this._newCon("users/register","POST")
val con = this.newCon("users/register", "POST")
val params = "username=$username&password=$password&email=$email"
con.outputStream.write(params.toByteArray())
@ -63,19 +70,17 @@ class Auth: Client() {
if (con.responseCode == 204) {
response = 1
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = -1
}
con.disconnect()
return response
}
fun refreshToken(token: TokenModel, client_id: String, client_secret: String): TokenModel {
val con = this._newCon("users/token", "POST", token.token)
val con = this.newCon("users/token", "POST", token.token)
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())
// val token = TokenModel()
@ -98,13 +103,10 @@ class Auth: Client() {
data.endObject()
data.close()
token.status = 1
}
else{
} else {
Log.d("Status", con.responseMessage)
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
token.status = 0
}
@ -114,11 +116,10 @@ class Auth: Client() {
}
fun me(token: String): UserModel {
val con = this._newCon("users/me","GET", token)
val con = this.newCon("users/me", "GET", token)
val user = UserModel()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
@ -148,8 +149,7 @@ class Auth: Client() {
}
}
data.endObject()
}
else{
} else {
data.skipValue()
}
}
@ -165,13 +165,10 @@ class Auth: Client() {
data.endObject()
data.close()
user.status = 1
}
else{
} else {
Log.d("Status", con.responseMessage)
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
user.status = 0
}
@ -179,5 +176,4 @@ class Auth: Client() {
con.disconnect()
return user
}
}

View File

@ -1,23 +1,13 @@
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")
val con = this.newCon("video-channels/$account", "GET")
var channel = ChannelModel()
try {
if (con.responseCode == 200) {

View File

@ -5,18 +5,15 @@ import android.util.Log
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.models.HostModel
import java.io.InputStreamReader
import java.io.Reader
import java.net.HttpURLConnection
import java.net.URL
open class Client {
protected fun _newCon(uri: String, method: String, token: String = ""): HttpURLConnection {
protected fun newCon(uri: String, method: String, token: String = ""): HttpURLConnection {
val url = URL("https://${ManagerSingleton.url}/api/v1/$uri")
val con = url.openConnection() as HttpURLConnection
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("Accept", "*/*")
@ -28,15 +25,16 @@ open class Client {
con.connectTimeout = 60000
con.readTimeout = 60000
if(method == "POST")
if (method == "POST") {
con.doOutput = true
}
Log.d("Petition", url.toString())
return con
}
fun getKeys(): HostModel {
val con = this._newCon("oauth-clients/local","GET")
val con = this.newCon("oauth-clients/local", "GET")
val keys = HostModel("", "")
try {
if (con.responseCode == 200) {
@ -66,6 +64,4 @@ open class Client {
con.disconnect()
return keys
}
}

View File

@ -1,13 +1,11 @@
package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import android.util.JsonToken
import android.util.Log
import org.libre.agosto.p2play.models.CommentaryModel
import java.io.InputStreamReader
class Comments : Client() {
private fun parseCommentaries(data: JsonReader): ArrayList<CommentaryModel> {
val commentaries = arrayListOf<CommentaryModel>()
data.beginObject()
@ -32,7 +30,7 @@ class Comments: Client() {
fun getCommentaries(videoId: Int): ArrayList<CommentaryModel> {
var commentaries = arrayListOf<CommentaryModel>()
val con = this._newCon("videos/$videoId/comment-threads", "GET")
val con = this.newCon("videos/$videoId/comment-threads", "GET")
try {
if (con.responseCode == 200) {
@ -49,7 +47,7 @@ class Comments: Client() {
}
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 = "text=$text"
con.outputStream.write(params.toByteArray())
@ -59,13 +57,11 @@ class Comments: Client() {
if (con.responseCode == 200) {
con.disconnect()
response = true
}
else{
} else {
Log.d("Status", con.responseMessage)
response = false
}
}
catch (err: Exception){
} catch (err: Exception) {
err.printStackTrace()
response = false
}
@ -74,4 +70,67 @@ class Comments: Client() {
return response
}
fun getCommentariesThread(videoId: Int, threadId: Int): ArrayList<CommentaryModel> {
var commentaries = arrayListOf<CommentaryModel>()
val con = this.newCon("videos/$videoId/comment-threads/$threadId", "GET")
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"children" -> {
data.beginArray()
while (data.hasNext()) {
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"comment" -> {
val comment = CommentaryModel()
comment.parseCommentary(data)
commentaries.add(comment)
}
else -> data.skipValue()
}
}
data.endObject()
}
data.endArray()
}
else -> data.skipValue()
}
}
data.endObject()
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return commentaries
}
fun replyThread(token: String, videoId: Int, threadId: Int, text: String): Boolean {
val con = this.newCon("videos/$videoId/comments/$threadId", "POST", token)
val params = "text=$text"
con.outputStream.write(params.toByteArray())
val response: Boolean = try {
if (con.responseCode == 200) {
con.disconnect()
true
} else {
Log.d("Status", con.responseMessage)
false
}
} catch (err: Exception) {
err.printStackTrace()
false
}
con.disconnect()
return response
}
}

View File

@ -1,7 +1,6 @@
package org.libre.agosto.p2play.ajax
import android.util.JsonReader
import android.util.JsonToken
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.models.VideoModel
import java.io.InputStreamReader
@ -30,13 +29,12 @@ class Videos: Client() {
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 count = ManagerSingleton.videos_count
var params = "start=$start&count=$count&sort=$sort&nsfw=$nsfw"
if(filter != "")
params+="&filter=$filter"
val con = this._newCon("videos?$params","GET")
val count = ManagerSingleton.videosCount
var params = "start=$start&count=$count&sort=$sort&nsfw=$nsfw&isLocal=$isLocal"
val con = this.newCon("videos?$params", "GET")
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
@ -65,13 +63,13 @@ class Videos: Client() {
}
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> {
val count = ManagerSingleton.videos_count
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val con = this._newCon("users/me/videos?$params","GET", token)
val con = this.newCon("users/me/videos?$params", "GET", token)
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
@ -89,9 +87,9 @@ class Videos: Client() {
}
fun videoSubscriptions(token: String, start: Int = 0): ArrayList<VideoModel> {
val count = ManagerSingleton.videos_count
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val 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>()
try {
if (con.responseCode == 200) {
@ -99,6 +97,10 @@ class Videos: Client() {
val data = JsonReader(response)
videos = parseVideos(data)
data.close()
} else {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
print(data)
}
} catch (err: Exception) {
err.printStackTrace()
@ -109,9 +111,9 @@ class Videos: Client() {
}
fun videoHistory(token: String, start: Int = 0): ArrayList<VideoModel> {
val count = ManagerSingleton.videos_count
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val con = this._newCon("users/me/history/videos?$params","GET", token)
val con = this.newCon("users/me/history/videos?$params", "GET", token)
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
@ -129,10 +131,10 @@ class Videos: Client() {
}
fun search(text: String, start: Int = 0): ArrayList<VideoModel> {
val count = ManagerSingleton.videos_count
val count = ManagerSingleton.videosCount
val nsfw = ManagerSingleton.nfsw
val params = "search=$text&start=$start&count=$count&nsfw=$nsfw"
val con = this._newCon("search/videos?$params","GET")
val con = this.newCon("search/videos?$params", "GET")
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
@ -149,7 +151,7 @@ class Videos: Client() {
}
fun fullDescription(videoId: Int): String {
val con = this._newCon("videos/$videoId/description","GET")
val con = this.newCon("videos/$videoId/description", "GET")
var description = ""
try {
if (con.responseCode == 200) {
@ -176,9 +178,9 @@ class Videos: Client() {
}
fun channelVideos(account: String, start: Int): ArrayList<VideoModel> {
val count = ManagerSingleton.videos_count
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val con = this._newCon("video-channels/$account/videos?$params","GET")
val con = this.newCon("video-channels/$account/videos?$params", "GET")
var videos = arrayListOf<VideoModel>()
try {
if (con.responseCode == 200) {
@ -198,4 +200,42 @@ class Videos: Client() {
fun getMostLikedVideos(start: Int = 0): ArrayList<VideoModel> {
return this.getVideos(start, "-likes")
}
fun getVideo(uuid: String): VideoModel {
val con = this.newCon("videos/$uuid", "GET")
val video = VideoModel()
try {
if (con.responseCode == 200) {
val response = InputStreamReader(con.inputStream)
val data = JsonReader(response)
video.parseVideo(data)
data.close()
}
} catch (err: Exception) {
err.printStackTrace()
}
con.disconnect()
return video
}
fun accountVideos(account: String, start: Int): ArrayList<VideoModel> {
val count = ManagerSingleton.videosCount
val params = "start=$start&count=$count"
val con = this.newCon("accounts/$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
}
}

View File

@ -0,0 +1,128 @@
package org.libre.agosto.p2play.dialogs
import android.app.Dialog
import android.os.AsyncTask
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso
import org.libre.agosto.p2play.ManagerSingleton
import org.libre.agosto.p2play.R
import org.libre.agosto.p2play.adapters.CommentariesAdapter
import org.libre.agosto.p2play.ajax.Comments
import org.libre.agosto.p2play.databinding.DialogThreadBinding
import org.libre.agosto.p2play.models.CommentaryModel
class ThreadDialog : DialogFragment() {
private lateinit var comment: CommentaryModel
lateinit var fragmentManager2: FragmentManager
private val client: Comments = Comments()
private var _binding: DialogThreadBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
// The system calls this to get the DialogFragment's layout, regardless of
// whether it's being displayed as a dialog or an embedded fragment.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
// Inflate the layout to use as a dialog or embedded fragment.
_binding = DialogThreadBinding.inflate(inflater, container, false)
val view = binding.root
comment = arguments?.getSerializable("comment") as CommentaryModel
binding.commentThread?.userTxt?.text = comment.username
binding.commentThread?.userCommentary?.text = comment.commentary
Picasso.get().load("https://${ManagerSingleton.url}${comment.userImageUrl}").into(binding.commentThread?.userCommentImg)
binding.commentThread?.replyBtn?.visibility = View.GONE
if (ManagerSingleton.user.status == 1) {
binding.commentBox?.commentaryText?.setText("${comment.nameChannel}@${comment.userHost} ")
if (ManagerSingleton.user.avatar != "") {
Picasso.get().load("https://${ManagerSingleton.url}${ManagerSingleton.user.avatar}").into(binding.commentBox?.userImgCom)
}
binding.commentBox?.commentaryText?.requestFocus()
binding.commentBox?.commentaryBtn?.setOnClickListener { this.replyThread() }
} else {
binding.commentBox?.commentaryLayout?.visibility = View.GONE
}
binding.materialToolbar.setTitle("Thread")
binding.materialToolbar.setNavigationIcon(R.drawable.baseline_arrow_back_24)
binding.materialToolbar.setNavigationOnClickListener {
dismiss()
this.fragmentManager2.popBackStack()
}
this.getComments()
return view
}
// The system calls this only when creating the layout in a dialog.
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
return dialog
}
private fun getComments() {
AsyncTask.execute {
val data =
this.client.getCommentariesThread(this.comment.videoId, this.comment.id)
activity?.runOnUiThread {
this.setDataComments(data)
}
}
}
private fun setDataComments(data: ArrayList<CommentaryModel>) {
// Set data for RecyclerView
val viewAdapter = CommentariesAdapter(data).setFragmentManager(this.fragmentManager2)
view?.findViewById<RecyclerView>(R.id.listCommentaries)?.let {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
it.setHasFixedSize(true)
// use a linear layout manager
it.layoutManager = LinearLayoutManager(activity)
// specify an viewAdapter (see also next example)
it.adapter = viewAdapter
}
}
private fun replyThread() {
val commentary = binding.commentBox?.commentaryText?.text.toString()
if (commentary == "") {
ManagerSingleton.toast(getString(R.string.emptyCommentaryMsg), requireActivity())
return
}
AsyncTask.execute {
val res = this.client.replyThread(ManagerSingleton.token.token, this.comment.videoId, this.comment.id, commentary)
activity?.runOnUiThread {
if (res) {
ManagerSingleton.toast(getString(R.string.makedCommentaryMsg), requireActivity())
binding.commentBox?.commentaryText?.text?.clear()
this.getComments()
} else {
ManagerSingleton.toast(getString(R.string.errorCommentaryMsg), requireActivity())
}
}
}
}
}

View File

@ -0,0 +1,38 @@
package org.libre.agosto.p2play.fragmentAdapters
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter
import org.libre.agosto.p2play.fragments.AccountVideosFragment
import org.libre.agosto.p2play.fragments.AccountChannelsFragment
import org.libre.agosto.p2play.fragments.AccountInfoFragment
import org.libre.agosto.p2play.models.AccountModel
val TAB_NAMES = arrayOf(
"Videos",
"Channels",
"Info"
)
class AccountAdapter(fm: FragmentManager, c: Lifecycle) : FragmentStateAdapter(fm, c) {
lateinit var accountId: String
lateinit var account: AccountModel
override fun getItemCount(): Int = 3
override fun createFragment(i: Int): Fragment {
val fragment = when (i) {
0 -> AccountVideosFragment.newInstance(accountId)
1 -> AccountChannelsFragment.newInstance(accountId)
2 -> AccountInfoFragment.newInstance(account)
else -> throw Error("Invalid tab")
}
return fragment
}
fun get(position: Int): CharSequence {
return TAB_NAMES[position]
}
}

View File

@ -0,0 +1,82 @@
package org.libre.agosto.p2play.fragments
import android.os.AsyncTask
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.libre.agosto.p2play.adapters.ChannelAdapter
import org.libre.agosto.p2play.ajax.Accounts
import org.libre.agosto.p2play.databinding.FragmentChannelsBinding
import org.libre.agosto.p2play.helpers.getViewManager
import org.libre.agosto.p2play.models.ChannelModel
private const val ARG_PARAM1 = "accountId"
class AccountChannelsFragment : Fragment() {
private var _binding: FragmentChannelsBinding? = null
private val binding get() = _binding!!
private var accountId: String? = null
private val client = Accounts()
private lateinit var viewManager: RecyclerView.LayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
accountId = it.getString(ARG_PARAM1)
}
viewManager = getViewManager(this.requireContext(), resources)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentChannelsBinding.inflate(inflater, container, false)
return binding.root
}
override fun onResume() {
super.onResume()
getChannels()
}
private fun getChannels() {
AsyncTask.execute {
val channels = client.getChannels(this.accountId!!)
requireActivity().runOnUiThread {
initRecycler(channels)
}
}
}
private fun initRecycler(data: ArrayList<ChannelModel>) {
val viewAdapter = ChannelAdapter(data)
binding.channelList.apply {
viewAdapter.parent = requireActivity()
setHasFixedSize(true)
// use a linear layout manager
layoutManager = viewManager
// specify an viewAdapter (see also next example)
adapter = viewAdapter
}
}
companion object {
@JvmStatic
fun newInstance(accountId: String) =
AccountChannelsFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, accountId)
}
}
}
}

View File

@ -0,0 +1,50 @@
package org.libre.agosto.p2play.fragments
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import org.libre.agosto.p2play.databinding.FragmentChannelInfoBinding
import org.libre.agosto.p2play.models.AccountModel
import java.io.Serializable
private const val ARG_PARAM1 = "account"
class AccountInfoFragment : Fragment() {
private var _binding: FragmentChannelInfoBinding? = null
private val binding get() = _binding!!
private var account: AccountModel? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
account = it.getSerializable(ARG_PARAM1) as AccountModel
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentChannelInfoBinding.inflate(inflater, container, false)
binding.account.text = account?.name
binding.host.text = account?.host
binding.description.text = account?.description
return binding.root
}
companion object {
@JvmStatic
fun newInstance(account: AccountModel) =
AccountInfoFragment().apply {
arguments = Bundle().apply {
val param = account as Serializable
putSerializable(ARG_PARAM1, param)
}
}
}
}

View File

@ -0,0 +1,86 @@
package org.libre.agosto.p2play.fragments
import android.os.AsyncTask
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.libre.agosto.p2play.adapters.VideosAdapter
import org.libre.agosto.p2play.ajax.Videos
import org.libre.agosto.p2play.databinding.FragmentChannelVideosBinding
import org.libre.agosto.p2play.helpers.getViewManager
import org.libre.agosto.p2play.models.VideoModel
private const val ARG_PARAM1 = "accountId"
class AccountVideosFragment : Fragment() {
private var _binding: FragmentChannelVideosBinding? = null
private val binding get() = _binding!!
private var accountId: String? = "agosto182"
private val videosService = Videos()
private lateinit var viewManager: RecyclerView.LayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
accountId = it.getString(ARG_PARAM1, accountId)
}
viewManager = getViewManager(this.requireContext(), resources)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentChannelVideosBinding.inflate(inflater, container, false)
return binding.root
}
override fun onResume() {
super.onResume()
getVideos()
}
private fun getVideos() {
AsyncTask.execute {
val videos = videosService.accountVideos(this.accountId!!, 0)
activity?.runOnUiThread {
initRecycler(videos)
}
}
}
private fun initRecycler(data: ArrayList<VideoModel>) {
// val data = arrayListOf<VideoModel>()
val viewAdapter = VideosAdapter(data)
binding.videosList.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
}
}
companion object {
@JvmStatic
fun newInstance(param1: String) =
AccountVideosFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
}
}
}
}

View File

@ -0,0 +1,24 @@
package org.libre.agosto.p2play.helpers
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView.LayoutManager
fun getViewManager (context: Context, resources: Resources): LayoutManager {
val screenSize = resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK
val manager = if (screenSize > Configuration.SCREENLAYOUT_SIZE_LARGE) {
val orientation = resources.configuration.orientation
val gridItems = when (orientation) {
Configuration.ORIENTATION_LANDSCAPE -> 4
else -> 3
}
GridLayoutManager(context, gridItems)
} else {
LinearLayoutManager(context)
}
return manager
}

View File

@ -0,0 +1,20 @@
package org.libre.agosto.p2play.helpers
fun mapSeconds(inputSeconds: Int): String {
val seconds = (inputSeconds % 60)
var minutes = inputSeconds / 60
var hours = 0
if (minutes > 60) {
hours = minutes / 60
minutes %= 60
}
var result = minutes.toString().padStart(2, '0') + ":" + seconds.toString().padStart(2, '0')
if (hours > 0) {
result = hours.toString().padStart(2, '0') + ":" + result
}
return result
}

View File

@ -0,0 +1,13 @@
package org.libre.agosto.p2play.helpers
import android.view.View
import android.view.Window
import android.view.WindowManager
fun setFullscreen(window: Window) {
val attrs = 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
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
}

View File

@ -0,0 +1,16 @@
package org.libre.agosto.p2play.models
import java.io.Serializable
data class AccountAvatar (
val path: String
)
class AccountModel (
val name: String,
val url: String,
val host: String,
val avatars: ArrayList<AccountAvatar>,
val displayName: String,
val description: String
): Serializable

View File

@ -12,7 +12,7 @@ class ChannelModel (
var name: String = "",
var description: String = "",
var support: String = "",
var channelImg: String = ""
var channelImg: String = "",
) {
fun getAccount(): String {
return "$nameChannel@$host"
@ -22,7 +22,6 @@ class ChannelModel (
data.beginObject()
while (data.hasNext()) {
when (data.nextName()) {
"id" -> this.id = data.nextInt()
"url" -> this.url = data.nextString()
@ -31,17 +30,19 @@ class ChannelModel (
"followersCount" -> this.followers = data.nextInt()
"displayName" -> this.name = data.nextString()
"description" -> {
if(data.peek() == JsonToken.STRING)
if (data.peek() == JsonToken.STRING) {
this.description = data.nextString()
else
} else {
data.skipValue()
}
}
"support" -> {
if(data.peek() == JsonToken.STRING)
if (data.peek() == JsonToken.STRING) {
this.support = data.nextString()
else
} else {
data.skipValue()
}
}
"avatar" -> {
if (data.peek() == JsonToken.BEGIN_OBJECT) {
data.beginObject()
@ -52,10 +53,10 @@ class ChannelModel (
}
}
data.endObject()
}
else
} else {
data.skipValue()
}
}
else -> data.skipValue()
}
}

View File

@ -2,6 +2,7 @@ package org.libre.agosto.p2play.models
import android.util.JsonReader
import android.util.JsonToken
import java.io.Serializable
class CommentaryModel(
var id: Int = 0,
@ -11,8 +12,10 @@ class CommentaryModel (
var userImageUrl: String = "",
var commentary: String = "",
var userHost: String = "",
var replies: Int = 0
) {
var replies: Int = 0,
var nameChannel: String = "",
var videoId: Int = 0,
) : Serializable {
fun parseCommentary(data: JsonReader) {
data.beginObject()
while (data.hasNext()) {
@ -22,6 +25,7 @@ class CommentaryModel (
"threadId" -> this.threadId = data.nextInt()
"text" -> this.commentary = data.nextString()
"totalReplies" -> this.replies = data.nextInt()
"videoId" -> this.videoId = data.nextInt()
"account" -> {
data.beginObject()
while (data.hasNext()) {
@ -39,13 +43,13 @@ class CommentaryModel (
}
}
data.endObject()
}
else
} else {
data.skipValue()
}
}
"uuid" -> this.userUuid = data.nextString()
"host" -> this.userHost = data.nextString()
"name" -> this.nameChannel = data.nextString()
else -> data.skipValue()
}
}
@ -56,4 +60,8 @@ class CommentaryModel (
}
data.endObject()
}
fun getAccount(): String {
return "$nameChannel@$userHost"
}
}

View File

@ -0,0 +1,62 @@
package org.libre.agosto.p2play.models
import android.util.JsonReader
class DownloadFiles(
var resolution: String = "",
var url: String = ""
)
class StreamingModel(
var playlistUrl: String = "",
var segmentsSha256Url: String = "",
var downloadFiles: ArrayList<DownloadFiles> = arrayListOf<DownloadFiles>()
) {
fun parse(data: JsonReader) {
data.beginObject()
while (data.hasNext()) {
val key = data.nextName()
when (key.toString()) {
"playlistUrl" -> {
this.playlistUrl = data.nextString()
}
"segmentsSha256Url" -> {
this.segmentsSha256Url = data.nextString()
}
"files" -> {
data.beginArray()
if (data.hasNext()) {
data.beginObject()
val downloadFile = DownloadFiles()
while (data.hasNext()) {
val key2 = data.nextName()
when (key2.toString()) {
"fileDownloadUrl" -> downloadFile.url = data.nextString()
"resolution" -> {
data.beginObject()
while(data.hasNext()) {
val keyRes = data.nextName()
when (keyRes!!) {
"label" -> downloadFile.resolution = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
}
else -> data.skipValue()
}
}
this.downloadFiles.add(downloadFile)
data.endObject()
}
while (data.hasNext()) {
data.skipValue()
}
data.endArray()
}
else -> data.skipValue()
}
}
data.endObject()
}
}

View File

@ -3,5 +3,5 @@ package org.libre.agosto.p2play.models
class TokenModel(
var token: String = "",
var refresh_token: String = "",
var status: Int = -1
var status: Int = -1,
)

View File

@ -8,5 +8,5 @@ class UserModel (
var nsfw: Boolean = true,
var followers: Int = 0,
var avatar: String = "",
var status: Int = -1
var status: Int = -1,
)

View File

@ -17,9 +17,11 @@ class VideoModel(
var views: Number = 0,
var userUuid: String = "",
var userHost: String = "",
var nameChannel: String = ""
var nameChannel: String = "",
var isLive: Boolean = false,
var streamingData: StreamingModel? = null,
) : Serializable {
fun getAccount(): String {
fun getChannel(): String {
return "$nameChannel@$userHost"
}
@ -38,11 +40,12 @@ class VideoModel(
this.name = data.nextString()
}
"description" -> {
if(data.peek() == JsonToken.STRING)
if (data.peek() == JsonToken.STRING) {
this.description = data.nextString()
else
} else {
data.skipValue()
}
}
"duration" -> {
this.duration = data.nextInt()
}
@ -55,6 +58,55 @@ class VideoModel(
"views" -> {
this.views = data.nextInt()
}
"isLive" -> {
this.isLive = data.nextBoolean()
}
"streamingPlaylists" -> {
data.beginArray()
if (data.hasNext()) {
val streamingData = StreamingModel()
streamingData.parse(data)
this.streamingData = streamingData
}
data.endArray()
}
"files" -> {
data.beginArray()
if (streamingData === null) {
if (data.hasNext()) {
data.beginObject()
while (data.hasNext()) {
val key2 = data.nextName()
streamingData = StreamingModel()
val downloadFile = DownloadFiles()
when (key2.toString()) {
"fileUrl" -> {
streamingData!!.playlistUrl = data.nextString()
}
"fileDownloadUrl" -> downloadFile.url = data.nextString()
"resolution" -> {
data.beginObject()
while(data.hasNext()) {
val keyRes = data.nextName()
when (keyRes!!) {
"label" -> downloadFile.resolution = data.nextString()
else -> data.skipValue()
}
}
data.endObject()
}
else -> data.skipValue()
}
streamingData!!.downloadFiles.add(downloadFile)
}
data.endObject()
}
while (data.hasNext()) {
data.skipValue()
}
}
data.endArray()
}
"channel" -> {
data.beginObject()
while (data.hasNext()) {
@ -72,10 +124,9 @@ class VideoModel(
}
}
data.endObject()
}
else
} else {
data.skipValue()
}
}
"uuid" -> this.userUuid = data.nextString()
"host" -> this.userHost = data.nextString()

View File

@ -0,0 +1,47 @@
package org.libre.agosto.p2play.services
import android.app.PendingIntent
import android.content.Intent
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService
import org.libre.agosto.p2play.ReproductorActivity
import org.libre.agosto.p2play.singletons.PlaybackSingleton
class PlaybackService : MediaSessionService() {
private var mediaSession: MediaSession? = null
// Create your Player and MediaSession in the onCreate lifecycle event
override fun onCreate() {
super.onCreate()
val player = PlaybackSingleton.player!!
mediaSession = MediaSession.Builder(this, player)
.build()
val contentIntent = Intent(this, ReproductorActivity::class.java)
contentIntent.putExtra("resume", true)
val pendingIntent = PendingIntent.getActivity(
this,
0,
contentIntent,
PendingIntent.FLAG_MUTABLE,
)
mediaSession!!.setSessionActivity(pendingIntent)
}
// Remember to release the player and media session in onDestroy
override fun onDestroy() {
mediaSession?.run {
release()
mediaSession = null
}
super.onDestroy()
}
override fun onTaskRemoved(rootIntent: Intent?) {
this.mediaSession!!.player.stop()
super.onTaskRemoved(rootIntent)
}
override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
return mediaSession
}
}

View File

@ -0,0 +1,51 @@
package org.libre.agosto.p2play.singletons
import android.content.ComponentName
import android.content.Context
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.MediaController
import androidx.media3.session.SessionToken
import com.google.common.util.concurrent.MoreExecutors
import org.libre.agosto.p2play.models.VideoModel
import org.libre.agosto.p2play.services.PlaybackService
object PlaybackSingleton {
var player: ExoPlayer? = null
var video: VideoModel? = null
private var withMediaSession = false
fun setData(mediaItem: MediaItem, video: VideoModel): ExoPlayer? {
player?.let {
if (it.isPlaying) {
it.pause()
}
it.setMediaItem(mediaItem)
it.prepare()
this.video = video
return it
}
return null
}
fun release() {
player?.release()
}
fun runMediaSession(context: Context) {
if (!this.withMediaSession) {
val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))
val controllerFuture = MediaController.Builder(context, sessionToken).buildAsync()
controllerFuture.addListener(
{
val med = controllerFuture.get()
},
MoreExecutors.directExecutor(),
)
this.withMediaSession = true
}
}
}

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@ -8,18 +8,18 @@
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeColor="#585858"
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"/>
android:fillColor="#585858"
android:strokeColor="#585858"
android:fillType="evenOdd" />
<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"/>
android:fillColor="#585858"
android:strokeColor="#585858"
android:fillType="evenOdd" />
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#88ffffff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M18,13c0,3.31 -2.69,6 -6,6s-6,-2.69 -6,-6s2.69,-6 6,-6v4l5,-5l-5,-5v4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8H18z"/>
<path android:fillColor="@android:color/white" android:pathData="M10.86,15.94l0,-4.27l-0.09,0l-1.77,0.63l0,0.69l1.01,-0.31l0,3.26z"/>
<path android:fillColor="@android:color/white" android:pathData="M12.25,13.44v0.74c0,1.9 1.31,1.82 1.44,1.82c0.14,0 1.44,0.09 1.44,-1.82v-0.74c0,-1.9 -1.31,-1.82 -1.44,-1.82C13.55,11.62 12.25,11.53 12.25,13.44zM14.29,13.32v0.97c0,0.77 -0.21,1.03 -0.59,1.03c-0.38,0 -0.6,-0.26 -0.6,-1.03v-0.97c0,-0.75 0.22,-1.01 0.59,-1.01C14.07,12.3 14.29,12.57 14.29,13.32z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="48dp">
<path android:fillColor="@android:color/white" android:pathData="M7,14L5,14v5h5v-2L7,17v-3zM5,10h2L7,7h3L10,5L5,5v5zM17,17h-3v2h5v-5h-2v3zM14,5v2h3v3h2L19,5h-5z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M260,800Q169,800 104.5,737Q40,674 40,583Q40,505 87,444Q134,383 210,366Q227,294 295,229Q363,164 440,164Q473,164 496.5,187.5Q520,211 520,244L520,486L584,424L640,480L480,640L320,480L376,424L440,486L440,244Q364,258 322,317.5Q280,377 280,440L260,440Q202,440 161,481Q120,522 120,580Q120,638 161,679Q202,720 260,720L740,720Q782,720 811,691Q840,662 840,620Q840,578 811,549Q782,520 740,520L680,520L680,440Q680,392 658,350.5Q636,309 600,280L600,187Q674,222 717,290.5Q760,359 760,440L760,440L760,440Q829,448 874.5,499.5Q920,551 920,620Q920,695 867.5,747.5Q815,800 740,800L260,800ZM480,442Q480,442 480,442Q480,442 480,442L480,442Q480,442 480,442Q480,442 480,442L480,442Q480,442 480,442Q480,442 480,442L480,442Q480,442 480,442Q480,442 480,442Q480,442 480,442Q480,442 480,442L480,442Q480,442 480,442Q480,442 480,442Q480,442 480,442Q480,442 480,442L480,442L480,442Q480,442 480,442Q480,442 480,442Z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M8,5v14l11,-7z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#fff" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M11.99,5V1l-5,5l5,5V7c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6h-2c0,4.42 3.58,8 8,8s8,-3.58 8,-8S16.41,5 11.99,5z"/>
<path android:fillColor="@android:color/white" android:pathData="M10.89,16h-0.85v-3.26l-1.01,0.31v-0.69l1.77,-0.63h0.09V16z"/>
<path android:fillColor="@android:color/white" android:pathData="M15.17,14.24c0,0.32 -0.03,0.6 -0.1,0.82s-0.17,0.42 -0.29,0.57s-0.28,0.26 -0.45,0.33s-0.37,0.1 -0.59,0.1s-0.41,-0.03 -0.59,-0.1s-0.33,-0.18 -0.46,-0.33s-0.23,-0.34 -0.3,-0.57s-0.11,-0.5 -0.11,-0.82V13.5c0,-0.32 0.03,-0.6 0.1,-0.82s0.17,-0.42 0.29,-0.57s0.28,-0.26 0.45,-0.33s0.37,-0.1 0.59,-0.1s0.41,0.03 0.59,0.1c0.18,0.07 0.33,0.18 0.46,0.33s0.23,0.34 0.3,0.57s0.11,0.5 0.11,0.82V14.24zM14.32,13.38c0,-0.19 -0.01,-0.35 -0.04,-0.48s-0.07,-0.23 -0.12,-0.31s-0.11,-0.14 -0.19,-0.17s-0.16,-0.05 -0.25,-0.05s-0.18,0.02 -0.25,0.05s-0.14,0.09 -0.19,0.17s-0.09,0.18 -0.12,0.31s-0.04,0.29 -0.04,0.48v0.97c0,0.19 0.01,0.35 0.04,0.48s0.07,0.24 0.12,0.32s0.11,0.14 0.19,0.17s0.16,0.05 0.25,0.05s0.18,-0.02 0.25,-0.05s0.14,-0.09 0.19,-0.17s0.09,-0.19 0.11,-0.32s0.04,-0.29 0.04,-0.48V13.38z"/>
</vector>

View File

@ -7,7 +7,7 @@
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:strokeColor="#585858"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
@ -15,7 +15,7 @@
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeColor="#585858"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
<path
@ -23,7 +23,7 @@
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeColor="#585858"
android:fillType="evenOdd"
android:strokeLineCap="round"/>
</vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp" />
<!-- This is the border color -->
<!--- This is the background color -->
<solid android:color="@color/colorDislike" />
</shape>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="5dp" />
<!-- This is the border color -->
<!--- This is the background color -->
<solid android:color="?attr/colorSecondary" />
</shape>

View File

@ -0,0 +1,360 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="match_parent"
tools:context=".ReproductorActivity">
<RelativeLayout
android:id="@+id/fullScreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RelativeLayout
android:id="@+id/fullScreenExo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" >
<androidx.media3.ui.PlayerView
android:id="@+id/fullscreenPlayer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
app:use_controller="true"
app:show_buffering="always"
app:controller_layout_id="@layout/custom_player_controls"
app:player_layout_id="@layout/exo_player_view"/>
</RelativeLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/nonFullScreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
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="match_parent"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<WebView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="205dp"
android:layout_weight="1"
android:visibility="gone" />
<androidx.media3.ui.PlayerView
android:id="@+id/exoPlayer"
android:layout_width="match_parent"
android:layout_height="500dp"
app:show_buffering="always"
app:use_controller="true"
app:controller_layout_id="@layout/custom_player_controls"/>
<TextView
android:id="@+id/tittleVideoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:textAppearance="@android:style/TextAppearance.Material.Display1"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/viewsTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textSize="12sp" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/actionsLayout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="top"
android:orientation="horizontal"
android:visibility="gone">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/likeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/likeBtn"
android:cropToPadding="false"
android:scaleType="center"
android:visibility="visible"
app:srcCompat="@drawable/ic_like" />
<TextView
android:id="@+id/textViewLike"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/likeBtn"
android:textAlignment="center" />
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:id="@+id/dislikeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/imageView2"
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_dislike" />
<TextView
android:id="@+id/textViewDislike"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/dislikeBtn"
android:textAlignment="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/reportLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
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_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
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/shareBtn"
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>
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImg"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:cropToPadding="false"
android:padding="5dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:orientation="vertical">
<TextView
android:id="@+id/userTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxWidth="300dp"
android:textAppearance="@android:style/TextAppearance.Material.Large"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/hostTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="10sp"
android:textStyle="italic" />
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/subscribeBtn"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/subscribeBtn"
android:textSize="12sp"
android:visibility="invisible" />
</LinearLayout>
<TextView
android:id="@+id/descriptionTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLength="1000"
android:maxLines="100"
android:paddingLeft="5dp"
android:text="@string/descriptionTxt"
android:textStyle="bold" />
<TextView
android:id="@+id/descriptionVideoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:autoLink="web"
android:linksClickable="true"
android:maxLength="10000"
android:maxLines="100"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/showMoreBtn"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/showMore"
android:visibility="gone" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="20dp" />
</LinearLayout>
<androidx.constraintlayout.widget.Barrier
android:layout_width="match_parent"
android:layout_height="match_parent"
app:barrierDirection="left" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<include
android:id="@+id/commentBox"
layout="@layout/comment_component" />
<TextView
android:id="@+id/commentariesTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:text="@string/commentariesTxt"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listCommentaries"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 The Android Open Source Project
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
http://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.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 0dp dimensions are used to prevent this view from influencing the size of
the parent view if it uses "wrap_content". It is expanded to occupy the
entirety of the parent in code, after the parent's size has been
determined. See: https://github.com/google/ExoPlayer/issues/8726.
-->
<View android:id="@id/exo_controls_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/exo_black_opacity_60"/>
<FrameLayout
android:id="@id/exo_bottom_bar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:layout_marginTop="@dimen/exo_styled_bottom_bar_margin_top"
android:background="@color/exo_bottom_bar_background"
android:layoutDirection="ltr">
<LinearLayout
android:id="@id/exo_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layoutDirection="ltr"
android:paddingStart="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingLeft="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingEnd="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingRight="@dimen/exo_styled_bottom_bar_time_padding">
<TextView
android:id="@id/exo_position"
style="@style/ExoStyledControls.TimeText.Position" />
<TextView
style="@style/ExoStyledControls.TimeText.Separator"
android:text="/" />
<TextView
android:id="@id/exo_duration"
style="@style/ExoStyledControls.TimeText.Duration" />
</LinearLayout>
<LinearLayout
android:id="@id/exo_basic_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:layoutDirection="ltr">
<ImageButton
android:id="@id/exo_subtitle"
style="@style/ExoStyledControls.Button.Bottom.CC" />
<ImageButton
android:id="@id/exo_settings"
style="@style/ExoStyledControls.Button.Bottom.Settings" />
<ImageButton
android:id="@+id/exo_fullscreen_custom"
style="@style/ExoStyledControls.Button.Bottom.Settings"
android:src="@drawable/ic_fullscreen_24"
android:visibility="visible" />
</LinearLayout>
</FrameLayout>
<View android:id="@id/exo_progress_placeholder"
android:layout_width="match_parent"
android:layout_height="@dimen/exo_styled_progress_layout_height"
android:layout_gravity="bottom"
android:layout_marginBottom="@dimen/exo_styled_progress_margin_bottom"/>
<LinearLayout
android:id="@id/exo_center_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@android:color/transparent"
android:gravity="center"
android:padding="@dimen/exo_styled_controls_padding"
android:clipToPadding="false"
android:layoutDirection="ltr">
<include layout="@layout/exo_player_control_rewind_button" />
<ImageButton android:id="@id/exo_play_pause"
style="@style/ExoStyledControls.Button.Center.PlayPause"/>
<include layout="@layout/exo_player_control_ffwd_button" />
</LinearLayout>
</merge>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44000000">
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="800dp"
android:layout_height="0dp"
android:background="?attr/colorSurface"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/materialToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
<include
android:id="@+id/commentThread"
layout="@layout/view_commentary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listCommentaries"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp" />
</LinearLayout>
<include
android:id="@+id/commentBox"
layout="@layout/comment_component"
android:layout_width="700dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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"
@ -29,7 +29,7 @@
android:contentDescription="Logo"
app:srcCompat="@mipmap/ic_launcher" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -39,11 +39,10 @@
android:layout_height="wrap_content"
android:text="@string/aboutLabel"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black"
android:textAppearance="@android:style/TextAppearance.Material.Medium"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -55,7 +54,7 @@
android:textAlignment="textStart"
android:textSize="16sp" />
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/gitlabUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -66,7 +65,7 @@
android:textSize="16sp"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="20dp" />
@ -88,7 +87,7 @@
android:textSize="16sp"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -98,11 +97,10 @@
android:layout_height="wrap_content"
android:text="@string/aboutInstance"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black"
android:textAppearance="@android:style/TextAppearance.Material.Medium"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="20dp" />
@ -124,7 +122,7 @@
android:textSize="16sp"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -135,7 +133,11 @@
android:text="@string/aboutLicense"
android:textAlignment="textStart"
android:textSize="16sp" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:layout_collapseMode="pin" />
<ImageView
android:id="@+id/backgroundImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
app:layout_collapseMode="pin"
android:orientation="vertical">
<ImageView
android:id="@+id/profileImage"
android:layout_width="80dp"
android:layout_height="80dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/default_avatar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -56,8 +56,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false">
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
@ -141,14 +141,13 @@
tools:layout_editor_absoluteY="214dp" />
</FrameLayout>
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listVideosChannel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
</androidx.core.widget.NestedScrollView>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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"
@ -29,24 +29,30 @@
android:contentDescription="Logo"
app:srcCompat="@drawable/icon" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<TextView
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/hostInfoText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hostInfoText"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black" />
/>
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<EditText
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="@string/instance"
app:expandedHintEnabled="false">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/hostText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -54,13 +60,15 @@
android:hint="@string/hostText"
android:inputType="text" />
<Button
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/button"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/okButton" />
</LinearLayout>
</FrameLayout>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,26 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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="match_parent"
tools:context=".LoginActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
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="match_parent"
android:orientation="vertical">
android:gravity="center"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_max="500dp">
<ImageView
android:id="@+id/imageView2"
@ -29,7 +22,7 @@
android:contentDescription="Logo"
app:srcCompat="@drawable/icon" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -39,62 +32,66 @@
android:layout_height="wrap_content"
android:text="@string/loginInfo"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black" />
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<TextView
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/userTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/userTxt" />
android:layout_margin="4dp"
android:hint="@string/userTxt"
android:maxWidth="600dp">
<EditText
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/userText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/userText"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/passwordTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/passwordTxt" />
android:layout_margin="4dp"
android:hint="@string/passwordTxt"
android:maxWidth="600dp"
android:maxEms="10"
app:endIconMode="password_toggle">
<EditText
android:id="@+id/passwordText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/passwordText"
android:inputType="text|textPassword" />
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/loginBtn"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/loginBtn"
android:textAlignment="center" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/registerActionBtn"
style="@style/Widget.AppCompat.Button.Borderless"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/registerActionBtn"
android:visibility="visible" />
android:visibility="invisible" />
</LinearLayout>
</FrameLayout>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
@ -8,12 +8,29 @@
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.NavigationView
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
</com.google.android.material.appbar.AppBarLayout>
<include
android:id="@+id/content"
layout="@layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
@ -26,4 +43,4 @@
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
</androidx.drawerlayout.widget.DrawerLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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"
@ -29,7 +29,7 @@
android:contentDescription="Logo"
app:srcCompat="@drawable/icon" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -42,7 +42,7 @@
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -99,4 +99,4 @@
</LinearLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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"
@ -10,16 +10,45 @@
android:id="@+id/fullScreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:visibility="gone" />
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
<RelativeLayout
android:id="@+id/fullScreenExo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" >
<androidx.media3.ui.PlayerView
android:id="@+id/fullscreenPlayer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
app:use_controller="true"
app:show_buffering="always"
app:controller_layout_id="@layout/custom_player_controls"
app:player_layout_id="@layout/exo_player_view"/>
</RelativeLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/nonFullScreen"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -37,17 +66,24 @@
<WebView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="270dp"
android:layout_weight="1">
android:layout_height="205dp"
android:layout_weight="1"
android:visibility="gone" />
</WebView>
<androidx.media3.ui.PlayerView
android:id="@+id/exoPlayer"
android:layout_width="match_parent"
android:layout_height="205dp"
app:show_buffering="always"
app:use_controller="true"
app:controller_layout_id="@layout/custom_player_controls" />
<TextView
android:id="@+id/tittleVideoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:textAppearance="@android:style/TextAppearance.Material.Large"
android:textAppearance="@android:style/TextAppearance.Material.Display1"
android:textSize="18sp"
android:textStyle="bold" />
@ -59,7 +95,7 @@
android:paddingRight="5dp"
android:textSize="12sp" />
<LinearLayout
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/actionsLayout"
android:layout_width="match_parent"
android:layout_height="50dp"
@ -67,7 +103,7 @@
android:orientation="horizontal"
android:visibility="gone">
<LinearLayout
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/likeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -94,7 +130,7 @@
android:layout_weight="1"
android:text="@string/likeBtn"
android:textAlignment="center" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:id="@+id/dislikeLayout"
@ -124,6 +160,35 @@
android:textAlignment="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/downloadLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/downloadImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/reportBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_outline_cloud_download_24"
app:tint="#585858" />
<TextView
android:id="@+id/downloadText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/downloadText"
android:textAlignment="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/reportLayout"
android:layout_width="match_parent"
@ -138,7 +203,7 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/dislikeBtn"
android:contentDescription="@string/reportBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_alert" />
@ -152,6 +217,7 @@
android:textAlignment="center" />
</LinearLayout>
<LinearLayout
android:id="@+id/shareLayout"
android:layout_width="match_parent"
@ -166,7 +232,7 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/dislikeBtn"
android:contentDescription="@string/shareBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_share" />
@ -179,38 +245,39 @@
android:text="@string/shareBtn"
android:textAlignment="center" />
</LinearLayout>
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_weight="1"
android:gravity="center|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImg"
android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_width="35dp"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_weight="1"
android:adjustViewBounds="false"
android:adjustViewBounds="true"
android:cropToPadding="false"
android:padding="5dp"
android:scaleType="centerInside"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="2"
android:layout_height="wrap_content"
android:layout_weight="3"
android:orientation="vertical">
<TextView
android:id="@+id/userTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxWidth="300dp"
android:textAppearance="@android:style/TextAppearance.Material.Large"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
@ -223,14 +290,14 @@
</LinearLayout>
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/subscribeBtn"
style="@style/Widget.AppCompat.Button.Colored"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/subscribeBtn"
android:textSize="10sp"
android:textSize="12sp"
android:visibility="invisible" />
</LinearLayout>
@ -257,9 +324,9 @@
android:paddingLeft="10dp"
android:paddingRight="10dp" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/showMoreBtn"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
@ -272,7 +339,7 @@
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_weight="1" />
@ -285,51 +352,15 @@
android:text="@string/commentariesTxt"
android:textStyle="bold" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="20dp" />
<LinearLayout
android:id="@+id/commentaryLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<include
android:id="@+id/commentBox"
layout="@layout/comment_component" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImgCom"
android:layout_width="10dp"
android:layout_height="60dp"
android:layout_weight="1"
app:srcCompat="@drawable/default_avatar" />
<EditText
android:id="@+id/commentaryText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:ems="10"
android:hint="@string/commentHolder"
android:inputType="textMultiLine" />
</LinearLayout>
<Button
android:id="@+id/commentaryBtn"
style="@style/Widget.AppCompat.Button.Colored"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/commentaryText" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listCommentaries"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -339,5 +370,6 @@
</LinearLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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"
@ -29,7 +29,7 @@
android:contentDescription="@string/app_name"
app:srcCompat="@mipmap/ic_launcher" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -39,10 +39,9 @@
android:layout_height="wrap_content"
android:text="@string/charging"
android:textAlignment="center"
android:textAppearance="@android:style/TextAppearance.Material.Medium.Inverse"
android:textColor="@android:color/black" />
android:textAppearance="@android:style/TextAppearance.Material.Medium" />
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="30dp" />
@ -55,4 +54,4 @@
</LinearLayout>
</FrameLayout>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,25 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/P2playTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/P2playTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/commentaryLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImgCom"
android:layout_width="5dp"
android:layout_height="57dp"
android:layout_weight="1"
app:srcCompat="@drawable/default_avatar" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_weight="3"
android:hint="@string/commentHolder">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/commentaryText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:ems="10"
android:inputType="textMultiLine" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/commentaryBtn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/commentaryText" />
</androidx.appcompat.widget.LinearLayoutCompat>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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"
@ -8,7 +8,7 @@
tools:context=".MainActivity"
tools:showIn="@layout/app_bar_main">
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -16,7 +16,7 @@
android:visibility="visible"
app:layout_constraintTop_toTopOf="parent">
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -24,5 +24,17 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.constraint.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<include
android:id="@+id/mini"
layout="@layout/mini_player"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2020 The Android Open Source Project
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
http://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.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 0dp dimensions are used to prevent this view from influencing the size of
the parent view if it uses "wrap_content". It is expanded to occupy the
entirety of the parent in code, after the parent's size has been
determined. See: https://github.com/google/ExoPlayer/issues/8726.
-->
<View android:id="@id/exo_controls_background"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/exo_black_opacity_60"/>
<FrameLayout
android:id="@id/exo_bottom_bar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:layout_marginTop="@dimen/exo_styled_bottom_bar_margin_top"
android:background="@color/exo_bottom_bar_background"
android:layoutDirection="ltr">
<LinearLayout
android:id="@id/exo_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layoutDirection="ltr"
android:paddingStart="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingLeft="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingEnd="@dimen/exo_styled_bottom_bar_time_padding"
android:paddingRight="@dimen/exo_styled_bottom_bar_time_padding">
<TextView
android:id="@id/exo_position"
style="@style/ExoStyledControls.TimeText.Position" />
<TextView
style="@style/ExoStyledControls.TimeText.Separator"
android:text="/" />
<TextView
android:id="@id/exo_duration"
style="@style/ExoStyledControls.TimeText.Duration" />
</LinearLayout>
<LinearLayout
android:id="@id/exo_basic_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:layoutDirection="ltr">
<ImageButton
android:id="@id/exo_subtitle"
style="@style/ExoStyledControls.Button.Bottom.CC" />
<ImageButton
android:id="@id/exo_settings"
style="@style/ExoStyledControls.Button.Bottom.Settings" />
<ImageButton
android:id="@+id/exo_fullscreen_custom"
style="@style/ExoStyledControls.Button.Bottom.Settings"
android:src="@drawable/ic_fullscreen_24"
android:visibility="visible" />
</LinearLayout>
</FrameLayout>
<View android:id="@id/exo_progress_placeholder"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="bottom"
android:layout_marginBottom="45dp"/>
<LinearLayout
android:id="@id/exo_center_controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@android:color/transparent"
android:gravity="center"
android:padding="@dimen/exo_styled_controls_padding"
android:clipToPadding="false"
android:layoutDirection="ltr">
<include layout="@layout/exo_player_control_rewind_button" />
<ImageButton android:id="@id/exo_play_pause"
style="@style/ExoStyledControls.Button.Center.PlayPause"/>
<include layout="@layout/exo_player_control_ffwd_button" />
</LinearLayout>
</merge>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?attr/colorSurface"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="130dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/materialToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
<include
android:id="@+id/commentThread"
layout="@layout/view_commentary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listCommentaries"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="10dp"/>
</LinearLayout>
<include
android:id="@+id/commentBox"
layout="@layout/comment_component"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.AccountInfoFragment">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/accountTitle"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/accountName" />
<TextView
android:id="@+id/account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="8dp" />
<TextView
android:id="@+id/hostTitle"
style="@style/TextAppearance.MaterialComponents.Body2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hostIndicator" />
<TextView
android:id="@+id/host"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="8dp" />
<TextView
android:id="@+id/descriptionTitle"
style="@style/TextAppearance.MaterialComponents.Body2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/descriptionTxt" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</FrameLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.AccountVideosFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/videosList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.AccountChannelsFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/channelList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:background="?attr/androidBackgroundSecondary"
android:elevation="5dp"
android:clickable="true"
android:id="@+id/mini_player">
<ImageView
android:id="@+id/mini_player_image"
android:layout_width="wrap_content"
android:layout_height="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/default_avatar"
tools:srcCompat="@drawable/default_avatar" />
<TextView
android:id="@+id/mini_player_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:maxWidth="180dp"
android:text="Video"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
app:layout_constraintStart_toEndOf="@+id/mini_player_image"
app:layout_constraintTop_toTopOf="parent"
android:maxLines="1"
android:ellipsize="end"
android:textColor="?attr/androidOnBackgroundSecondary"/>
<TextView
android:id="@+id/mini_player_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginBottom="8dp"
android:maxWidth="180dp"
android:text="Author"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/mini_player_image"
android:maxLines="1"
android:ellipsize="end" />
<ImageView
android:id="@+id/mini_play_pause"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/likeBtn"
android:cropToPadding="false"
android:scaleType="center"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_pause_24"
app:tint="@color/colorAccent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,26 +1,28 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
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
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/reportText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
</com.google.android.material.textfield.TextInputEditText>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View File

@ -0,0 +1,9 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/settings"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp" >
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/twoFactorText"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<requestFocus />
</com.google.android.material.textfield.TextInputEditText>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">
<ImageView
android:id="@+id/channelImage"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
tools:srcCompat="@drawable/default_avatar" />
<TextView
android:id="@+id/channelName"
android:layout_width="200dp"
android:layout_height="26dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
app:layout_constraintStart_toEndOf="@+id/channelImage"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/channelDescription"
android:layout_width="198dp"
android:layout_height="17dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="TextView"
app:layout_constraintStart_toEndOf="@+id/channelImage"
app:layout_constraintTop_toBottomOf="@+id/channelName" />
<Button
android:id="@+id/subscribeBtn"
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="@string/subscribeBtn"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -7,6 +7,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingRight="10dp"
@ -19,6 +20,7 @@
android:layout_height="60dp"
android:layout_weight="1"
android:contentDescription="@string/app_name"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<LinearLayout
@ -45,6 +47,14 @@
android:linksClickable="true"
android:maxLength="1000"
android:maxLines="10" />
<TextView
android:id="@+id/replyBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/reply"
android:textColor="?attr/colorSecondary"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.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"
@ -14,27 +14,70 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/thumb"
android:layout_width="match_parent"
android:layout_height="230dp"
android:layout_height="205dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@android:drawable/ic_menu_gallery" />
<TextView
android:id="@+id/isLive"
android:layout_width="65dp"
android:layout_height="19dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="16dp"
android:background="@drawable/live_shape"
android:ems="10"
android:paddingHorizontal="3dp"
android:text="@string/is_live_video"
android:textAlignment="center"
android:textColor="@color/durationColor"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="invisible" />
<TextView
android:id="@+id/duration"
android:layout_width="65dp"
android:layout_height="19dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
android:background="@drawable/round_text"
android:ems="10"
android:paddingHorizontal="3dp"
android:text="00:00"
android:textAlignment="center"
android:textColor="?attr/colorOnSecondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="63dp"
android:layout_height="55dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/userImg"
android:layout_width="140dp"
android:layout_width="120dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:adjustViewBounds="true"
android:clickable="false"
android:cropToPadding="false"
android:padding="5dp"
android:scaleType="centerInside"
android:scaleType="fitCenter"
app:srcCompat="@drawable/default_avatar" />
<LinearLayout
@ -50,7 +93,8 @@
android:layout_height="wrap_content"
android:maxLength="70"
android:textSize="14sp"
android:textStyle="bold" />
android:textStyle="bold"
android:theme="@style/MaterialAlertDialog.MaterialComponents.Title.Text" />
<TextView
android:id="@+id/descriptionTxt"
@ -64,10 +108,10 @@
</LinearLayout>
<Space
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="15dp"
android:layout_height="5dp"
android:layout_weight="1"
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
</android.support.constraint.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -5,7 +5,8 @@
<item
android:id="@+id/app_bar_search"
android:icon="@drawable/ic_search_black_24dp"
app:actionViewClass="android.widget.SearchView"
app:actionViewClass="androidx.appcompat.widget.SearchView"
android:title="@string/action_login"
app:showAsAction="always"/>
<item

View File

@ -2,14 +2,14 @@
<resources>
<!-- Start Global strings -->
<string name="comming">Proximamente</string>
<string name="charging">Cargando...</string>
<string name="charging">Cargando</string>
<!-- End Global strings -->
<!-- Start About strings -->
<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="aboutStatus">Puedes seguir nuestro blog:</string>
<string name="aboutLicense">Copyleft GNU GPLv3 License</string>
<string name="aboutLicense">GNU GPLv3 License</string>
<string name="aboutInstance">Sobre la instancia</string>
<string name="aboutInWeb">Para ver los terminos y mas visita la web:</string>
<!-- End About strings -->
@ -25,6 +25,7 @@
<string name="passwordTxt">Contraseña:</string>
<string name="loginBtn">Ingresar</string>
<string name="registerActionBtn">Crear una cuenta</string>
<string name="instance">Instancia</string>
<!-- Toast msg -->
<string name="loginSuccess_msg">Te has identificado</string>
<string name="loginError_msg">Ha ocurrido un error</string>
@ -47,6 +48,7 @@
<string name="timeMin_text">minutos</string>
<string name="timeHrs_text">horas</string>
<string name="nav_header_title">Inicia session</string>
<string name="is_live_video">En vivo</string>
<!-- Toast msg -->
<string name="logout_msg">Te has desconectado</string>
<!-- End Main strings -->

View File

@ -0,0 +1,124 @@
<resources>
<!-- Start Global string -->
<string name="comming">Bientôt disponible !</string>
<string name="charging">Chargement…</string>
<!-- End Global string -->
<!-- Start About strings -->
<string name="aboutLabel">À propos de P2Play</string>
<string name="aboutText">P2Play est une application Android non officielle pour PeerTube. Vous pouvez regarder et contribuer avec le code sur GitLab :</string>
<string name="aboutStatus">Vous pouvez suivre notre blog :</string>
<string name="aboutLicense">Licence GNU GPLv3</string>
<string name="aboutInstance">À propos de l\'instance</string>
<string name="aboutInWeb">Vous pouvez voir les termes et plus sur le web :</string>
<!-- End About strings -->
<!-- Start Host strings -->
<string name="hostInfoText">Sélectionnez votre instance</string>
<string name="okButton">Accepter</string>
<string name="errorMsg">Erreur, réessayez</string>
<string name="finallyMsg">Hôte enregistré</string>
<string name="instance">Instance</string>
<!-- End Host strings -->
<!-- Start Login strings -->
<string name="loginInfo">Connectez-vous ou créez un nouveau compte</string>
<string name="userTxt">Nom d\'utilisateur :</string>
<string name="userText" translatable="false"> </string>
<string name="passwordTxt">Mot de passe :</string>
<string name="passwordText" translatable="false"> </string>
<string name="loginBtn">Connectez-vous maintenant</string>
<string name="registerActionBtn">Créer un nouveau compte</string>
<string name="twoFactorLabel">Code à deux facteurs</string>
<!-- Toast msg -->
<string name="loginSuccess_msg">Vous êtes maintenant connecté</string>
<string name="loginError_msg">Une erreur est survenue</string>
<string name="loginFailed_msg">Identifiants invalides</string>
<string name="registerSuccess_msg">Vous êtes maintenant enregistré</string>
<string name="registerError_msg">Une erreur est survenue</string>
<string name="registerFailed_msg">Données invalides</string>
<!-- Register msg -->
<string name="registerBtn">Inscrivez-vous maintenant</string>
<string name="emailTxt">E-mail :</string>
<string name="emailText" translatable="false">user@mail.com</string>
<!-- End Login strings -->
<!-- Start Main strings -->
<string name="title_subscriptions">Abonnements</string>
<string name="title_recent">Récent</string>
<string name="title_popular">Populaire</string>
<string name="title_trending">Tendance</string>
<string name="title_local">Vidéos locales</string>
<string name="title_myVideos">Mes vidéos</string>
<string name="view_text">vues</string>
<string name="timeSec_text">secondes</string>
<string name="timeMin_text">minutes</string>
<string name="timeHrs_text">heures</string>
<string name="nav_header_title">Se connecter</string>
<string name="is_live_video">En direct</string>
<!-- Toast msg -->
<string name="logout_msg">Vous êtes maintenant déconnecté</string>
<!-- End Main strings -->
<!-- Start Menu strings -->
<string name="nav_subscriptions">Abonnements</string>
<string name="nav_popular">Populaire</string>
<string name="nav_trending">Tendance</string>
<string name="nav_recent">Récent</string>
<string name="nav_local">Local</string>
<string name="nav_about">À propos</string>
<string name="nav_history">Historique</string>
<string name="nav_menu_myLibrary">Ma bibliothèque</string>
<string name="nav_menu_videos">Vidéos</string>
<string name="nav_menu_more">Plus</string>
<string name="nav_likes">Les plus aimés</string>
<!-- End Menu strings -->
<!-- Start MiniMenu strings -->
<string name="action_settings">Paramètres</string>
<string name="action_login">Se connecter</string>
<string name="action_logout">Déconnexion</string>
<!-- End MiniMenu strings -->
<!-- Start Reproductor strings -->
<string name="descriptionTxt">Description :</string>
<string name="commentariesTxt">Commentaires :</string>
<string name="commentHolder">Faire un commentaire</string>
<!-- Actions -->
<string name="subscribeBtn">S\'abonner</string>
<string name="likeBtn">J\'aime</string>
<string name="dislikeBtn">Je n\'aime pas</string>
<string name="shareBtn">Partager</string>
<string name="reportBtn">Signaler</string>
<string name="unSubscribeBtn">Se désabonner</string>
<string name="commentaryText">Commentaire</string>
<string name="showMore">Afficher plus</string>
<!-- Comments -->
<string name="reply">Répondre</string>
<string name="see_replies">Voir les réponses (%1$d)</string>
<!-- Messages -->
<string name="subscribeMsg">Vous êtes abonné à cette chaîne</string>
<string name="rateMsg">Vous avez évalué la vidéo</string>
<string name="unSubscribeMsg">Vous vous êtes désabonné de cette chaîne</string>
<string name="makedCommentaryMsg">Vous avez commenté cette vidéo</string>
<string name="errorCommentaryMsg">Une erreur est survenue, réessayez</string>
<string name="emptyCommentaryMsg">Veuillez d\'abord faire un commentaire</string>
<!-- End Reproductor strings -->
<!-- Start Settings strings -->
<string name="title_activity_settings">Paramètres</string>
<!-- Example General settings -->
<string name="pref_header_general">Général</string>
<string name="pref_nfsw_title">Contenu NFSW</string>
<string name="pref_nfsw_description">Quand activé, cela peut afficher du contenu adulte et sensible.</string>
<string name="pref_hostname_title">Instance Peertube</string>
<string name="pref_hostname_error" translatable="false">-</string>
<string name="pref_message_exit">Redémarrez l\'application pour appliquer les changements</string>
<string name="pref_videos_count_title">Vidéos par page</string>
<!-- End Settings strings -->
<!-- Start Channel/Account strings -->
<string name="followersIndicator">Abonnés :</string>
<string name="hostIndicator">Hôte :</string>
<string name="accountName">Nom du compte :</string>
<!-- End Channel strings -->
<!-- Start Prompt string -->
<string name="reportDialog">Raison pour signaler cette vidéo :</string>
<string name="reportDialogMsg">Vous avez signalé la vidéo</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Bonjour fragment vide</string>
<!-- End Prompt strings -->
</resources>

View File

@ -0,0 +1,82 @@
<?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">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,25 @@
<resources>
<style name="Theme.P2play" parent="Theme.MaterialComponents.DayNight">
<item name="colorPrimary">@color/md_theme_dark_primary</item>
<item name="colorOnPrimary">@color/md_theme_dark_onPrimary</item>
<item name="colorSecondary">@color/md_theme_dark_secondary</item>
<item name="colorOnSecondary">@color/md_theme_dark_onSecondary</item>
<item name="colorError">@color/md_theme_dark_error</item>
<item name="colorOnError">@color/md_theme_dark_onError</item>
<item name="android:colorBackground">@color/md_theme_dark_background</item>
<item name="colorOnBackground">@color/md_theme_dark_onBackground</item>
<item name="colorSurface">@color/md_theme_dark_surface</item>
<item name="colorOnSurface">@color/md_theme_dark_onSurface</item>
<item name="colorPrimaryDark">@color/colorAccent</item>
<item name="colorAccent">@color/md_theme_dark_onBackground</item>
<item name="android:textColorLink">@color/md_theme_dark_secondary</item>
<item name="androidBackgroundSecondary">@color/md_theme_dark_tertiaryContainer</item>
<item name="androidOnBackgroundSecondary">@color/md_theme_dark_onTertiaryContainer</item>
</style>
<style name="Theme.P2play.NoActionBar" parent="Theme.P2play">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="androidBackgroundSecondary" format="reference" />
<attr name="androidOnBackgroundSecondary" format="reference" />
</resources>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="colorPrimary">#9F4200</color>
<color name="colorPrimaryDark">#F4DED5</color>
<color name="colorAccent">#0f3239</color>
<color name="colorHeader">#ffffff</color>
<color name="colorBody">#fff</color>
<color name="colorMenu">#000</color>
@ -10,4 +10,69 @@
<color name="colorLike">#FF3C9100</color>
<color name="colorDislike">#ec020e</color>
<color name="colorProfile">#262626</color>
<color name="durationBackground">#88000000</color>
<color name="durationColor">#ffffff</color>
<color name="seed">#f16805</color>
<color name="md_theme_light_primary">#9F4200</color>
<color name="md_theme_light_onPrimary">#FFFFFF</color>
<color name="md_theme_light_primaryContainer">#FFDBCB</color>
<color name="md_theme_light_onPrimaryContainer">#341100</color>
<color name="md_theme_light_secondary">#566500</color>
<color name="md_theme_light_onSecondary">#FFFFFF</color>
<color name="md_theme_light_secondaryContainer">#D9EC7B</color>
<color name="md_theme_light_onSecondaryContainer">#181E00</color>
<color name="md_theme_light_tertiary">#904D00</color>
<color name="md_theme_light_onTertiary">#FFFFFF</color>
<color name="md_theme_light_tertiaryContainer">#FFDCC3</color>
<color name="md_theme_light_onTertiaryContainer">#2F1500</color>
<color name="md_theme_light_error">#BA1A1A</color>
<color name="md_theme_light_errorContainer">#FFDAD6</color>
<color name="md_theme_light_onError">#FFFFFF</color>
<color name="md_theme_light_onErrorContainer">#410002</color>
<color name="md_theme_light_background">#F8FDFF</color>
<color name="md_theme_light_onBackground">#001F25</color>
<color name="md_theme_light_surface">#F8FDFF</color>
<color name="md_theme_light_onSurface">#001F25</color>
<color name="md_theme_light_surfaceVariant">#F4DED5</color>
<color name="md_theme_light_onSurfaceVariant">#52443D</color>
<color name="md_theme_light_outline">#85736C</color>
<color name="md_theme_light_inverseOnSurface">#D6F6FF</color>
<color name="md_theme_light_inverseSurface">#00363F</color>
<color name="md_theme_light_inversePrimary">#FFB692</color>
<color name="md_theme_light_shadow">#000000</color>
<color name="md_theme_light_surfaceTint">#9F4200</color>
<color name="md_theme_light_outlineVariant">#D7C2B9</color>
<color name="md_theme_light_scrim">#000000</color>
<color name="md_theme_dark_primary">#FFB692</color>
<color name="md_theme_dark_onPrimary">#562000</color>
<color name="md_theme_dark_primaryContainer">#793000</color>
<color name="md_theme_dark_onPrimaryContainer">#FFDBCB</color>
<color name="md_theme_dark_secondary">#BDD062</color>
<color name="md_theme_dark_onSecondary">#2C3400</color>
<color name="md_theme_dark_secondaryContainer">#404C00</color>
<color name="md_theme_dark_onSecondaryContainer">#D9EC7B</color>
<color name="md_theme_dark_tertiary">#FFB77C</color>
<color name="md_theme_dark_onTertiary">#4D2600</color>
<color name="md_theme_dark_tertiaryContainer">#6E3900</color>
<color name="md_theme_dark_onTertiaryContainer">#FFDCC3</color>
<color name="md_theme_dark_error">#FFB4AB</color>
<color name="md_theme_dark_errorContainer">#93000A</color>
<color name="md_theme_dark_onError">#690005</color>
<color name="md_theme_dark_onErrorContainer">#FFDAD6</color>
<color name="md_theme_dark_background">#001F25</color>
<color name="md_theme_dark_onBackground">#A6EEFF</color>
<color name="md_theme_dark_surface">#001F25</color>
<color name="md_theme_dark_onSurface">#A6EEFF</color>
<color name="md_theme_dark_surfaceVariant">#52443D</color>
<color name="md_theme_dark_onSurfaceVariant">#D7C2B9</color>
<color name="md_theme_dark_outline">#A08D85</color>
<color name="md_theme_dark_inverseOnSurface">#001F25</color>
<color name="md_theme_dark_inverseSurface">#A6EEFF</color>
<color name="md_theme_dark_inversePrimary">#9F4200</color>
<color name="md_theme_dark_shadow">#000000</color>
<color name="md_theme_dark_surfaceTint">#FFB692</color>
<color name="md_theme_dark_outlineVariant">#52443D</color>
<color name="md_theme_dark_scrim">#000000</color>
</resources>

View File

@ -9,14 +9,13 @@
<string name="charging">Loading…</string>
<!-- End Global string -->
<!-- Start About strings -->
<string name="aboutGitUrl" translatable="false">https://gitlab.com/agosto182/p2play/</string>
<string name="aboutGnuUrl" translatable="false">https://personaljournal.ca/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 follow our blog:</string>
<string name="aboutLicense">Copyleft GNU GPLv3 License</string>
<string name="aboutLicense">Licence GNU GPLv3 License</string>
<string name="aboutInstance">About instance</string>
<string name="aboutInWeb">You can see terms and more on the web:</string>
<!-- End About strings -->
@ -25,6 +24,7 @@
<string name="okButton">Accept</string>
<string name="errorMsg">Error, try again</string>
<string name="finallyMsg">Host saved</string>
<string name="instance">Instance</string>
<!-- End Host strings -->
<!-- Start Login strings -->
<string name="loginInfo">Login or register new account</string>
@ -34,11 +34,12 @@
<string name="passwordText" translatable="false"> </string>
<string name="loginBtn">Login now</string>
<string name="registerActionBtn">Create new account</string>
<string name="twoFactorLabel">Two factor code</string>
<!-- 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="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="registerFailed_msg">Invalid data</string>
<!-- Register msg -->
@ -59,8 +60,9 @@
<string name="timeHrs_text">hours</string>
<string name="nav_header_title">Log In</string>
<string name="nav_header_subtitle" translatable="false">P2Play</string>
<string name="is_live_video">Live</string>
<!-- Toast msg -->
<string name="logout_msg">You are disconnected</string>
<string name="logout_msg">You are now disconnected</string>
<!-- End Main strings -->
<!-- Start Menu strings -->
<string name="nav_subscriptions">Subscriptions</string>
@ -82,8 +84,8 @@
<!-- End MiniMenu strings -->
<!-- Start Reproductor strings -->
<string name="descriptionTxt">Description:</string>
<string name="commentariesTxt">Commentaries:</string>
<string name="commentHolder">Make a commentary</string>
<string name="commentariesTxt">Comments:</string>
<string name="commentHolder">Make a comment</string>
<!-- Actions -->
<string name="subscribeBtn">Subscribe</string>
<string name="likeBtn">Like</string>
@ -93,31 +95,40 @@
<string name="unSubscribeBtn">Unsubscribe</string>
<string name="commentaryText">Comment</string>
<string name="showMore">Show more</string>
<!-- Comments -->
<string name="reply">Reply</string>
<string name="see_replies">See replies (%1$d)</string>
<!-- Messages -->
<string name="subscribeMsg">You are subscribed to this channel</string>
<string name="rateMsg">You are rated the video</string>
<string name="unSubscribeMsg">You are unsubscribed to this channel</string>
<string name="makedCommentaryMsg">You are commented this video</string>
<string name="subscribeMsg">You have subscribed to this channel</string>
<string name="rateMsg">You have rated the video</string>
<string name="unSubscribeMsg">You have unsubscribed from this channel</string>
<string name="makedCommentaryMsg">You have commented on this video</string>
<string name="errorCommentaryMsg">An error has occurred, try again</string>
<string name="emptyCommentaryMsg">Please make a comment first</string>
<string name="downloadText">Download</string>
<string name="downloadStarted">Download as started</string>
<string name="downloadFailed">Unable to download this video</string>
<!-- End Reproductor strings -->
<!-- Start Settings strings -->
<string name="title_activity_settings">Settings</string>
<!-- Example General settings -->
<string name="pref_header_general">General</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_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>
<!-- End Settings strings -->
<!-- Start Channel strings -->
<!-- Start Channel/Account strings -->
<string name="followersIndicator">Followers:</string>
<string name="hostIndicator">Host:</string>
<string name="accountName">Account Name:</string>
<!-- End Channel strings -->
<!-- Start Prompt string -->
<string name="reportDialog">Reason for report video:</string>
<string name="reportDialogMsg">You are reported the video</string>
<string name="reportDialog">Reason to report this video:</string>
<string name="reportDialogMsg">You reported the video</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<!-- End Prompt strings -->
</resources>

View File

@ -0,0 +1,29 @@
<resources>
<style name="Theme.P2play" parent="Theme.MaterialComponents.DayNight">
<item name="colorPrimary">@color/md_theme_light_primary</item>
<item name="colorOnPrimary">@color/md_theme_light_onPrimary</item>
<item name="colorSecondary">@color/md_theme_light_secondary</item>
<item name="colorOnSecondary">@color/md_theme_light_onSecondary</item>
<item name="colorError">@color/md_theme_light_error</item>
<item name="colorOnError">@color/md_theme_light_onError</item>
<item name="android:colorBackground">@color/md_theme_light_background</item>
<item name="colorOnBackground">@color/md_theme_light_onBackground</item>
<item name="colorSurface">@color/md_theme_light_surface</item>
<item name="colorOnSurface">@color/md_theme_light_onSurface</item>
<item name="colorPrimaryDark">@color/md_theme_light_primary</item>
<item name="colorAccent">@color/md_theme_light_secondary</item>
<item name="android:textColorLink">@color/md_theme_light_secondary</item>
<item name="androidBackgroundSecondary">@color/md_theme_light_tertiaryContainer</item>
<item name="androidOnBackgroundSecondary">@color/md_theme_light_onTertiaryContainer</item>
</style>
<style name="Theme.P2play.NoActionBar" parent="Theme.P2play">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="Theme.P2play.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="Theme.P2play.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

View File

@ -1,29 +0,0 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- NOTE: EditTextPreference accepts EditText attributes. -->
<!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
<EditTextPreference
android:capitalize="words"
android:defaultValue="@string/pref_hostname_error"
android:inputType="textCapWords"
android:key="hostP2play"
android:maxLines="1"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/pref_hostname_title" />
<SwitchPreference
android:defaultValue="false"
android:key="show_nfsw"
android:summary="@string/pref_nfsw_description"
android:title="@string/pref_nfsw_title" />
<EditTextPreference
android:defaultValue="15"
android:inputType="number"
android:key="videos_count"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/pref_videos_count_title" />
</PreferenceScreen>

View File

@ -1,20 +0,0 @@
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<!-- These settings headers are only used on tablets. -->
<header
android:fragment="org.libre.agosto.p2play.SettingsActivity$GeneralPreferenceFragment"
android:icon="@drawable/ic_info_black_24dp"
android:title="@string/pref_header_general" />
<!-- <header
android:fragment="org.libre.agosto.p2play.SettingsActivity$NotificationPreferenceFragment"
android:icon="@drawable/ic_notifications_black_24dp"
android:title="@string/pref_header_notifications" />
<header
android:fragment="org.libre.agosto.p2play.SettingsActivity$DataSyncPreferenceFragment"
android:icon="@drawable/ic_sync_black_24dp"
android:title="@string/pref_header_data_sync" /> -->
</preference-headers>

View File

@ -0,0 +1,31 @@
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory app:title="@string/pref_header_general">
<EditTextPreference
app:defaultValue="@string/pref_hostname_error"
android:inputType="text"
app:key="hostP2play"
android:maxLines="1"
android:selectAllOnFocus="true"
android:singleLine="true"
app:useSimpleSummaryProvider="true"
app:title="@string/pref_hostname_title" />
<SwitchPreference
app:defaultValue="false"
app:key="show_nsfw"
app:summary="@string/pref_nfsw_description"
app:title="@string/pref_nfsw_title" />
<EditTextPreference
app:defaultValue="15"
android:inputType="number"
app:key="videos_count"
android:selectAllOnFocus="true"
app:singleLine="true"
app:useSimpleSummaryProvider="true"
app:title="@string/pref_videos_count_title" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -1,9 +1,8 @@
package org.libre.agosto.p2play
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*

View File

@ -1,15 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.9.20'
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.android.tools.build:gradle:8.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@ -18,10 +17,10 @@ buildscript {
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
task clean(type: Delete) {
tasks.register('clean', Delete) {
delete rootProject.buildDir
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Some files were not shown because too many files have changed in this diff Show More