diff --git a/app/build.gradle b/app/build.gradle
index 17038106f..298d93f81 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,8 +10,8 @@ android {
applicationId 'com.github.libretube'
minSdk 21
targetSdk 31
- versionCode 6
- versionName '0.2.4'
+ versionCode 7
+ versionName '0.2.5'
multiDexEnabled true
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
resValue "string", "app_name", "LibreTube"
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index 6c783c252..135a379d0 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -16,23 +16,10 @@
}
],
"attributes": [],
- "versionCode": 6,
- "versionName": "0.2.4",
+ "versionCode": 7,
+ "versionName": "0.2.5",
"outputFile": "app-x86_64-release.apk"
},
- {
- "type": "ONE_OF_MANY",
- "filters": [
- {
- "filterType": "ABI",
- "value": "arm64-v8a"
- }
- ],
- "attributes": [],
- "versionCode": 6,
- "versionName": "0.2.4",
- "outputFile": "app-arm64-v8a-release.apk"
- },
{
"type": "ONE_OF_MANY",
"filters": [
@@ -42,10 +29,23 @@
}
],
"attributes": [],
- "versionCode": 6,
- "versionName": "0.2.4",
+ "versionCode": 7,
+ "versionName": "0.2.5",
"outputFile": "app-x86-release.apk"
},
+ {
+ "type": "ONE_OF_MANY",
+ "filters": [
+ {
+ "filterType": "ABI",
+ "value": "arm64-v8a"
+ }
+ ],
+ "attributes": [],
+ "versionCode": 7,
+ "versionName": "0.2.5",
+ "outputFile": "app-arm64-v8a-release.apk"
+ },
{
"type": "ONE_OF_MANY",
"filters": [
@@ -55,8 +55,8 @@
}
],
"attributes": [],
- "versionCode": 6,
- "versionName": "0.2.4",
+ "versionCode": 7,
+ "versionName": "0.2.5",
"outputFile": "app-armeabi-v7a-release.apk"
}
],
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1fe7b6b19..31c00cbde 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
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
bottomNavigationView = findViewById(R.id.bottomNav)
diff --git a/app/src/main/java/com/github/libretube/PipedApi.kt b/app/src/main/java/com/github/libretube/PipedApi.kt
index 600cfec40..f0d2bb31c 100644
--- a/app/src/main/java/com/github/libretube/PipedApi.kt
+++ b/app/src/main/java/com/github/libretube/PipedApi.kt
@@ -52,8 +52,13 @@ interface PipedApi {
@POST("unsubscribe")
suspend fun unsubscribe(@Header("Authorization") token: String, @Body subscribe: Subscribe): Message
+ @POST("import")
+ suspend fun importSubscriptions(@Header("Authorization") token: String, @Body channels: List): Message
+
//only for fetching servers list
@GET
suspend fun getInstances(@Url url: String): List
+
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/libretube/SearchFragment.kt b/app/src/main/java/com/github/libretube/SearchFragment.kt
index 4dd09676f..5bafb6d9b 100644
--- a/app/src/main/java/com/github/libretube/SearchFragment.kt
+++ b/app/src/main/java/com/github/libretube/SearchFragment.kt
@@ -125,4 +125,8 @@ class SearchFragment : Fragment() {
requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
}
+ override fun onStop() {
+ super.onStop()
+ hideKeyboard()
+ }
}
diff --git a/app/src/main/java/com/github/libretube/Settings.kt b/app/src/main/java/com/github/libretube/Settings.kt
index 85c729898..b901d8d53 100644
--- a/app/src/main/java/com/github/libretube/Settings.kt
+++ b/app/src/main/java/com/github/libretube/Settings.kt
@@ -1,13 +1,12 @@
package com.github.libretube
import android.Manifest
-import android.content.ContentValues.TAG
+import android.content.ContentResolver
import android.content.Context
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
-import android.os.Environment
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
@@ -15,67 +14,83 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
-import androidx.preference.SwitchPreferenceCompat
import com.blankj.utilcode.util.UriUtils
-import com.github.libretube.obj.Subscribe
import retrofit2.HttpException
-import java.io.ByteArrayOutputStream
-import java.io.IOException
-import java.io.InputStream
+import java.io.*
import java.util.zip.ZipFile
+
class Settings : PreferenceFragmentCompat() {
val TAG = "Settings"
companion object {
lateinit var getContent: ActivityResultLauncher
}
-
override fun onCreate(savedInstanceState: Bundle?) {
getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
if (uri != null) {
try{
- Log.d(TAG,UriUtils.uri2File(uri).toString())
- val file = UriUtils.uri2File(uri)
- var inputStream: InputStream? = null
- if (file.extension == "zip") {
- var zipfile = ZipFile(file)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- var zipentry =
- zipfile.getEntry("Takeout/YouTube and YouTube Music/subscriptions/subscriptions.csv")
+ // Open a specific media item using ParcelFileDescriptor.
+ val resolver: ContentResolver =
+ requireActivity()
+ .contentResolver
- inputStream = zipfile.getInputStream(zipentry)
- }else if(file.extension == "csv"){
- inputStream = file.inputStream()
- }
- val baos = ByteArrayOutputStream()
-
- inputStream?.use { it.copyTo(baos) }
-
- var subscriptions = baos.toByteArray().decodeToString()
-
- var subscribedCount = 0
-
- for (text in subscriptions.lines()) {
- if (text.take(24) != "Channel Id,Channel Url,C" && text.take(24).isNotEmpty()) {
- subscribe(text.take(24))
- subscribedCount++
- Log.d(TAG, "subscribed: " + text + " total: " + subscribedCount)
+ // "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?
+ while (reader.readLine().also { line = it } != null) {
+ Log.d(TAG,reader.readLine())
}
- }
+ 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)
- Toast.makeText(
- context,
- "Subscribed to " + subscribedCount + " channels.",
- Toast.LENGTH_SHORT
- ).show()
+ var zipentry =
+ zipfile.getEntry("Takeout/YouTube and YouTube Music/subscriptions/subscriptions.csv")
+
+ inputStream = zipfile.getInputStream(zipentry)
+ }else if(file.extension == "csv"){
+ inputStream = file.inputStream()
+ }
+ val baos = ByteArrayOutputStream()
+
+ inputStream?.use { it.copyTo(baos) }
+
+ var subscriptions = baos.toByteArray().decodeToString()
+ var channels: MutableList = emptyList().toMutableList()
+ var subscribedCount = 0
+ for (text in subscriptions.lines().subList(1,subscriptions.lines().size)) {
+ 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(
context,
R.string.error,
@@ -121,7 +136,9 @@ class Settings : PreferenceFragmentCompat() {
//check StorageAccess
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
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(
this.requireActivity(), arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
@@ -218,15 +235,12 @@ class Settings : PreferenceFragmentCompat() {
}
- private fun subscribe(channel_id: String) {
+ private fun subscribe(channels: List) {
fun run() {
lifecycleScope.launchWhenCreated {
val response = try {
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
- RetrofitInstance.api.subscribe(
- sharedPref?.getString("token", "")!!,
- Subscribe(channel_id)
- )
+ RetrofitInstance.api.importSubscriptions(sharedPref?.getString("token", "")!!,channels)
} catch (e: IOException) {
Log.e(TAG, "IOException, you might not have internet connection")
return@launchWhenCreated
@@ -234,9 +248,17 @@ class Settings : PreferenceFragmentCompat() {
Log.e(TAG, "HttpException, unexpected response$e")
return@launchWhenCreated
}
+ if(response.message == "ok"){
+ Toast.makeText(
+ context,
+ R.string.importsuccess,
+ Toast.LENGTH_SHORT
+ ).show()
+ }
}
}
run()
}
}
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 00a1e6b57..131e9c696 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -23,6 +23,7 @@
Choose a region
Login/Register
Please Login or Register from the settings to show your Subscriptions!
+ Subscribed successfully!
Subscribe to some channels first!
Can\'t Download this stream!
Download is completed!
diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml
index efcb289e0..98495f0af 100644
--- a/app/src/main/res/xml/settings.xml
+++ b/app/src/main/res/xml/settings.xml
@@ -59,7 +59,7 @@
app:key="grid"
app:entries="@array/grid"
app:entryValues="@array/grid"
- app:defaultValue=""
+ app:defaultValue="@integer/grid_items"
android:icon="@drawable/ic_column"
app:useSimpleSummaryProvider="true"
/>