mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-01-06 01:20:29 +05:30
Merge branch 'master' into title_description_seperation
This commit is contained in:
commit
33d634b713
@ -10,8 +10,8 @@ android {
|
|||||||
applicationId 'com.github.libretube'
|
applicationId 'com.github.libretube'
|
||||||
minSdk 21
|
minSdk 21
|
||||||
targetSdk 31
|
targetSdk 31
|
||||||
versionCode 6
|
versionCode 7
|
||||||
versionName '0.2.4'
|
versionName '0.2.5'
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
resValue "string", "app_name", "LibreTube"
|
resValue "string", "app_name", "LibreTube"
|
||||||
@ -71,7 +71,8 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'
|
implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'
|
||||||
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.13.2'
|
//do not update jackson annotations! it does not supports <api26
|
||||||
|
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.13.1'
|
||||||
|
|
||||||
implementation 'com.arthenica:ffmpeg-kit-min:4.5.1.LTS'
|
implementation 'com.arthenica:ffmpeg-kit-min:4.5.1.LTS'
|
||||||
|
|
||||||
|
@ -16,10 +16,23 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
"versionCode": 5,
|
"versionCode": 7,
|
||||||
"versionName": "0.2.3",
|
"versionName": "0.2.5",
|
||||||
"outputFile": "app-x86_64-release.apk"
|
"outputFile": "app-x86_64-release.apk"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "ONE_OF_MANY",
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"filterType": "ABI",
|
||||||
|
"value": "armeabi-v7a"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"attributes": [],
|
||||||
|
"versionCode": 7,
|
||||||
|
"versionName": "0.2.5",
|
||||||
|
"outputFile": "app-armeabi-v7a-release.apk"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "ONE_OF_MANY",
|
"type": "ONE_OF_MANY",
|
||||||
"filters": [
|
"filters": [
|
||||||
@ -29,8 +42,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
"versionCode": 5,
|
"versionCode": 7,
|
||||||
"versionName": "0.2.3",
|
"versionName": "0.2.5",
|
||||||
"outputFile": "app-x86-release.apk"
|
"outputFile": "app-x86-release.apk"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -42,22 +55,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
"versionCode": 5,
|
"versionCode": 7,
|
||||||
"versionName": "0.2.3",
|
"versionName": "0.2.5",
|
||||||
"outputFile": "app-arm64-v8a-release.apk"
|
"outputFile": "app-arm64-v8a-release.apk"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "ONE_OF_MANY",
|
|
||||||
"filters": [
|
|
||||||
{
|
|
||||||
"filterType": "ABI",
|
|
||||||
"value": "armeabi-v7a"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"attributes": [],
|
|
||||||
"versionCode": 5,
|
|
||||||
"versionName": "0.2.3",
|
|
||||||
"outputFile": "app-armeabi-v7a-release.apk"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"elementType": "File"
|
"elementType": "File"
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@ -43,7 +43,9 @@ class Home : Fragment() {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val recyclerView = view.findViewById<RecyclerView>(R.id.recview)
|
val recyclerView = view.findViewById<RecyclerView>(R.id.recview)
|
||||||
recyclerView.layoutManager = GridLayoutManager(view.context, resources.getInteger(R.integer.grid_items))
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
val grid = sharedPreferences.getString("grid", resources.getInteger(R.integer.grid_items).toString())!!
|
||||||
|
recyclerView.layoutManager = GridLayoutManager(view.context, grid.toInt())
|
||||||
val progressbar = view.findViewById<ProgressBar>(R.id.progressBar)
|
val progressbar = view.findViewById<ProgressBar>(R.id.progressBar)
|
||||||
fetchJson(progressbar,recyclerView)
|
fetchJson(progressbar,recyclerView)
|
||||||
refreshLayout = view.findViewById(R.id.home_refresh)
|
refreshLayout = view.findViewById(R.id.home_refresh)
|
||||||
|
@ -13,6 +13,7 @@ import android.util.Log
|
|||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
@ -39,6 +40,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
RetrofitInstance.url = sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks/")!!
|
RetrofitInstance.url = sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks/")!!
|
||||||
DynamicColors.applyToActivitiesIfAvailable(application)
|
DynamicColors.applyToActivitiesIfAvailable(application)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
when (sharedPreferences.getString("theme_togglee", "A")!!) {
|
||||||
|
"A" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||||
|
"L" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||||
|
"D" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||||
|
}
|
||||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
|
|
||||||
bottomNavigationView = findViewById(R.id.bottomNav)
|
bottomNavigationView = findViewById(R.id.bottomNav)
|
||||||
|
@ -52,8 +52,13 @@ interface PipedApi {
|
|||||||
@POST("unsubscribe")
|
@POST("unsubscribe")
|
||||||
suspend fun unsubscribe(@Header("Authorization") token: String, @Body subscribe: Subscribe): Message
|
suspend fun unsubscribe(@Header("Authorization") token: String, @Body subscribe: Subscribe): Message
|
||||||
|
|
||||||
|
@POST("import")
|
||||||
|
suspend fun importSubscriptions(@Header("Authorization") token: String, @Body channels: List<String>): Message
|
||||||
|
|
||||||
//only for fetching servers list
|
//only for fetching servers list
|
||||||
@GET
|
@GET
|
||||||
suspend fun getInstances(@Url url: String): List<Instances>
|
suspend fun getInstances(@Url url: String): List<Instances>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -194,9 +194,9 @@ class PlayerFragment : Fragment() {
|
|||||||
view.findViewById<ConstraintLayout>(R.id.main_container).isClickable = true
|
view.findViewById<ConstraintLayout>(R.id.main_container).isClickable = true
|
||||||
view.findViewById<LinearLayout>(R.id.linLayout).visibility = View.GONE
|
view.findViewById<LinearLayout>(R.id.linLayout).visibility = View.GONE
|
||||||
val mainActivity = activity as MainActivity
|
val mainActivity = activity as MainActivity
|
||||||
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
mainActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||||
isFullScreen = true
|
isFullScreen=true
|
||||||
} else {
|
}else{
|
||||||
with(motionLayout) {
|
with(motionLayout) {
|
||||||
getConstraintSet(R.id.start).constrainHeight(R.id.player, 0)
|
getConstraintSet(R.id.start).constrainHeight(R.id.player, 0)
|
||||||
enableTransition(R.id.yt_transition, true)
|
enableTransition(R.id.yt_transition, true)
|
||||||
@ -231,9 +231,11 @@ class PlayerFragment : Fragment() {
|
|||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
println(e)
|
println(e)
|
||||||
Log.e(TAG, "IOException, you might not have internet connection")
|
Log.e(TAG, "IOException, you might not have internet connection")
|
||||||
|
Toast.makeText(context,R.string.unknown_error, Toast.LENGTH_SHORT).show()
|
||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
} catch (e: HttpException) {
|
} catch (e: HttpException) {
|
||||||
Log.e(TAG, "HttpException, unexpected response")
|
Log.e(TAG, "HttpException, unexpected response")
|
||||||
|
Toast.makeText(context,R.string.server_error, Toast.LENGTH_SHORT).show()
|
||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
}
|
}
|
||||||
var videosNameArray: Array<CharSequence> = arrayOf()
|
var videosNameArray: Array<CharSequence> = arrayOf()
|
||||||
@ -266,10 +268,12 @@ class PlayerFragment : Fragment() {
|
|||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
val defres = sharedPreferences.getString("default_res", "")!!
|
val defres = sharedPreferences.getString("default_res", "")!!
|
||||||
when {
|
when {
|
||||||
defres != "" -> {
|
defres!="" -> {
|
||||||
run lit@{
|
var foundRes = false
|
||||||
|
run lit@ {
|
||||||
response.videoStreams!!.forEachIndexed { index, pipedStream ->
|
response.videoStreams!!.forEachIndexed { index, pipedStream ->
|
||||||
if (pipedStream.quality!!.contains(defres)) {
|
if (pipedStream.quality!!.contains(defres)){
|
||||||
|
foundRes = true
|
||||||
val dataSourceFactory: DataSource.Factory =
|
val dataSourceFactory: DataSource.Factory =
|
||||||
DefaultHttpDataSource.Factory()
|
DefaultHttpDataSource.Factory()
|
||||||
val videoItem: MediaItem = MediaItem.Builder()
|
val videoItem: MediaItem = MediaItem.Builder()
|
||||||
@ -288,6 +292,12 @@ class PlayerFragment : Fragment() {
|
|||||||
exoPlayer.setMediaSource(mergeSource)
|
exoPlayer.setMediaSource(mergeSource)
|
||||||
view.findViewById<TextView>(R.id.quality_text).text = videosNameArray[index + 1]
|
view.findViewById<TextView>(R.id.quality_text).text = videosNameArray[index + 1]
|
||||||
return@lit
|
return@lit
|
||||||
|
}else if (index+1 == response.videoStreams.size){
|
||||||
|
val mediaItem: MediaItem = MediaItem.Builder()
|
||||||
|
.setUri(response.hls)
|
||||||
|
.setSubtitleConfigurations(subtitle)
|
||||||
|
.build()
|
||||||
|
exoPlayer.setMediaItem(mediaItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,11 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.AutoCompleteTextView
|
import android.widget.AutoCompleteTextView
|
||||||
|
import android.widget.TextView.OnEditorActionListener
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
@ -75,6 +77,17 @@ class SearchFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
autoTextView.setOnEditorActionListener(OnEditorActionListener { _, actionId, _ ->
|
||||||
|
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||||
|
hideKeyboard();
|
||||||
|
autoTextView.dismissDropDown();
|
||||||
|
return@OnEditorActionListener true
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
autoTextView.setOnDismissListener {
|
||||||
|
hideKeyboard();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchSuggestions(query: String, autoTextView: AutoCompleteTextView){
|
private fun fetchSuggestions(query: String, autoTextView: AutoCompleteTextView){
|
||||||
@ -125,4 +138,8 @@ class SearchFragment : Fragment() {
|
|||||||
requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
hideKeyboard()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
package com.github.libretube
|
package com.github.libretube
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.ContentValues.TAG
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
@ -15,59 +14,100 @@ import androidx.activity.result.ActivityResultLauncher
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
|
||||||
import com.blankj.utilcode.util.UriUtils
|
import com.blankj.utilcode.util.UriUtils
|
||||||
import com.github.libretube.obj.Subscribe
|
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.*
|
||||||
import java.io.IOException
|
|
||||||
import java.util.zip.ZipFile
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
class Settings : PreferenceFragmentCompat() {
|
|
||||||
|
|
||||||
|
class Settings : PreferenceFragmentCompat() {
|
||||||
|
val TAG = "Settings"
|
||||||
companion object {
|
companion object {
|
||||||
lateinit var getContent: ActivityResultLauncher<String>
|
lateinit var getContent: ActivityResultLauncher<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
|
getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
|
||||||
|
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
var zipfile = ZipFile(UriUtils.uri2File(uri))
|
try{
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
|
||||||
var zipentry =
|
// Open a specific media item using ParcelFileDescriptor.
|
||||||
zipfile.getEntry("Takeout/YouTube and YouTube Music/subscriptions/subscriptions.csv")
|
val resolver: ContentResolver =
|
||||||
|
requireActivity()
|
||||||
|
.contentResolver
|
||||||
|
|
||||||
var inputStream = zipfile.getInputStream(zipentry)
|
// "rw" for read-and-write;
|
||||||
|
// "rwt" for truncating or overwriting existing file contents.
|
||||||
|
val readOnlyMode = "r"
|
||||||
|
// uri - I have got from onActivityResult
|
||||||
|
//uri = data.getData();
|
||||||
|
val parcelFile = resolver.openFileDescriptor(uri, readOnlyMode)
|
||||||
|
val fileReader = FileReader(parcelFile!!.fileDescriptor)
|
||||||
|
val reader = BufferedReader(fileReader)
|
||||||
|
var line: String?
|
||||||
|
var channels: MutableList<String> = emptyList<String>().toMutableList()
|
||||||
|
var subscribedCount = 0
|
||||||
|
while (reader.readLine().also { line = it } != null) {
|
||||||
|
if (line!!.replace(" ","") != "" && subscribedCount >0) {
|
||||||
|
val channel = line!!.split(",")[0]
|
||||||
|
channels.add(channel)
|
||||||
|
|
||||||
val baos = ByteArrayOutputStream()
|
Log.d(TAG, "subscribed: " + line + " total: " + subscribedCount)
|
||||||
|
}
|
||||||
|
subscribedCount++
|
||||||
|
}
|
||||||
|
subscribe(channels)
|
||||||
|
reader.close()
|
||||||
|
fileReader.close()
|
||||||
|
}else{
|
||||||
|
Log.d(TAG,UriUtils.uri2File(uri).toString())
|
||||||
|
val file = UriUtils.uri2File(uri)
|
||||||
|
var inputStream: InputStream? = null
|
||||||
|
if (file.extension == "zip") {
|
||||||
|
var zipfile = ZipFile(file)
|
||||||
|
|
||||||
inputStream.use { it.copyTo(baos) }
|
var zipentry =
|
||||||
|
zipfile.getEntry("Takeout/YouTube and YouTube Music/subscriptions/subscriptions.csv")
|
||||||
|
|
||||||
var subscriptions = baos.toByteArray().decodeToString()
|
inputStream = zipfile.getInputStream(zipentry)
|
||||||
|
}else if(file.extension == "csv"){
|
||||||
|
inputStream = file.inputStream()
|
||||||
|
}
|
||||||
|
val baos = ByteArrayOutputStream()
|
||||||
|
|
||||||
var subscribedCount = 0
|
inputStream?.use { it.copyTo(baos) }
|
||||||
|
|
||||||
for (text in subscriptions.lines()) {
|
var subscriptions = baos.toByteArray().decodeToString()
|
||||||
if (text.take(24) != "Channel Id,Channel Url,C" && !text.take(24).isEmpty()) {
|
var channels: MutableList<String> = emptyList<String>().toMutableList()
|
||||||
subscribe(text.take(24))
|
var subscribedCount = 0
|
||||||
subscribedCount++
|
for (text in subscriptions.lines().subList(1,subscriptions.lines().size)) {
|
||||||
Log.d(TAG, "subscribed: " + text + " total: " + subscribedCount)
|
if (text.replace(" ","") != "") {
|
||||||
|
val channel = text.split(",")[0]
|
||||||
|
channels.add(channel)
|
||||||
|
subscribedCount++
|
||||||
|
Log.d(TAG, "subscribed: " + text + " total: " + subscribedCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subscribe(channels)
|
||||||
}
|
}
|
||||||
}
|
}catch (e: Exception){
|
||||||
|
Log.e(TAG,e.toString())
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
context,
|
context,
|
||||||
"Subscribed to " + subscribedCount + " channels.",
|
R.string.error,
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -100,17 +140,24 @@ class Settings : PreferenceFragmentCompat() {
|
|||||||
|
|
||||||
val importFromYt = findPreference<Preference>("import_from_yt")
|
val importFromYt = findPreference<Preference>("import_from_yt")
|
||||||
importFromYt?.setOnPreferenceClickListener {
|
importFromYt?.setOnPreferenceClickListener {
|
||||||
|
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
|
||||||
|
val token = sharedPref?.getString("token","")!!
|
||||||
//check StorageAccess
|
//check StorageAccess
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
Log.d("myz", "" + Build.VERSION.SDK_INT)
|
Log.d("myz", "" + Build.VERSION.SDK_INT)
|
||||||
if (!Environment.isExternalStorageManager()) {
|
if (ContextCompat.checkSelfPermission(this.requireContext(), Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
ActivityCompat.requestPermissions(
|
ActivityCompat.requestPermissions(
|
||||||
this.requireActivity(), arrayOf(
|
this.requireActivity(), arrayOf(
|
||||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
Manifest.permission.MANAGE_EXTERNAL_STORAGE
|
Manifest.permission.MANAGE_EXTERNAL_STORAGE
|
||||||
), 1
|
), 1
|
||||||
) //permission request code is just an int
|
) //permission request code is just an int
|
||||||
|
}else if (token != ""){
|
||||||
|
getContent.launch("*/*")
|
||||||
|
}else{
|
||||||
|
Toast.makeText(context, R.string.login_first, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ActivityCompat.checkSelfPermission(
|
if (ActivityCompat.checkSelfPermission(
|
||||||
@ -129,12 +176,12 @@ class Settings : PreferenceFragmentCompat() {
|
|||||||
),
|
),
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
|
}else if (token != ""){
|
||||||
|
getContent.launch("*/*")
|
||||||
|
}else{
|
||||||
|
Toast.makeText(context, R.string.login_first, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getContent.launch("application/zip")
|
|
||||||
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,15 +244,12 @@ class Settings : PreferenceFragmentCompat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun subscribe(channel_id: String) {
|
private fun subscribe(channels: List<String>) {
|
||||||
fun run() {
|
fun run() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
val response = try {
|
val response = try {
|
||||||
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
|
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
|
||||||
RetrofitInstance.api.subscribe(
|
RetrofitInstance.api.importSubscriptions(sharedPref?.getString("token", "")!!,channels)
|
||||||
sharedPref?.getString("token", "")!!,
|
|
||||||
Subscribe(channel_id)
|
|
||||||
)
|
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Log.e(TAG, "IOException, you might not have internet connection")
|
Log.e(TAG, "IOException, you might not have internet connection")
|
||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
@ -213,9 +257,17 @@ class Settings : PreferenceFragmentCompat() {
|
|||||||
Log.e(TAG, "HttpException, unexpected response$e")
|
Log.e(TAG, "HttpException, unexpected response$e")
|
||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
}
|
}
|
||||||
|
if(response.message == "ok"){
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
R.string.importsuccess,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ class Subscriptions : Fragment() {
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
|
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
|
||||||
token = sharedPref?.getString("token","")!!
|
token = sharedPref?.getString("token","")!!
|
||||||
Log.e(TAG,token)
|
|
||||||
refreshLayout = view.findViewById(R.id.sub_refresh)
|
refreshLayout = view.findViewById(R.id.sub_refresh)
|
||||||
if(token!=""){
|
if(token!=""){
|
||||||
view.findViewById<RelativeLayout>(R.id.loginOrRegister).visibility=View.GONE
|
view.findViewById<RelativeLayout>(R.id.loginOrRegister).visibility=View.GONE
|
||||||
@ -59,7 +58,9 @@ class Subscriptions : Fragment() {
|
|||||||
fetchChannels(channelRecView)
|
fetchChannels(channelRecView)
|
||||||
|
|
||||||
var feedRecView = view.findViewById<RecyclerView>(R.id.sub_feed)
|
var feedRecView = view.findViewById<RecyclerView>(R.id.sub_feed)
|
||||||
feedRecView.layoutManager = GridLayoutManager(view.context, resources.getInteger(R.integer.grid_items))
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
val grid = sharedPreferences.getString("grid", resources.getInteger(R.integer.grid_items).toString())!!
|
||||||
|
feedRecView.layoutManager = GridLayoutManager(view.context, grid.toInt())
|
||||||
fetchFeed(feedRecView, progressBar)
|
fetchFeed(feedRecView, progressBar)
|
||||||
|
|
||||||
refreshLayout?.setOnRefreshListener {
|
refreshLayout?.setOnRefreshListener {
|
||||||
@ -92,7 +93,7 @@ class Subscriptions : Fragment() {
|
|||||||
val response = try {
|
val response = try {
|
||||||
RetrofitInstance.api.getFeed(token)
|
RetrofitInstance.api.getFeed(token)
|
||||||
}catch(e: IOException) {
|
}catch(e: IOException) {
|
||||||
println(e)
|
Log.e(TAG,e.toString())
|
||||||
Log.e(TAG, "IOException, you might not have internet connection")
|
Log.e(TAG, "IOException, you might not have internet connection")
|
||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
} catch (e: HttpException) {
|
} catch (e: HttpException) {
|
||||||
@ -119,7 +120,7 @@ class Subscriptions : Fragment() {
|
|||||||
val response = try {
|
val response = try {
|
||||||
RetrofitInstance.api.subscriptions(token)
|
RetrofitInstance.api.subscriptions(token)
|
||||||
}catch(e: IOException) {
|
}catch(e: IOException) {
|
||||||
println(e)
|
Log.e(TAG,e.toString())
|
||||||
Log.e(TAG, "IOException, you might not have internet connection")
|
Log.e(TAG, "IOException, you might not have internet connection")
|
||||||
return@launchWhenCreated
|
return@launchWhenCreated
|
||||||
} catch (e: HttpException) {
|
} catch (e: HttpException) {
|
||||||
@ -137,16 +138,11 @@ class Subscriptions : Fragment() {
|
|||||||
}
|
}
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
Log.e(TAG,"Stopped")
|
|
||||||
subscriptionAdapter = null
|
|
||||||
view?.findViewById<RecyclerView>(R.id.sub_feed)?.adapter=null
|
|
||||||
super.onStop()
|
|
||||||
}
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
Log.e(TAG,"Destroyed")
|
Log.e(TAG,"Destroyed")
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
subscriptionAdapter = null
|
||||||
|
view?.findViewById<RecyclerView>(R.id.sub_feed)?.adapter=null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
10
app/src/main/res/drawable/ic_column.xml
Normal file
10
app/src/main/res/drawable/ic_column.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M10,18h5L15,5h-5v13zM4,18h5L9,5L4,5v13zM16,5v13h5L21,5h-5z"/>
|
||||||
|
</vector>
|
@ -236,12 +236,12 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_toEndOf="@+id/player_channelImage"
|
|
||||||
android:layout_toStartOf="@+id/player_subscribe"
|
android:layout_toStartOf="@+id/player_subscribe"
|
||||||
android:text=""
|
android:layout_toEndOf="@+id/player_channelImage"
|
||||||
android:textStyle="bold"
|
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"/>
|
android:maxLines="1"
|
||||||
|
android:text=""
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
@ -51,7 +51,9 @@
|
|||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintEnd_toEndOf="@+id/thumbnailcard"
|
app:layout_constraintEnd_toEndOf="@+id/thumbnailcard"
|
||||||
app:layout_constraintStart_toEndOf="@+id/channel_image"
|
app:layout_constraintStart_toEndOf="@+id/channel_image"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/thumbnailcard" />
|
app:layout_constraintTop_toBottomOf="@+id/thumbnailcard"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textView_channel"
|
android:id="@+id/textView_channel"
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
<item name="android:statusBarColor" tools:targetApi="m">@android:color/transparent</item>
|
<item name="android:statusBarColor" tools:targetApi="m">@android:color/transparent</item>
|
||||||
<item name="android:windowLightStatusBar" tools:targetApi="m">false</item>
|
<item name="android:windowLightStatusBar" tools:targetApi="m">false</item>
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
<item name="fontFamily">@font/roboto</item>
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
@ -32,7 +32,6 @@
|
|||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
<item name="android:windowLightStatusBar">true</item>
|
<item name="android:windowLightStatusBar">true</item>
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
<item name="fontFamily">@font/roboto</item>
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
@ -417,6 +417,7 @@
|
|||||||
<item>D</item>
|
<item>D</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="defres">
|
<string-array name="defres">
|
||||||
|
<item>HLS</item>
|
||||||
<item>1080p</item>
|
<item>1080p</item>
|
||||||
<item>720p</item>
|
<item>720p</item>
|
||||||
<item>480p</item>
|
<item>480p</item>
|
||||||
@ -424,4 +425,20 @@
|
|||||||
<item>240p</item>
|
<item>240p</item>
|
||||||
<item>144p</item>
|
<item>144p</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="defresValue">
|
||||||
|
<item></item>
|
||||||
|
<item>1080p</item>
|
||||||
|
<item>720p</item>
|
||||||
|
<item>480p</item>
|
||||||
|
<item>360p</item>
|
||||||
|
<item>240p</item>
|
||||||
|
<item>144p</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="grid">
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
<item>4</item>
|
||||||
|
<item>5</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
@ -17,11 +17,13 @@
|
|||||||
<string name="loggedout">Logged out successfully!</string>
|
<string name="loggedout">Logged out successfully!</string>
|
||||||
<string name="registered">Registered successfully! You may now subscribe to channels you want.</string>
|
<string name="registered">Registered successfully! You may now subscribe to channels you want.</string>
|
||||||
<string name="already_logged_in">You are already logged in, you may logout of your account.</string>
|
<string name="already_logged_in">You are already logged in, you may logout of your account.</string>
|
||||||
|
<string name="login_first">Please login and try again!</string>
|
||||||
<string name="instances">Choose an instance</string>
|
<string name="instances">Choose an instance</string>
|
||||||
<string name="customInstance">Add a custom instance</string>
|
<string name="customInstance">Add a custom instance</string>
|
||||||
<string name="region">Choose a region</string>
|
<string name="region">Choose a region</string>
|
||||||
<string name="login_register">Login/Register</string>
|
<string name="login_register">Login/Register</string>
|
||||||
<string name="please_login">Please Login or Register from the settings to show your Subscriptions!</string>
|
<string name="please_login">Please Login or Register from the settings to show your Subscriptions!</string>
|
||||||
|
<string name="importsuccess">Subscribed successfully!</string>
|
||||||
<string name="subscribeIsEmpty">Subscribe to some channels first!</string>
|
<string name="subscribeIsEmpty">Subscribe to some channels first!</string>
|
||||||
<string name="cannotDownload">Can\'t Download this stream!</string>
|
<string name="cannotDownload">Can\'t Download this stream!</string>
|
||||||
<string name="dlcomplete">Download is completed!</string>
|
<string name="dlcomplete">Download is completed!</string>
|
||||||
@ -33,7 +35,9 @@
|
|||||||
<string name="app_theme">App theme</string>
|
<string name="app_theme">App theme</string>
|
||||||
<string name="server_error">Server countered a problem. Maybe try another instance?</string>
|
<string name="server_error">Server countered a problem. Maybe try another instance?</string>
|
||||||
<string name="unknown_error">Network error!</string>
|
<string name="unknown_error">Network error!</string>
|
||||||
|
<string name="error">Something went wrong!</string>
|
||||||
<string name="empty">Username and Password can\'t be empty!</string>
|
<string name="empty">Username and Password can\'t be empty!</string>
|
||||||
<string name="notgmail">This is not your gmail account!</string>
|
<string name="notgmail">This is not your gmail account!</string>
|
||||||
<string name="defres">Default Video Resolution</string>
|
<string name="defres">Default Video Resolution</string>
|
||||||
|
<string name="grid">Choose the grid columns</string>
|
||||||
</resources>
|
</resources>
|
@ -29,6 +29,5 @@
|
|||||||
<item name="colorPrimaryInverse">@color/md_theme_light_primaryInverse</item>
|
<item name="colorPrimaryInverse">@color/md_theme_light_primaryInverse</item>
|
||||||
|
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
<item name="fontFamily">@font/roboto</item>
|
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
@ -1,11 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<androidx.preference.SwitchPreferenceCompat
|
|
||||||
app:key="darkMode"
|
|
||||||
app:title="Toggle dark mode"
|
|
||||||
app:isPreferenceVisible="false"/>
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
app:key="region"
|
app:key="region"
|
||||||
app:title="@string/region"
|
app:title="@string/region"
|
||||||
@ -54,10 +49,19 @@
|
|||||||
app:title="@string/defres"
|
app:title="@string/defres"
|
||||||
app:key="default_res"
|
app:key="default_res"
|
||||||
app:entries="@array/defres"
|
app:entries="@array/defres"
|
||||||
app:entryValues="@array/defres"
|
app:entryValues="@array/defresValue"
|
||||||
app:defaultValue=""
|
app:defaultValue=""
|
||||||
android:icon="@drawable/ic_hd"
|
android:icon="@drawable/ic_hd"
|
||||||
app:useSimpleSummaryProvider="true"
|
app:useSimpleSummaryProvider="true"
|
||||||
/>
|
/>
|
||||||
|
<ListPreference
|
||||||
|
app:title="@string/grid"
|
||||||
|
app:key="grid"
|
||||||
|
app:entries="@array/grid"
|
||||||
|
app:entryValues="@array/grid"
|
||||||
|
app:defaultValue="@integer/grid_items"
|
||||||
|
android:icon="@drawable/ic_column"
|
||||||
|
app:useSimpleSummaryProvider="true"
|
||||||
|
/>
|
||||||
|
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user