mirror of
https://github.com/f-droid/fdroidclient.git
synced 2026-05-25 00:46:45 -04:00
[app] move archive repos to toggle of main repo
archive repos can now be enabled/disabled in the details screen of each repo
This commit is contained in:
@@ -167,6 +167,7 @@ dependencies {
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
|
||||
implementation 'androidx.palette:palette:1.0.0'
|
||||
implementation 'androidx.work:work-runtime:2.8.1'
|
||||
implementation 'com.google.guava:guava:31.0-android' // somehow needed for work-runtime to function
|
||||
|
||||
@@ -47,6 +47,8 @@ import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.index.RepoManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
|
||||
public class ManageReposActivity extends AppCompatActivity implements RepoAdapter.RepoItemListener {
|
||||
@@ -139,7 +141,7 @@ public class ManageReposActivity extends AppCompatActivity implements RepoAdapte
|
||||
touchHelper.attachToRecyclerView(repoList);
|
||||
repoList.setAdapter(repoAdapter);
|
||||
FDroidApp.getRepoManager(this).getLiveRepositories().observe(this, items -> {
|
||||
repoAdapter.updateItems(items);
|
||||
repoAdapter.updateItems(new ArrayList<>(items)); // copy list, so we don't modify original in adapter
|
||||
isItemReorderingEnabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.fdroid.index.v2.FileV2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class RepoAdapter extends RecyclerView.Adapter<RepoAdapter.RepoViewHolder> {
|
||||
|
||||
@@ -48,6 +49,11 @@ public class RepoAdapter extends RecyclerView.Adapter<RepoAdapter.RepoViewHolder
|
||||
// we could do better, but not really worth it at this point
|
||||
void updateItems(List<Repository> items) {
|
||||
this.items.clear();
|
||||
// filter out archive repos
|
||||
ListIterator<Repository> iterator = items.listIterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (iterator.next().isArchiveRepo()) iterator.remove();
|
||||
}
|
||||
this.items.addAll(items);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -29,8 +29,10 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.core.app.NavUtils;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
@@ -105,7 +107,10 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
||||
|
||||
private MirrorAdapter adapterToNotify;
|
||||
|
||||
private RepoDetailsViewModel model;
|
||||
// FIXME access to this could be moved into ViewModel
|
||||
private RepositoryDao repositoryDao;
|
||||
// FIXME access to this could be moved into ViewModel
|
||||
private AppDao appDao;
|
||||
@Nullable
|
||||
private Disposable disposable;
|
||||
@@ -128,6 +133,7 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
||||
fdroidApp.setSecureWindow(this);
|
||||
|
||||
fdroidApp.applyPureBlackBackgroundInDarkTheme(this);
|
||||
model = new ViewModelProvider(this).get(RepoDetailsViewModel.class);
|
||||
repositoryDao = DBHelper.getDb(this).getRepositoryDao();
|
||||
appDao = DBHelper.getDb(this).getAppDao();
|
||||
|
||||
@@ -142,6 +148,7 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
||||
repoView = findViewById(R.id.repo_view);
|
||||
|
||||
repoId = getIntent().getLongExtra(ARG_REPO_ID, 0);
|
||||
model.initRepo(repoId);
|
||||
repo = FDroidApp.getRepoManager(this).getRepository(repoId);
|
||||
|
||||
TextView inputUrl = findViewById(R.id.input_repo_url);
|
||||
@@ -179,6 +186,18 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
||||
qrCode.setImageBitmap(bitmap);
|
||||
}
|
||||
});
|
||||
|
||||
SwitchCompat switchCompat = findViewById(R.id.archiveRepo);
|
||||
model.getLiveData().observe(this, s -> {
|
||||
Boolean enabled = s.getArchiveEnabled();
|
||||
if (enabled == null) {
|
||||
switchCompat.setEnabled(false);
|
||||
} else {
|
||||
switchCompat.setEnabled(true);
|
||||
switchCompat.setChecked(enabled);
|
||||
}
|
||||
});
|
||||
switchCompat.setOnClickListener(v -> model.setArchiveRepoEnabled(repo, switchCompat.isChecked()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.fdroid.fdroid.views.repos
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import android.widget.Toast.LENGTH_SHORT
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import info.guardianproject.netcipher.NetCipher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.fdroid.database.Repository
|
||||
import org.fdroid.fdroid.FDroidApp
|
||||
import org.fdroid.fdroid.R
|
||||
import org.fdroid.fdroid.UpdateService
|
||||
|
||||
data class RepoDetailsState(
|
||||
val repo: Repository?,
|
||||
val archiveEnabled: Boolean? = null,
|
||||
)
|
||||
|
||||
class RepoDetailsViewModel(app: Application) : AndroidViewModel(app) {
|
||||
|
||||
private val repoManager = FDroidApp.getRepoManager(app)
|
||||
private val _state = MutableStateFlow<RepoDetailsState?>(null)
|
||||
val state = _state.asStateFlow()
|
||||
val liveData = _state.asLiveData()
|
||||
|
||||
fun initRepo(repoId: Long) {
|
||||
val repo = repoManager.getRepository(repoId)
|
||||
if (repo == null) {
|
||||
_state.value = RepoDetailsState(null)
|
||||
} else {
|
||||
_state.value = RepoDetailsState(
|
||||
repo = repo,
|
||||
archiveEnabled = repo.isArchiveEnabled(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun setArchiveRepoEnabled(repo: Repository, enabled: Boolean) {
|
||||
// archiveEnabled = null means we don't know current state, it's in progress
|
||||
_state.value = _state.value?.copy(archiveEnabled = null)
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
repoManager.setArchiveRepoEnabled(repo, enabled, NetCipher.getProxy())
|
||||
_state.value = _state.value?.copy(archiveEnabled = enabled)
|
||||
if (enabled) withContext(Dispatchers.Main) {
|
||||
val address = repo.address.replace(Regex("repo/?$"), "archive")
|
||||
UpdateService.updateRepoNow(getApplication(), address)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(this.javaClass.simpleName, "Error toggling archive repo: ", e)
|
||||
_state.value = _state.value?.copy(archiveEnabled = repo.isArchiveEnabled())
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(getApplication(), R.string.repo_archive_failed, LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Repository.isArchiveEnabled(): Boolean {
|
||||
return repoManager.getRepositories().find { r ->
|
||||
r.isArchiveRepo && r.certificate == certificate
|
||||
}?.enabled ?: false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -161,6 +161,12 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/repo_edit_credentials" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/archiveRepo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/repo_archive_toggle" />
|
||||
|
||||
<!-- Signature (or "unsigned" if none) -->
|
||||
<TextView
|
||||
android:id="@+id/label_repo_fingerprint"
|
||||
|
||||
@@ -452,6 +452,7 @@ This often occurs with apps installed via Google Play or other sources, if they
|
||||
<string name="repo_url">Address</string>
|
||||
<string name="repo_num_apps">Number of apps</string>
|
||||
<string name="repo_num_apps_button">Show apps</string>
|
||||
<string name="repo_archive_toggle">Repository Archive</string>
|
||||
<string name="repo_fingerprint">Fingerprint of the signing key (SHA-256)</string>
|
||||
<string name="repo_description">Description</string>
|
||||
<string name="repo_last_update">Last update</string>
|
||||
@@ -467,6 +468,7 @@ This often occurs with apps installed via Google Play or other sources, if they
|
||||
You need to enable it to view the apps it provides.
|
||||
</string>
|
||||
<string name="unknown">Unknown</string>
|
||||
<string name="repo_archive_failed">Archive repo currently not available</string>
|
||||
<string name="repo_confirm_delete_title">Delete Repository?</string>
|
||||
<string name="repo_confirm_delete_body">Deleting a repository means
|
||||
apps from it will no longer be available.\n\nNote: All
|
||||
|
||||
Reference in New Issue
Block a user