Skip to content
Merged
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
131 changes: 79 additions & 52 deletions app/src/main/java/com/httrack/android/CleanupActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
Expand All @@ -45,6 +47,7 @@
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

import com.httrack.android.jni.HTTrackLib;

Expand All @@ -59,6 +62,7 @@ public class CleanupActivity extends ListActivity {
private String[] projects;
private int action;
private final HashSet<Integer> toBeDeleted = new HashSet<Integer>();
private volatile boolean deleteInProgress;

public static final int ACTION_CLEANUP = 1;
public static final int ACTION_SELECT = 2;
Expand Down Expand Up @@ -208,66 +212,89 @@ public boolean accept(final File dir, final String filename) {
}
}

protected boolean deleteProjects() {
boolean success = true;
for (final int position : toBeDeleted) {
// Delete project.
final String name = projects[position];
final File target = new File(projectRootFile, name);
if (deleteRecursively(target)) {
// Mark item as disabled.
final View item = list.getChildAt(position);
final View o = item.findViewById(R.id.blocCheck);
o.setBackgroundResource(R.color.gray);
final CheckBox cb = (CheckBox) item.findViewById(R.id.check);
cb.setClickable(false);
cb.setEnabled(false);
} else {
success = false;
}

/**
* Delete the selected projects off the UI thread: one delete() per file over a whole mirror
* plus a native index rebuild blows past the ANR budget. The selection is snapshotted here and
* the result posted back to finish the activity; a second run while one is going is ignored.
*/
protected void deleteProjects() {
if (deleteInProgress) {
return;
}
// Everything was deleted
final HashSet<Integer> positions = new HashSet<Integer>(toBeDeleted);
toBeDeleted.clear();
deleteInProgress = true;
Toast.makeText(this, "Deleting projects…", Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
@Override
public void run() {
final HashSet<Integer> deleted = new HashSet<Integer>();
for (final int position : positions) {
if (deleteRecursively(new File(projectRootFile, projects[position]))) {
deleted.add(position);
}
}

// Root path can be deleted ?
final boolean deleteRootPath = pathIsEmpty(projectRootFile);
if (deleteRootPath) {
if (deleteRecursively(projectRootFile)) {
Log.d(getClass().getSimpleName(), "successfully deleted root path: "
+ projectRootFile);
} else {
Log.w(getClass().getSimpleName(), "could not delet root path: "
+ projectRootFile);
}

// Delete top-level parent if a "HTTrack" folder was found. This ensure
// that we fully cleanup user-data.
final File parentRoot = projectRootFile.getParentFile();
if (parentRoot != null && parentRoot.getName().equals("HTTrack")
&& pathIsEmpty(parentRoot)) {
if (deleteRecursively(parentRoot)) {
Log.d(getClass().getSimpleName(), "successfully deleted root path: "
+ parentRoot);
// Root path can be deleted ?
final boolean deleteRootPath = pathIsEmpty(projectRootFile);
if (deleteRootPath) {
if (deleteRecursively(projectRootFile)) {
Log.d(getClass().getSimpleName(), "successfully deleted root path: "
+ projectRootFile);
} else {
Log.w(getClass().getSimpleName(), "could not delet root path: "
+ projectRootFile);
}

// Delete top-level parent if a "HTTrack" folder was found. This ensure
// that we fully cleanup user-data.
final File parentRoot = projectRootFile.getParentFile();
if (parentRoot != null && parentRoot.getName().equals("HTTrack")
&& pathIsEmpty(parentRoot)) {
if (deleteRecursively(parentRoot)) {
Log.d(getClass().getSimpleName(), "successfully deleted root path: "
+ parentRoot);
} else {
Log.w(getClass().getSimpleName(), "could not delet root path: "
+ parentRoot);
}
}
} else {
Log.w(getClass().getSimpleName(), "could not delet root path: "
+ parentRoot);
// Rebuild top index
HTTrackLib.buildTopIndex(projectRootFile, resourceFile);
}
}
} else {
// Rebuild top index
HTTrackLib.buildTopIndex(projectRootFile, resourceFile);
}

// Push result
final Intent intent = new Intent();
intent.putExtra("com.httrack.android.rootPathWasDeleted", deleteRootPath);
setResult(Activity.RESULT_OK, intent);
deliverDeleteOutcome(deleted, deleteRootPath);
}
}, "cleanup-delete").start();
}

// Finish
finish();
/** Finish with the result on the main thread; touch the list only if we still own it. */
private void deliverDeleteOutcome(final HashSet<Integer> deleted,
final boolean rootPathWasDeleted) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
deleteInProgress = false;
if (!isFinishing() && !isDestroyed()) {
for (final int position : deleted) {
final View item = list.getChildAt(position);
if (item == null) {
continue;
}
item.findViewById(R.id.blocCheck).setBackgroundResource(R.color.gray);
final CheckBox cb = (CheckBox) item.findViewById(R.id.check);
cb.setClickable(false);
cb.setEnabled(false);
}
}

return success;
final Intent intent = new Intent();
intent.putExtra("com.httrack.android.rootPathWasDeleted", rootPathWasDeleted);
setResult(Activity.RESULT_OK, intent);
finish();
}
});
}

public void onClickDelete(final View v) {
Expand Down
28 changes: 26 additions & 2 deletions app/src/main/java/com/httrack/android/HTTrackActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -2267,6 +2267,7 @@ private void startLegacyMirrorImport() {

// Process-wide: a rotation recreates the activity, but the detached worker keeps copying.
private static final AtomicBoolean importInProgress = new AtomicBoolean();
private volatile boolean browseAllInProgress;

/**
* Copy the picked tree into our Websites directory, entirely off the UI thread: even walking
Expand Down Expand Up @@ -2649,8 +2650,31 @@ public void onBrowse(final View view) {
* "Browse All Websites"
*/
public void onBrowseAll(final View view) {
buildTopIndex();
browse(getProjectRootIndexFile());
if (browseAllInProgress) {
return;
}
// Regenerating the aggregate index walks every project's cache; keep it off the click handler.
final File index = getProjectRootIndexFile();
browseAllInProgress = true;
showNotification(getString(R.string.browse_all_building));
new Thread(new Runnable() {
@Override
public void run() {
try {
buildTopIndex();
} finally {
browseAllInProgress = false;
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
if (!isFinishing() && !isDestroyed()) {
browse(index);
}
}
});
}
}, "browse-all-index").start();
}

/*
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
<string name="action_import_mirrors">Import existing mirrors</string>
<string name="import_mirrors_prompt">Pick the folder that holds your older HTTrack mirrors (for example HTTrack on the internal storage). Their contents will be copied into this app\'s storage; the originals are left untouched.</string>
<string name="import_mirrors_running">Importing mirrors…</string>
<string name="browse_all_building">Building index…</string>
<string name="import_mirrors_done">Imported %1$d files (%2$d already present).</string>
<string name="import_mirrors_partial">Imported %1$d files; %2$d could not be copied. You can run the import again.</string>
<string name="import_mirrors_none">Nothing to import from that folder.</string>
Expand Down
Loading