Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 65 additions & 51 deletions app/src/main/java/org/lsposed/manager/repo/RepoLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,7 @@ public boolean upgradable(long versionCode, String versionName) {
private final Path repoFile = Paths.get(App.getInstance().getFilesDir().getAbsolutePath(), "repo.json");
private final Set<RepoListener> listeners = ConcurrentHashMap.newKeySet();
private boolean repoLoaded = false;
private static final String originRepoUrl = "https://modules.lsposed.org/";
private static final String backupRepoUrl = "https://modules-blogcdn.lsposed.org/";

private static final String secondBackupRepoUrl = "https://modules-cloudflare.lsposed.org/";
private static String repoUrl = originRepoUrl;
private static final String repoUrl = "https://backup.modules.lsposed.org/";
private final Resources resources = App.getInstance().getResources();
private final String[] channels = resources.getStringArray(R.array.update_channel_values);

Expand All @@ -98,22 +94,28 @@ public static synchronized RepoLoader getInstance() {

synchronized public void loadRemoteData() {
repoLoaded = false;
boolean loaded = false;
try {
try (var response = App.getOkHttpClient().newCall(new Request.Builder().url(repoUrl + "modules.json").build()).execute()) {

if (response.isSuccessful()) {
ResponseBody body = response.body();
if (body != null) {
try {
String bodyString = body.string();
Files.write(repoFile, bodyString.getBytes(StandardCharsets.UTF_8));
loadLocalData(false);
} catch (Throwable t) {
Log.e(App.TAG, Log.getStackTraceString(t));
for (RepoListener listener : listeners) {
listener.onThrowable(t);
}
}
if (!response.isSuccessful()) {
throw new IOException("Unexpected response " + response.code() + " from " + response.request().url());
}
ResponseBody body = response.body();
if (body == null) {
throw new IOException("Empty response from " + response.request().url());
}
try {
String bodyString = body.string();
if (bodyString.trim().isEmpty()) {
throw new IOException("Empty response from " + response.request().url());
}
Files.write(repoFile, bodyString.getBytes(StandardCharsets.UTF_8));
loadLocalData(false);
loaded = true;
} catch (Throwable t) {
Log.e(App.TAG, Log.getStackTraceString(t));
for (RepoListener listener : listeners) {
listener.onThrowable(t);
}
}
}
Expand All @@ -122,12 +124,12 @@ synchronized public void loadRemoteData() {
for (RepoListener listener : listeners) {
listener.onThrowable(e);
}
if (repoUrl.equals(originRepoUrl)) {
repoUrl = backupRepoUrl;
loadRemoteData();
} else if (repoUrl.equals(backupRepoUrl)) {
repoUrl = secondBackupRepoUrl;
loadRemoteData();
} finally {
if (!loaded) {
repoLoaded = true;
for (RepoListener listener : listeners) {
listener.onRepoLoaded();
}
}
}
}
Expand Down Expand Up @@ -252,39 +254,51 @@ public void loadRemoteReleases(String packageName) {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.e(App.TAG, call.request().url() + e.getMessage());
if (repoUrl.equals(originRepoUrl)) {
repoUrl = backupRepoUrl;
loadRemoteReleases(packageName);
} else if (repoUrl.equals(backupRepoUrl)) {
repoUrl = secondBackupRepoUrl;
loadRemoteReleases(packageName);
} else {
for (RepoListener listener : listeners) {
listener.onThrowable(e);
}
for (RepoListener listener : listeners) {
listener.onThrowable(e);
}
}

@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
if (response.isSuccessful()) {
if (!response.isSuccessful()) {
var e = new IOException("Unexpected response " + response.code() + " from " + call.request().url());
for (RepoListener listener : listeners) {
listener.onThrowable(e);
}
response.close();
return;
}
try (response) {
ResponseBody body = response.body();
if (body != null) {
try {
String bodyString = body.string();
Gson gson = new Gson();
OnlineModule module = gson.fromJson(bodyString, OnlineModule.class);
module.releasesLoaded = true;
onlineModules.replace(packageName, module);
for (RepoListener listener : listeners) {
listener.onModuleReleasesLoaded(module);
}
} catch (Throwable t) {
Log.e(App.TAG, Log.getStackTraceString(t));
for (RepoListener listener : listeners) {
listener.onThrowable(t);
}
if (body == null) {
throw new IOException("Empty response from " + call.request().url());
}
try {
String bodyString = body.string();
if (bodyString.trim().isEmpty()) {
throw new IOException("Empty response from " + call.request().url());
}
Gson gson = new Gson();
OnlineModule module = gson.fromJson(bodyString, OnlineModule.class);
if (module == null) {
throw new IOException("Invalid response from " + call.request().url());
}
module.releasesLoaded = true;
onlineModules.replace(packageName, module);
for (RepoListener listener : listeners) {
listener.onModuleReleasesLoaded(module);
}
} catch (Throwable t) {
Log.e(App.TAG, Log.getStackTraceString(t));
for (RepoListener listener : listeners) {
listener.onThrowable(t);
}
}
} catch (Throwable t) {
Log.e(App.TAG, Log.getStackTraceString(t));
for (RepoListener listener : listeners) {
listener.onThrowable(t);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ public class RepoItemFragment extends BaseFragment implements RepoLoader.RepoLis
OnlineModule module;
private ReleaseAdapter releaseAdapter;
private InformationAdapter informationAdapter;
private boolean remoteModuleLoadRequested = false;
private boolean releaseLoadRequestedByUser = false;

@Nullable
@Override
Expand Down Expand Up @@ -147,6 +149,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
releaseAdapter = new ReleaseAdapter();
informationAdapter = new InformationAdapter();
RepoLoader.getInstance().addListener(this);
loadRemoteModuleIfReadmeMissing();
return binding.getRoot();
}

Expand Down Expand Up @@ -184,7 +187,7 @@ private void renderGithubMarkdown(WebView view, @Nullable String text) {
} else {
direction = "ltr";
}
if (text == null) {
if (TextUtils.isEmpty(text)) {
text = "<center>" + App.getInstance().getString(R.string.list_empty) + "</center>";
}
if (ResourceUtils.isNightMode(getResources().getConfiguration())) {
Expand Down Expand Up @@ -238,6 +241,43 @@ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceReque
}
}

@Nullable
private OnlineModule refreshModuleFromRepo() {
if (module == null || module.getName() == null) return module;
var updatedModule = RepoLoader.getInstance().getOnlineModule(module.getName());
if (updatedModule != null) {
module = updatedModule;
}
return module;
}

private boolean hasReadme(@Nullable OnlineModule module) {
return module != null && (!TextUtils.isEmpty(module.getReadmeHTML()) || !TextUtils.isEmpty(module.getReadme()));
}

private void loadRemoteModuleIfReadmeMissing() {
var currentModule = refreshModuleFromRepo();
if (currentModule == null || currentModule.getName() == null) return;
if (remoteModuleLoadRequested || currentModule.releasesLoaded || hasReadme(currentModule)) return;

remoteModuleLoadRequested = true;
RepoLoader.getInstance().loadRemoteReleases(currentModule.getName());
}

@Nullable
private String getModuleReadme() {
var currentModule = refreshModuleFromRepo();
if (currentModule == null) return null;
String readme = currentModule.getReadmeHTML();
if (TextUtils.isEmpty(readme)) {
readme = currentModule.getReadme();
}
if (TextUtils.isEmpty(readme)) {
loadRemoteModuleIfReadmeMissing();
}
return readme;
}

@Override
public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {

Expand All @@ -260,20 +300,36 @@ public void onDestroyView() {
binding = null;
}

@Override
public void onRepoLoaded() {
var currentModule = refreshModuleFromRepo();
if (!hasReadme(currentModule)) {
remoteModuleLoadRequested = false;
}
loadRemoteModuleIfReadmeMissing();
if (releaseAdapter != null) {
runAsync(releaseAdapter::loadItems);
}
}

@Override
public void onModuleReleasesLoaded(OnlineModule module) {
if (this.module == null || module == null || !TextUtils.equals(this.module.getName(), module.getName())) return;
this.module = module;
var repoLoader = RepoLoader.getInstance();
if (releaseAdapter != null) {
runAsync(releaseAdapter::loadItems);
}
if ((repoLoader.getReleases(module.getName()) != null ? repoLoader.getReleases(module.getName()).size() : 1) == 1) {
if (releaseLoadRequestedByUser && (repoLoader.getReleases(module.getName()) != null ? repoLoader.getReleases(module.getName()).size() : 1) == 1) {
showHint(R.string.module_release_no_more, true);
}
releaseLoadRequestedByUser = false;
}

@Override
public void onThrowable(Throwable t) {
remoteModuleLoadRequested = false;
releaseLoadRequestedByUser = false;
if (releaseAdapter != null) {
runAsync(releaseAdapter::loadItems);
}
Expand Down Expand Up @@ -456,6 +512,7 @@ public void onBindViewHolder(@NonNull ReleaseAdapter.ViewHolder holder, int posi
if (holder.progress.getVisibility() == View.GONE) {
holder.title.setVisibility(View.GONE);
holder.progress.show();
releaseLoadRequestedByUser = true;
RepoLoader.getInstance().loadRemoteReleases(module.getName());
}
Comment thread
Shallow-dusty marked this conversation as resolved.
});
Expand Down Expand Up @@ -611,9 +668,17 @@ public void onPause() {
}
}

public static class ReadmeFragment extends BorderFragment {
public static class ReadmeFragment extends BorderFragment implements RepoLoader.RepoListener {
ItemRepoReadmeBinding binding;

private void renderReadme() {
var parent = getParentFragment();
if (!(parent instanceof RepoItemFragment) || binding == null) return;

var repoItemFragment = (RepoItemFragment) parent;
repoItemFragment.renderGithubMarkdown(binding.readme, repoItemFragment.getModuleReadme());
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Expand All @@ -624,13 +689,40 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
}
return null;
}
var repoItemFragment = (RepoItemFragment) parent;
binding = ItemRepoReadmeBinding.inflate(getLayoutInflater(), container, false);
repoItemFragment.renderGithubMarkdown(binding.readme, repoItemFragment.module.getReadmeHTML());
renderReadme();
borderView = binding.scrollView;
RepoLoader.getInstance().addListener(this);
return binding.getRoot();
}

@Override
public void onRepoLoaded() {
if (binding != null) {
runOnUiThread(this::renderReadme);
}
}

@Override
public void onModuleReleasesLoaded(OnlineModule module) {
if (binding != null) {
var parent = getParentFragment();
if (parent instanceof RepoItemFragment) {
var repoItemFragment = (RepoItemFragment) parent;
if (repoItemFragment.module != null && TextUtils.equals(repoItemFragment.module.getName(), module.getName())) {
runOnUiThread(this::renderReadme);
}
}
}
}

@Override
public void onDestroyView() {
RepoLoader.getInstance().removeListener(this);
binding = null;
super.onDestroyView();
}

@Override
void scrollToTop() {
binding.scrollView.fullScroll(ScrollView.FOCUS_UP);
Expand Down