diff --git a/README.md b/README.md
index 2c5a75b..4b4da29 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,9 @@
Save for offline is an Android app for saving webpages for offline reading.
In you web browser select 'share' , and then 'Save For Offline'
+```
+This is an experimental beta version, and while it mostly works, it may have some problems. Please do report any bugs you find!
+```
## Screenshots
#### Grid layout for the list of all saved pages.
@@ -13,7 +16,7 @@ In you web browser select 'share' , and then 'Save For Offline'
![List layout](https://raw.githubusercontent.com/JonasCz/save-for-offline/master/screenshots/listlayout.png)
***
-#### Built in viewer. (Future versions may support opening saved files in web browser)
+#### Built in viewer. (Saved HTML files can also be opened in other apps or copied to computer)
![Viewer](https://raw.githubusercontent.com/JonasCz/save-for-offline/master/screenshots/viewer.png)
***
diff --git a/app/build.gradle b/app/build.gradle
index faf8bad..e9c3d16 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "jonas.tool.saveForOffline"
minSdkVersion 14
targetSdkVersion 19
- versionCode 10
- versionName "2.0.1 Beta"
+ versionCode 11
+ versionName "2.0.2 Beta"
}
buildTypes {
release {
@@ -21,4 +21,5 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
+
}
diff --git a/app/src/main/java/jonas/tool/saveForOffline/MainActivity.java b/app/src/main/java/jonas/tool/saveForOffline/MainActivity.java
index fe8fb1a..c0c79f1 100644
--- a/app/src/main/java/jonas/tool/saveForOffline/MainActivity.java
+++ b/app/src/main/java/jonas/tool/saveForOffline/MainActivity.java
@@ -41,7 +41,7 @@ public class MainActivity extends Activity implements SearchView.OnQueryTextList
private TextView helpText;
private int sortOrder = 0;
-
+
private GridView mainGrid;
private SearchView mSearchView;
@@ -52,7 +52,6 @@ public class MainActivity extends Activity implements SearchView.OnQueryTextList
private int scrollPosition;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -63,6 +62,7 @@ public void onCreate(Bundle savedInstanceState) {
mainGrid = (GridView) findViewById(R.id.List);
mainGrid.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+
mainGrid.setMultiChoiceModeListener(new ModeCallback());
@@ -91,13 +91,6 @@ public void onCreate(Bundle savedInstanceState) {
mainGrid.setAdapter(gridAdapter);
- }
-
- private void deleteItems() {
-
-
-
-
}
@Override
@@ -117,6 +110,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
mSearchView.setIconifiedByDefault(true);
mSearchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
+
}
@@ -195,7 +189,7 @@ public void onClick(DialogInterface dialog, int which) {
return true;
case R.id.ic_action_settings:
- Intent settings = new Intent(getApplicationContext(), Preferences.class);
+ Intent settings = new Intent(this, Preferences.class);
startActivityForResult(settings, 1);
return true;
@@ -205,6 +199,7 @@ public void onClick(DialogInterface dialog, int which) {
startActivity(intent);
return true;
+
default:
return super.onOptionsItemSelected(item);
}
@@ -271,8 +266,9 @@ private void displayData(String searchQuery) {
class ModeCallback implements ListView.MultiChoiceModeListener {
-
+ @Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_activity_multi_choice, menu);
mode.setTitle("Select Items");
@@ -281,10 +277,15 @@ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return true;
}
+
+
+ @Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ gridAdapter.selectedViewsPositions.clear();
return true;
}
+ @Override
public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
@@ -347,10 +348,10 @@ public void onClick(DialogInterface dialog, int which) {
displayData("");
pd.hide();
pd.cancel();
-
- Toast.makeText(MainActivity.this, "Deleted " + gridAdapter.selectedViewsPositions.size() + " saved pages",Toast.LENGTH_LONG).show();
-
+ Toast.makeText(MainActivity.this, "Deleted " + gridAdapter.selectedViewsPositions.size() + " saved pages", Toast.LENGTH_LONG).show();
+
+
mode.finish();
}
});
@@ -370,18 +371,20 @@ public void onClick(DialogInterface dialog,
break;
default:
-
+
break;
}
return true;
}
+ @Override
public void onDestroyActionMode(ActionMode mode) {
-
- gridAdapter.selectedViewsPositions.clear();
-
+
+ gridAdapter.selectedViewsPositions.clear();
+
}
+ @Override
public void onItemCheckedStateChanged(ActionMode mode,
int position, long itemId, boolean checked) {
Integer pos = position;
@@ -409,14 +412,16 @@ public void onItemCheckedStateChanged(ActionMode mode,
switch (checkedCount) {
case 0:
- mode.setSubtitle("Select items");
- Log.w("MainActivity / Gridview", "Should never happen: nothing selected");
+ mode.setSubtitle("Tap to select items");
+ findViewById(R.id.action_delete).setEnabled(false);
break;
case 1:
mode.setSubtitle("One item selected");
+ findViewById(R.id.action_delete).setEnabled(true);
break;
default:
- mode.setSubtitle("" + checkedCount + " items selected");
+ mode.setSubtitle(checkedCount + " items selected");
+ findViewById(R.id.action_delete).setEnabled(true);
break;
}
}
diff --git a/app/src/main/java/jonas/tool/saveForOffline/Preferences.java b/app/src/main/java/jonas/tool/saveForOffline/Preferences.java
index 678b028..f5198e1 100644
--- a/app/src/main/java/jonas/tool/saveForOffline/Preferences.java
+++ b/app/src/main/java/jonas/tool/saveForOffline/Preferences.java
@@ -47,7 +47,7 @@ public void onClick(DialogInterface dialog, int which) {
} else {
Preference advancedSavingOptions = getPreferenceScreen().findPreference("saving_advanced_opts");
advancedSavingOptions.setEnabled(true);
- advancedSavingOptions.setSummary("Choose how errors should be handled and what parts of a webpage to save (images, scripts...) ");
+ advancedSavingOptions.setSummary("Choose how errors should be handled and what parts of a webpage to save (images, scripts...). Use with care");
}
//disabled for now
}
diff --git a/app/src/main/java/jonas/tool/saveForOffline/SaveActivity.java b/app/src/main/java/jonas/tool/saveForOffline/SaveActivity.java
index e7c696f..64ae079 100644
--- a/app/src/main/java/jonas/tool/saveForOffline/SaveActivity.java
+++ b/app/src/main/java/jonas/tool/saveForOffline/SaveActivity.java
@@ -66,11 +66,10 @@ public void onCreate(Bundle savedInstanceState)
if (ua.equals("desktop")) {
webview.getSettings().setUserAgentString("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.517 Safari/537.36");
- Log.d("saveActivity", "using desktop ua");
}
if (ua.equals("ipad")) {
webview.getSettings().setUserAgentString("todo:iPad ua");
- Log.w("saveActivity", "iPad ua not implemented yet");
+
}
diff --git a/app/src/main/java/jonas/tool/saveForOffline/SaveService.java b/app/src/main/java/jonas/tool/saveForOffline/SaveService.java
index 80fa31d..576843a 100644
--- a/app/src/main/java/jonas/tool/saveForOffline/SaveService.java
+++ b/app/src/main/java/jonas/tool/saveForOffline/SaveService.java
@@ -269,18 +269,6 @@ private void grabPage(String url, String outputDirPath) throws Exception {
}
- for (String f: GrabUtility.framesToGrab) {
- lt.d(f);
- }
- for (String f: GrabUtility.cssToGrab) {
- lt.d(f);
- }
- for (String f: GrabUtility.extraCssToGrab) {
- lt.d(f);
- }
- for (String f: GrabUtility.filesToGrab) {
- lt.d(f);
- }
//download extra files, such as images / scripts
for (String urlToDownload: GrabUtility.filesToGrab) {
@@ -729,8 +717,8 @@ private void getExtraFile(String urlToDownload, File outputDir) {
}
/**
- * @author Pramod Khare & improved by Jonas Czec
- * Contains all the utility methods used in above GrabWebPage class
+ * @author Pramod Khare & improved by Jonas Czech
+ * Contains all the utility methods used in above class
*/
class GrabUtility{
// filesToGrab - maintains all the links to files which we are going to grab/download
@@ -762,7 +750,7 @@ public static String parseHtmlForLinks(String htmlToParse, String baseUrl) {
try {
fromHTMLPageUrl = new URL(baseUrl);
noBaseUrl = false;
- } catch (java.net.MalformedURLException e) {
+ } catch (MalformedURLException e) {
fromHTMLPageUrl = null;
noBaseUrl = true;
}
@@ -872,7 +860,8 @@ public static String parseHtmlForLinks(String htmlToParse, String baseUrl) {
}
if (saveVideo) {
- links = parsedHtml.select("video");
+ //video src is sometimes in a child element
+ links = parsedHtml.select("video:not([src])");
for (Element link: links.select("[src]")){
urlToGrab = link.attr("abs:src");
addLinkToList(urlToGrab);
@@ -880,6 +869,15 @@ public static String parseHtmlForLinks(String htmlToParse, String baseUrl) {
String replacedURL = urlToGrab.substring(urlToGrab.lastIndexOf("/") + 1).replaceAll("[^a-zA-Z0-9-_\\.]", "_");
link.attr("src", replacedURL);
}
+
+ links = parsedHtml.select("video[src]");
+ for (Element link: links){
+ urlToGrab = link.attr("abs:src");
+ addLinkToList(urlToGrab);
+
+ String replacedURL = urlToGrab.substring(urlToGrab.lastIndexOf("/") + 1).replaceAll("[^a-zA-Z0-9-_\\.]", "_");
+ link.attr("src", replacedURL);
+ }
}
if (makeLinksAbsolute) {
@@ -896,8 +894,6 @@ public static String parseHtmlForLinks(String htmlToParse, String baseUrl) {
public static String parseCssForLinks(String cssToParse, String baseUrl) {
-
- String importString = "@(import\\s*['\"])()([^ '\"]*)";
String patternString = "url(\\s*\\(\\s*['\"]*\\s*)(.*?)\\s*['\"]*\\s*\\)"; //I hate regexes...
Pattern pattern = Pattern.compile(patternString);
@@ -915,9 +911,11 @@ public static String parseCssForLinks(String cssToParse, String baseUrl) {
}
- addLinkToList(makeLinkRelative(matcher.group().replaceAll(patternString, "$2").trim(), baseUrl));
+ addLinkToList(makeLinkAbsolute(matcher.group().replaceAll(patternString, "$2").trim(), baseUrl));
}
+ // find css linked with @import - needs testing
+ String importString = "@(import\\s*['\"])()([^ '\"]*)";
pattern = Pattern.compile(importString);
matcher = pattern.matcher(cssToParse);
matcher.reset();
@@ -930,13 +928,14 @@ public static String parseCssForLinks(String cssToParse, String baseUrl) {
}
- extraCssToGrab.add(makeLinkRelative(matcher.group().replaceAll(patternString, "$2").trim(), baseUrl));
+ extraCssToGrab.add(makeLinkAbsolute(matcher.group().replaceAll(patternString, "$2").trim(), baseUrl));
}
return cssToParse;
}
public static void addLinkToList(String link) {
+ //no multithreading for now
synchronized (filesToGrab) {
if (!filesToGrab.contains(link)) {
filesToGrab.add(link);
@@ -944,16 +943,23 @@ public static void addLinkToList(String link) {
}
}
- public static String makeLinkRelative(String link, String baseurl) {
- //jsoup figures out the absolute url for me...
- Document d = Document.createShell(baseurl);
- d.body().appendElement("img").attr("src", link);
- return d.body().child(0).attr("abs:src");
+ public static String makeLinkAbsolute(String link, String baseurl) {
+ try {
+ URL u = new URL(new URL(baseurl), link);
+ return u.toString();
+ } catch (MalformedURLException e) {
+ lt.e("MalformedURLException while making url absolute");
+ lt.e("Link: " + link);
+ lt.e("BaseURL: " + baseurl);
+ return null;
+ }
+
}
}
class lt {
+ //log messages are sent here
public static void e (String message) {
Log.e("SaveService", message);
}
diff --git a/app/src/main/res/menu/main_activity_actions.xml b/app/src/main/res/menu/main_activity_actions.xml
index 8d5313e..9e5cdc8 100644
--- a/app/src/main/res/menu/main_activity_actions.xml
+++ b/app/src/main/res/menu/main_activity_actions.xml
@@ -13,8 +13,8 @@
+ android:title="Sort items by"
+ android:showAsAction="never"/>
- @style/ActionBarTabStyle.Theme_main_yellow
- @style/DropDownNav.Theme_main_yellow
- @style/ActionBar.Solid.Theme_main_yellow
- - @drawable/cab_background_top_theme_main_yellow
+ - @style/ActionBar.Solid.Theme_main_yellow
- @drawable/cab_background_bottom_theme_main_yellow
- @style/ActionButton.CloseMode.Theme_main_yellow
@@ -77,4 +77,4 @@
- @style/DropDownListView.Theme_main_yellow
-
\ No newline at end of file
+
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 28c3a18..2ba2fe5 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -67,7 +67,7 @@