[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:
Torsten Grote
2023-11-03 14:50:54 -03:00
parent e47ef72f75
commit 349f386d92
7 changed files with 110 additions and 1 deletions

View File

@@ -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

View File

@@ -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;
});
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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"

View File

@@ -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