mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-11-04 01:03:00 +00:00 
			
		
		
		
	SubscriptionImportWorker: inputs as sealed class
This commit is contained in:
		@@ -11,7 +11,6 @@ import androidx.appcompat.app.AlertDialog;
 | 
			
		||||
import androidx.fragment.app.DialogFragment;
 | 
			
		||||
import androidx.fragment.app.Fragment;
 | 
			
		||||
import androidx.work.Constraints;
 | 
			
		||||
import androidx.work.Data;
 | 
			
		||||
import androidx.work.ExistingWorkPolicy;
 | 
			
		||||
import androidx.work.NetworkType;
 | 
			
		||||
import androidx.work.OneTimeWorkRequest;
 | 
			
		||||
@@ -22,31 +21,19 @@ import com.evernote.android.state.State;
 | 
			
		||||
import com.livefront.bridge.Bridge;
 | 
			
		||||
 | 
			
		||||
import org.schabi.newpipe.R;
 | 
			
		||||
import org.schabi.newpipe.local.subscription.workers.SubscriptionImportInput;
 | 
			
		||||
import org.schabi.newpipe.local.subscription.workers.SubscriptionImportWorker;
 | 
			
		||||
import org.schabi.newpipe.util.Constants;
 | 
			
		||||
 | 
			
		||||
public class ImportConfirmationDialog extends DialogFragment {
 | 
			
		||||
    @State
 | 
			
		||||
    protected int mode;
 | 
			
		||||
    @State
 | 
			
		||||
    protected String value;
 | 
			
		||||
    @State
 | 
			
		||||
    protected int serviceId;
 | 
			
		||||
    protected SubscriptionImportInput input;
 | 
			
		||||
 | 
			
		||||
    public static void show(@NonNull final Fragment fragment, final int mode,
 | 
			
		||||
                            @Nullable final String value, final int serviceId) {
 | 
			
		||||
    public static void show(@NonNull final Fragment fragment, final SubscriptionImportInput input) {
 | 
			
		||||
        final var confirmationDialog = new ImportConfirmationDialog();
 | 
			
		||||
        confirmationDialog.setData(mode, value, serviceId);
 | 
			
		||||
        confirmationDialog.input = input;
 | 
			
		||||
        confirmationDialog.show(fragment.getParentFragmentManager(), null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("HiddenField")
 | 
			
		||||
    public void setData(final int mode, final String value, final int serviceId) {
 | 
			
		||||
        this.mode = mode;
 | 
			
		||||
        this.value = value;
 | 
			
		||||
        this.serviceId = serviceId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @NonNull
 | 
			
		||||
    @Override
 | 
			
		||||
    public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
 | 
			
		||||
@@ -57,17 +44,12 @@ public class ImportConfirmationDialog extends DialogFragment {
 | 
			
		||||
                .setCancelable(true)
 | 
			
		||||
                .setNegativeButton(R.string.cancel, null)
 | 
			
		||||
                .setPositiveButton(R.string.ok, (dialogInterface, i) -> {
 | 
			
		||||
                    final var inputData = new Data.Builder()
 | 
			
		||||
                            .putString(SubscriptionImportWorker.KEY_VALUE, value)
 | 
			
		||||
                            .putInt(SubscriptionImportWorker.KEY_MODE, mode)
 | 
			
		||||
                            .putInt(Constants.KEY_SERVICE_ID, serviceId)
 | 
			
		||||
                            .build();
 | 
			
		||||
                    final var constraints = new Constraints.Builder()
 | 
			
		||||
                            .setRequiredNetworkType(NetworkType.CONNECTED)
 | 
			
		||||
                            .build();
 | 
			
		||||
 | 
			
		||||
                    final var req = new OneTimeWorkRequest.Builder(SubscriptionImportWorker.class)
 | 
			
		||||
                            .setInputData(inputData)
 | 
			
		||||
                            .setInputData(input.toData())
 | 
			
		||||
                            .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
 | 
			
		||||
                            .setConstraints(constraints)
 | 
			
		||||
                            .build();
 | 
			
		||||
@@ -85,10 +67,6 @@ public class ImportConfirmationDialog extends DialogFragment {
 | 
			
		||||
    public void onCreate(@Nullable final Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
        if (mode == 0 && value == null && serviceId == 0) {
 | 
			
		||||
            throw new IllegalStateException("Input data not provided");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Bridge.restoreInstanceState(this, savedInstanceState);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -49,11 +49,10 @@ import org.schabi.newpipe.local.subscription.item.GroupsHeader
 | 
			
		||||
import org.schabi.newpipe.local.subscription.item.Header
 | 
			
		||||
import org.schabi.newpipe.local.subscription.item.ImportSubscriptionsHintPlaceholderItem
 | 
			
		||||
import org.schabi.newpipe.local.subscription.workers.SubscriptionExportWorker
 | 
			
		||||
import org.schabi.newpipe.local.subscription.workers.SubscriptionImportWorker
 | 
			
		||||
import org.schabi.newpipe.local.subscription.workers.SubscriptionImportInput
 | 
			
		||||
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard
 | 
			
		||||
import org.schabi.newpipe.streams.io.StoredFileHelper
 | 
			
		||||
import org.schabi.newpipe.ui.emptystate.setEmptyStateComposable
 | 
			
		||||
import org.schabi.newpipe.util.NO_SERVICE_ID
 | 
			
		||||
import org.schabi.newpipe.util.NavigationHelper
 | 
			
		||||
import org.schabi.newpipe.util.OnClickGesture
 | 
			
		||||
import org.schabi.newpipe.util.ServiceHelper
 | 
			
		||||
@@ -231,7 +230,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
 | 
			
		||||
        val data = result.data?.dataString
 | 
			
		||||
        if (data != null && result.resultCode == Activity.RESULT_OK) {
 | 
			
		||||
            ImportConfirmationDialog.show(
 | 
			
		||||
                this, SubscriptionImportWorker.PREVIOUS_EXPORT_MODE, data, NO_SERVICE_ID
 | 
			
		||||
                this, SubscriptionImportInput.PreviousExportMode(data)
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ import org.schabi.newpipe.error.UserAction;
 | 
			
		||||
import org.schabi.newpipe.extractor.NewPipe;
 | 
			
		||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
 | 
			
		||||
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
 | 
			
		||||
import org.schabi.newpipe.local.subscription.workers.SubscriptionImportWorker;
 | 
			
		||||
import org.schabi.newpipe.local.subscription.workers.SubscriptionImportInput;
 | 
			
		||||
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
 | 
			
		||||
import org.schabi.newpipe.streams.io.StoredFileHelper;
 | 
			
		||||
import org.schabi.newpipe.util.Constants;
 | 
			
		||||
@@ -164,8 +164,8 @@ public class SubscriptionsImportFragment extends BaseFragment {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void onImportUrl(final String value) {
 | 
			
		||||
        ImportConfirmationDialog.show(this, SubscriptionImportWorker.CHANNEL_URL_MODE, value,
 | 
			
		||||
                currentServiceId);
 | 
			
		||||
        ImportConfirmationDialog.show(this,
 | 
			
		||||
                new SubscriptionImportInput.ChannelUrlMode(currentServiceId, value));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void onImportFile() {
 | 
			
		||||
@@ -182,8 +182,8 @@ public class SubscriptionsImportFragment extends BaseFragment {
 | 
			
		||||
    private void requestImportFileResult(final ActivityResult result) {
 | 
			
		||||
        final String data = result.getData() != null ? result.getData().getDataString() : null;
 | 
			
		||||
        if (result.getResultCode() == Activity.RESULT_OK && data != null) {
 | 
			
		||||
            ImportConfirmationDialog.show(this, SubscriptionImportWorker.INPUT_STREAM_MODE,
 | 
			
		||||
                    data, currentServiceId);
 | 
			
		||||
            ImportConfirmationDialog.show(this,
 | 
			
		||||
                    new SubscriptionImportInput.InputStreamMode(currentServiceId, data));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,11 +3,13 @@ package org.schabi.newpipe.local.subscription.workers
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.pm.ServiceInfo
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.os.Parcelable
 | 
			
		||||
import android.webkit.MimeTypeMap
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import androidx.work.CoroutineWorker
 | 
			
		||||
import androidx.work.Data
 | 
			
		||||
import androidx.work.ForegroundInfo
 | 
			
		||||
import androidx.work.WorkManager
 | 
			
		||||
import androidx.work.WorkerParameters
 | 
			
		||||
@@ -18,12 +20,11 @@ import kotlinx.coroutines.rx3.await
 | 
			
		||||
import kotlinx.coroutines.sync.Mutex
 | 
			
		||||
import kotlinx.coroutines.sync.withLock
 | 
			
		||||
import kotlinx.coroutines.withContext
 | 
			
		||||
import kotlinx.parcelize.Parcelize
 | 
			
		||||
import org.schabi.newpipe.R
 | 
			
		||||
import org.schabi.newpipe.extractor.NewPipe
 | 
			
		||||
import org.schabi.newpipe.local.subscription.SubscriptionManager
 | 
			
		||||
import org.schabi.newpipe.util.ExtractorHelper
 | 
			
		||||
import org.schabi.newpipe.util.KEY_SERVICE_ID
 | 
			
		||||
import org.schabi.newpipe.util.NO_SERVICE_ID
 | 
			
		||||
 | 
			
		||||
class SubscriptionImportWorker(
 | 
			
		||||
    appContext: Context,
 | 
			
		||||
@@ -35,28 +36,30 @@ class SubscriptionImportWorker(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun doWork(): Result {
 | 
			
		||||
        val mode = inputData.getInt(KEY_MODE, CHANNEL_URL_MODE)
 | 
			
		||||
        val serviceId = inputData.getInt(KEY_SERVICE_ID, NO_SERVICE_ID)
 | 
			
		||||
        val value = inputData.getString(KEY_VALUE)!!
 | 
			
		||||
        val input = SubscriptionImportInput.fromData(inputData)
 | 
			
		||||
 | 
			
		||||
        val subscriptions = withContext(Dispatchers.IO) {
 | 
			
		||||
            if (mode == CHANNEL_URL_MODE) {
 | 
			
		||||
                NewPipe.getService(serviceId).subscriptionExtractor
 | 
			
		||||
                    .fromChannelUrl(value)
 | 
			
		||||
            when (input) {
 | 
			
		||||
                is SubscriptionImportInput.ChannelUrlMode ->
 | 
			
		||||
                    NewPipe.getService(input.serviceId).subscriptionExtractor
 | 
			
		||||
                        .fromChannelUrl(input.url)
 | 
			
		||||
                        .map { SubscriptionItem(it.serviceId, it.url, it.name) }
 | 
			
		||||
            } else {
 | 
			
		||||
                applicationContext.contentResolver.openInputStream(value.toUri())?.use {
 | 
			
		||||
                    if (mode == INPUT_STREAM_MODE) {
 | 
			
		||||
                        val contentType = MimeTypeMap.getFileExtensionFromUrl(value).ifEmpty { DEFAULT_MIME }
 | 
			
		||||
                        NewPipe.getService(serviceId).subscriptionExtractor
 | 
			
		||||
 | 
			
		||||
                is SubscriptionImportInput.InputStreamMode ->
 | 
			
		||||
                    applicationContext.contentResolver.openInputStream(input.url.toUri())?.use {
 | 
			
		||||
                        val contentType =
 | 
			
		||||
                            MimeTypeMap.getFileExtensionFromUrl(input.url).ifEmpty { DEFAULT_MIME }
 | 
			
		||||
                        NewPipe.getService(input.serviceId).subscriptionExtractor
 | 
			
		||||
                            .fromInputStream(it, contentType)
 | 
			
		||||
                            .map { SubscriptionItem(it.serviceId, it.url, it.name) }
 | 
			
		||||
                    } else {
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                is SubscriptionImportInput.PreviousExportMode ->
 | 
			
		||||
                    applicationContext.contentResolver.openInputStream(input.url.toUri())?.use {
 | 
			
		||||
                        ImportExportJsonHelper.readFrom(it)
 | 
			
		||||
                    }
 | 
			
		||||
            } ?: emptyList()
 | 
			
		||||
        }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val mutex = Mutex()
 | 
			
		||||
        var index = 1
 | 
			
		||||
@@ -146,10 +149,69 @@ class SubscriptionImportWorker(
 | 
			
		||||
        private const val BUFFER_COUNT_BEFORE_INSERT = 50
 | 
			
		||||
 | 
			
		||||
        const val WORK_NAME = "SubscriptionImportWorker"
 | 
			
		||||
        const val CHANNEL_URL_MODE = 0
 | 
			
		||||
        const val INPUT_STREAM_MODE = 1
 | 
			
		||||
        const val PREVIOUS_EXPORT_MODE = 2
 | 
			
		||||
        const val KEY_MODE = "key_mode"
 | 
			
		||||
        const val KEY_VALUE = "key_value"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sealed class SubscriptionImportInput : Parcelable {
 | 
			
		||||
    @Parcelize
 | 
			
		||||
    data class ChannelUrlMode(val serviceId: Int, val url: String) : SubscriptionImportInput()
 | 
			
		||||
    @Parcelize
 | 
			
		||||
    data class InputStreamMode(val serviceId: Int, val url: String) : SubscriptionImportInput()
 | 
			
		||||
    @Parcelize
 | 
			
		||||
    data class PreviousExportMode(val url: String) : SubscriptionImportInput()
 | 
			
		||||
 | 
			
		||||
    fun toData(): Data {
 | 
			
		||||
        return when (this) {
 | 
			
		||||
            is ChannelUrlMode -> Data.Builder()
 | 
			
		||||
                .putInt("mode", CHANNEL_URL_MODE)
 | 
			
		||||
                .putInt("service_id", serviceId)
 | 
			
		||||
                .putString("url", url)
 | 
			
		||||
                .build()
 | 
			
		||||
            is InputStreamMode ->
 | 
			
		||||
                Data.Builder()
 | 
			
		||||
                    .putInt("mode", INPUT_STREAM_MODE)
 | 
			
		||||
                    .putInt("service_id", serviceId)
 | 
			
		||||
                    .putString("url", url)
 | 
			
		||||
                    .build()
 | 
			
		||||
            is PreviousExportMode ->
 | 
			
		||||
                Data.Builder()
 | 
			
		||||
                    .putInt("mode", PREVIOUS_EXPORT_MODE)
 | 
			
		||||
                    .putString("url", url)
 | 
			
		||||
                    .build()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
 | 
			
		||||
        private const val CHANNEL_URL_MODE = 0
 | 
			
		||||
        private const val INPUT_STREAM_MODE = 1
 | 
			
		||||
        private const val PREVIOUS_EXPORT_MODE = 2
 | 
			
		||||
 | 
			
		||||
        fun fromData(data: Data): SubscriptionImportInput {
 | 
			
		||||
            val mode = data.getInt("mode", PREVIOUS_EXPORT_MODE)
 | 
			
		||||
            when (mode) {
 | 
			
		||||
                CHANNEL_URL_MODE -> {
 | 
			
		||||
                    val serviceId = data.getInt("service_id", -1)
 | 
			
		||||
                    if (serviceId == -1) {
 | 
			
		||||
                        throw IllegalArgumentException("No service id provided")
 | 
			
		||||
                    }
 | 
			
		||||
                    val url = data.getString("url")!!
 | 
			
		||||
                    return ChannelUrlMode(serviceId, url)
 | 
			
		||||
                }
 | 
			
		||||
                INPUT_STREAM_MODE -> {
 | 
			
		||||
                    val serviceId = data.getInt("service_id", -1)
 | 
			
		||||
                    if (serviceId == -1) {
 | 
			
		||||
                        throw IllegalArgumentException("No service id provided")
 | 
			
		||||
                    }
 | 
			
		||||
                    val url = data.getString("url")!!
 | 
			
		||||
                    return InputStreamMode(serviceId, url)
 | 
			
		||||
                }
 | 
			
		||||
                PREVIOUS_EXPORT_MODE -> {
 | 
			
		||||
                    val url = data.getString("url")!!
 | 
			
		||||
                    return PreviousExportMode(url)
 | 
			
		||||
                }
 | 
			
		||||
                else -> throw IllegalArgumentException("Unknown mode: $mode")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user