Skip to content

Commit bfcc31e

Browse files
evermind-zztheimpulson
authored andcommitted
BackupRestoreSettingsFragment: add UI options to import/export subscriptions
* create SubscriptionsImportExportHelper to share common code used in SubscriptionFragment and BackupRestoreSettingsFragment * Add UI options for import/export in BackupRestoreSettingsFragment
1 parent 6fa97e1 commit bfcc31e

File tree

6 files changed

+130
-55
lines changed

6 files changed

+130
-55
lines changed

app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt

Lines changed: 4 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.schabi.newpipe.local.subscription
22

3-
import android.app.Activity
43
import android.content.Context
54
import android.content.DialogInterface
65
import android.os.Bundle
@@ -14,8 +13,6 @@ import android.view.View
1413
import android.view.ViewGroup
1514
import android.webkit.MimeTypeMap
1615
import android.widget.Toast
17-
import androidx.activity.result.ActivityResult
18-
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
1916
import androidx.annotation.StringRes
2017
import androidx.appcompat.app.AlertDialog
2118
import androidx.lifecycle.ViewModelProvider
@@ -26,9 +23,6 @@ import com.xwray.groupie.GroupAdapter
2623
import com.xwray.groupie.Section
2724
import com.xwray.groupie.viewbinding.GroupieViewHolder
2825
import io.reactivex.rxjava3.disposables.CompositeDisposable
29-
import java.text.SimpleDateFormat
30-
import java.util.Date
31-
import java.util.Locale
3226
import org.schabi.newpipe.R
3327
import org.schabi.newpipe.database.feed.model.FeedGroupEntity.Companion.GROUP_ALL_ID
3428
import org.schabi.newpipe.databinding.DialogTitleBinding
@@ -52,10 +46,6 @@ import org.schabi.newpipe.local.subscription.item.FeedGroupCarouselItem
5246
import org.schabi.newpipe.local.subscription.item.GroupsHeader
5347
import org.schabi.newpipe.local.subscription.item.Header
5448
import org.schabi.newpipe.local.subscription.item.ImportSubscriptionsHintPlaceholderItem
55-
import org.schabi.newpipe.local.subscription.workers.SubscriptionExportWorker
56-
import org.schabi.newpipe.local.subscription.workers.SubscriptionImportInput
57-
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard
58-
import org.schabi.newpipe.streams.io.StoredFileHelper
5949
import org.schabi.newpipe.util.NavigationHelper
6050
import org.schabi.newpipe.util.OnClickGesture
6151
import org.schabi.newpipe.util.ServiceHelper
@@ -68,6 +58,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
6858

6959
private lateinit var viewModel: SubscriptionViewModel
7060
private lateinit var subscriptionManager: SubscriptionManager
61+
private lateinit var importExportHelper: SubscriptionsImportExportHelper
7162
private val disposables: CompositeDisposable = CompositeDisposable()
7263

7364
private val groupAdapter = GroupAdapter<GroupieViewHolder<FeedItemCarouselBinding>>()
@@ -76,11 +67,6 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
7667
private lateinit var feedGroupsSortMenuItem: GroupsHeader
7768
private val subscriptionsSection = Section()
7869

79-
private val requestExportLauncher =
80-
registerForActivityResult(StartActivityForResult(), this::requestExportResult)
81-
private val requestImportLauncher =
82-
registerForActivityResult(StartActivityForResult(), this::requestImportResult)
83-
8470
@State
8571
@JvmField
8672
var itemsListState: Parcelable? = null
@@ -100,6 +86,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
10086
override fun onAttach(context: Context) {
10187
super.onAttach(context)
10288
subscriptionManager = SubscriptionManager(requireContext())
89+
importExportHelper = SubscriptionsImportExportHelper(this)
10390
}
10491

10592
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@@ -139,7 +126,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
139126
// -- Import --
140127
val importSubMenu = menu.addSubMenu(R.string.import_from)
141128

142-
addMenuItemToSubmenu(importSubMenu, R.string.previous_export) { onImportPreviousSelected() }
129+
addMenuItemToSubmenu(importSubMenu, R.string.previous_export) { importExportHelper.onImportPreviousSelected() }
143130
.setIcon(R.drawable.ic_backup)
144131

145132
for (service in ServiceList.all()) {
@@ -157,7 +144,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
157144
// -- Export --
158145
val exportSubMenu = menu.addSubMenu(R.string.export_to)
159146

160-
addMenuItemToSubmenu(exportSubMenu, R.string.file) { onExportSelected() }
147+
addMenuItemToSubmenu(exportSubMenu, R.string.file) { importExportHelper.onExportSelected() }
161148
.setIcon(R.drawable.ic_save)
162149
}
163150

@@ -193,48 +180,10 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
193180
NavigationHelper.openSubscriptionsImportFragment(fragmentManager, serviceId)
194181
}
195182

196-
private fun onImportPreviousSelected() {
197-
NoFileManagerSafeGuard.launchSafe(
198-
requestImportLauncher,
199-
StoredFileHelper.getPicker(activity, JSON_MIME_TYPE),
200-
TAG,
201-
requireContext()
202-
)
203-
}
204-
205-
private fun onExportSelected() {
206-
val date = SimpleDateFormat("yyyyMMddHHmm", Locale.ENGLISH).format(Date())
207-
val exportName = "newpipe_subscriptions_$date.json"
208-
209-
NoFileManagerSafeGuard.launchSafe(
210-
requestExportLauncher,
211-
StoredFileHelper.getNewPicker(activity, exportName, JSON_MIME_TYPE, null),
212-
TAG,
213-
requireContext()
214-
)
215-
}
216-
217183
private fun openReorderDialog() {
218184
FeedGroupReorderDialog().show(parentFragmentManager, null)
219185
}
220186

221-
private fun requestExportResult(result: ActivityResult) {
222-
val data = result.data?.data
223-
if (data != null && result.resultCode == Activity.RESULT_OK) {
224-
SubscriptionExportWorker.schedule(activity, data)
225-
}
226-
}
227-
228-
private fun requestImportResult(result: ActivityResult) {
229-
val data = result.data?.dataString
230-
if (data != null && result.resultCode == Activity.RESULT_OK) {
231-
ImportConfirmationDialog.show(
232-
this,
233-
SubscriptionImportInput.PreviousExportMode(data)
234-
)
235-
}
236-
}
237-
238187
// ////////////////////////////////////////////////////////////////////////
239188
// Fragment Views
240189
// ////////////////////////////////////////////////////////////////////////
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.schabi.newpipe.local.subscription
2+
3+
import android.app.Activity
4+
import android.content.Context
5+
import androidx.activity.result.ActivityResult
6+
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
7+
import androidx.fragment.app.Fragment
8+
import java.text.SimpleDateFormat
9+
import java.util.Date
10+
import java.util.Locale
11+
import org.schabi.newpipe.local.subscription.SubscriptionFragment.Companion.JSON_MIME_TYPE
12+
import org.schabi.newpipe.local.subscription.workers.SubscriptionExportWorker
13+
import org.schabi.newpipe.local.subscription.workers.SubscriptionImportInput
14+
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard
15+
import org.schabi.newpipe.streams.io.StoredFileHelper
16+
17+
/**
18+
* This class has to be created in onAttach() or onCreate().
19+
*
20+
* It contains registerForActivityResult calls and those
21+
* calls are only allowed before a fragment/activity is created.
22+
*/
23+
class SubscriptionsImportExportHelper(
24+
val fragment: Fragment
25+
) {
26+
val context: Context = fragment.requireContext()
27+
28+
companion object {
29+
val TAG: String =
30+
SubscriptionsImportExportHelper::class.java.simpleName + "@" + Integer.toHexString(
31+
hashCode()
32+
)
33+
}
34+
35+
private val requestExportLauncher =
36+
fragment.registerForActivityResult(StartActivityForResult(), this::requestExportResult)
37+
private val requestImportLauncher =
38+
fragment.registerForActivityResult(StartActivityForResult(), this::requestImportResult)
39+
40+
private fun requestExportResult(result: ActivityResult) {
41+
val data = result.data?.data
42+
if (data != null && result.resultCode == Activity.RESULT_OK) {
43+
SubscriptionExportWorker.schedule(context, data)
44+
}
45+
}
46+
47+
private fun requestImportResult(result: ActivityResult) {
48+
val data = result.data?.dataString
49+
if (data != null && result.resultCode == Activity.RESULT_OK) {
50+
ImportConfirmationDialog.show(
51+
fragment,
52+
SubscriptionImportInput.PreviousExportMode(data)
53+
)
54+
}
55+
}
56+
57+
fun onExportSelected() {
58+
val date = SimpleDateFormat("yyyyMMddHHmm", Locale.ENGLISH).format(Date())
59+
val exportName = "newpipe_subscriptions_$date.json"
60+
61+
NoFileManagerSafeGuard.launchSafe(
62+
requestExportLauncher,
63+
StoredFileHelper.getNewPicker(
64+
context,
65+
exportName,
66+
JSON_MIME_TYPE,
67+
null
68+
),
69+
TAG,
70+
context
71+
)
72+
}
73+
74+
fun onImportPreviousSelected() {
75+
NoFileManagerSafeGuard.launchSafe(
76+
requestImportLauncher,
77+
StoredFileHelper.getPicker(context, JSON_MIME_TYPE),
78+
TAG,
79+
context
80+
)
81+
}
82+
}

app/src/main/java/org/schabi/newpipe/settings/BackupRestoreSettingsFragment.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.schabi.newpipe.error.ErrorInfo;
2828
import org.schabi.newpipe.error.ErrorUtil;
2929
import org.schabi.newpipe.error.UserAction;
30+
import org.schabi.newpipe.local.subscription.SubscriptionsImportExportHelper;
3031
import org.schabi.newpipe.settings.export.BackupFileLocator;
3132
import org.schabi.newpipe.settings.export.ImportExportManager;
3233
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
@@ -57,8 +58,15 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
5758
private final ActivityResultLauncher<Intent> requestExportPathLauncher =
5859
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
5960
this::requestExportPathResult);
61+
private SubscriptionsImportExportHelper importExportHelper;
6062

6163

64+
@Override
65+
public void onAttach(@NonNull final Context context) {
66+
super.onAttach(context);
67+
importExportHelper = new SubscriptionsImportExportHelper(this);
68+
}
69+
6270
@Override
6371
public void onCreatePreferences(@Nullable final Bundle savedInstanceState,
6472
@Nullable final String rootKey) {
@@ -123,6 +131,21 @@ ZIP_MIME_TYPE, getImportExportDataUri()),
123131
alertDialog.show();
124132
return true;
125133
});
134+
135+
final Preference exportSubsPreference =
136+
requirePreference(R.string.export_subscriptions_key);
137+
exportSubsPreference.setOnPreferenceClickListener(reference -> {
138+
importExportHelper.onExportSelected();
139+
return true;
140+
});
141+
142+
final Preference importSubsPreference =
143+
requirePreference(R.string.import_subscriptions_key);
144+
importSubsPreference.setOnPreferenceClickListener(preference -> {
145+
importExportHelper.onImportPreviousSelected();
146+
return true;
147+
});
148+
126149
}
127150

128151
private void requestExportPathResult(final ActivityResult result) {

app/src/main/res/values/settings_keys.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@
413413
<string name="import_export_data_path">import_export_data_path</string>
414414
<string name="import_data">import_data</string>
415415
<string name="export_data">export_data</string>
416+
<string name="import_subscriptions_key">import_subscriptions_key</string>
417+
<string name="export_subscriptions_key">export_subscriptions_key</string>
416418

417419
<string name="clear_cookie_key">clear_cookie</string>
418420

app/src/main/res/values/strings.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,11 @@
520520
<string name="export_ongoing">Exporting…</string>
521521
<string name="import_file_title">Import file</string>
522522
<string name="previous_export">Previous export</string>
523+
<string name="import_subscriptions_title">Import subscriptions"</string>
524+
<string name="export_subscriptions_title">Export subscriptions</string>
525+
<string name="import_subscriptions_summary">Import subscriptions from a previous .json export"</string>
526+
<string name="export_subscriptions_summary">Export your subscriptions to a .json file</string>
527+
<string name="import_from_previous_export">Import from previous export</string>
523528
<string name="subscriptions_import_unsuccessful">Could not import subscriptions</string>
524529
<string name="subscriptions_export_unsuccessful">Could not export subscriptions</string>
525530
<string name="import_youtube_instructions">Import YouTube subscriptions from Google takeout:

app/src/main/res/xml/backup_restore_settings.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,18 @@
2222
android:summary="@string/reset_settings_summary"
2323
app:singleLineTitle="false"
2424
app:iconSpaceReserved="false" />
25+
26+
<Preference
27+
android:key="@string/export_subscriptions_key"
28+
android:title="@string/export_subscriptions_title"
29+
android:summary="@string/export_subscriptions_summary"
30+
app:singleLineTitle="false"
31+
app:iconSpaceReserved="false" />
32+
33+
<Preference
34+
android:key="@string/import_subscriptions_key"
35+
android:title="@string/import_subscriptions_title"
36+
android:summary="@string/import_subscriptions_summary"
37+
app:singleLineTitle="false"
38+
app:iconSpaceReserved="false" />
2539
</PreferenceScreen>

0 commit comments

Comments
 (0)