From 579a9382e7e9532b9810f647a5aeaa7df86e375c Mon Sep 17 00:00:00 2001 From: JonasCz Date: Sun, 15 Feb 2015 21:28:15 +0000 Subject: [PATCH] Update readme, also various fixes and improvements. --- README.md | 5 +- app/build.gradle | 5 +- .../tool/saveForOffline/MainActivity.java | 47 +++++++++------- .../tool/saveForOffline/Preferences.java | 2 +- .../tool/saveForOffline/SaveActivity.java | 3 +- .../tool/saveForOffline/SaveService.java | 56 ++++++++++--------- .../main/res/menu/main_activity_actions.xml | 4 +- .../res/values/styles_theme_main_yellow.xml | 4 +- app/src/main/res/xml/preferences.xml | 2 +- 9 files changed, 71 insertions(+), 57 deletions(-) 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 @@