Skip to content

Commit 579a938

Browse files
committed
Update readme, also various fixes and improvements.
1 parent 785bffb commit 579a938

File tree

9 files changed

+71
-57
lines changed

9 files changed

+71
-57
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
Save for offline is an Android app for saving webpages for offline reading.
44

55
In you web browser select 'share' , and then 'Save For Offline'
6+
```
7+
This is an experimental beta version, and while it mostly works, it may have some problems. Please do report any bugs you find!
8+
```
69

710
## Screenshots
811
#### Grid layout for the list of all saved pages.
@@ -13,7 +16,7 @@ In you web browser select 'share' , and then 'Save For Offline'
1316
![List layout](https://raw.githubusercontent.com/JonasCz/save-for-offline/master/screenshots/listlayout.png)
1417
***
1518

16-
#### Built in viewer. (Future versions may support opening saved files in web browser)
19+
#### Built in viewer. (Saved HTML files can also be opened in other apps or copied to computer)
1720
![Viewer](https://raw.githubusercontent.com/JonasCz/save-for-offline/master/screenshots/viewer.png)
1821
***
1922

app/build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ android {
88
applicationId "jonas.tool.saveForOffline"
99
minSdkVersion 14
1010
targetSdkVersion 19
11-
versionCode 10
12-
versionName "2.0.1 Beta"
11+
versionCode 11
12+
versionName "2.0.2 Beta"
1313
}
1414
buildTypes {
1515
release {
@@ -21,4 +21,5 @@ android {
2121

2222
dependencies {
2323
compile fileTree(dir: 'libs', include: ['*.jar'])
24+
2425
}

app/src/main/java/jonas/tool/saveForOffline/MainActivity.java

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class MainActivity extends Activity implements SearchView.OnQueryTextList
4141
private TextView helpText;
4242

4343
private int sortOrder = 0;
44-
44+
4545

4646
private GridView mainGrid;
4747
private SearchView mSearchView;
@@ -52,7 +52,6 @@ public class MainActivity extends Activity implements SearchView.OnQueryTextList
5252

5353
private int scrollPosition;
5454

55-
5655
@Override
5756
public void onCreate(Bundle savedInstanceState) {
5857
super.onCreate(savedInstanceState);
@@ -63,6 +62,7 @@ public void onCreate(Bundle savedInstanceState) {
6362
mainGrid = (GridView) findViewById(R.id.List);
6463

6564
mainGrid.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
65+
6666
mainGrid.setMultiChoiceModeListener(new ModeCallback());
6767

6868

@@ -91,13 +91,6 @@ public void onCreate(Bundle savedInstanceState) {
9191
mainGrid.setAdapter(gridAdapter);
9292

9393

94-
}
95-
96-
private void deleteItems() {
97-
98-
99-
100-
10194
}
10295

10396
@Override
@@ -117,6 +110,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
117110
mSearchView.setIconifiedByDefault(true);
118111
mSearchView.setOnQueryTextListener(this);
119112
return super.onCreateOptionsMenu(menu);
113+
120114
}
121115

122116

@@ -195,7 +189,7 @@ public void onClick(DialogInterface dialog, int which) {
195189
return true;
196190

197191
case R.id.ic_action_settings:
198-
Intent settings = new Intent(getApplicationContext(), Preferences.class);
192+
Intent settings = new Intent(this, Preferences.class);
199193
startActivityForResult(settings, 1);
200194

201195
return true;
@@ -205,6 +199,7 @@ public void onClick(DialogInterface dialog, int which) {
205199
startActivity(intent);
206200
return true;
207201

202+
208203
default:
209204
return super.onOptionsItemSelected(item);
210205
}
@@ -271,8 +266,9 @@ private void displayData(String searchQuery) {
271266

272267
class ModeCallback implements ListView.MultiChoiceModeListener {
273268

274-
269+
@Override
275270
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
271+
276272
MenuInflater inflater = getMenuInflater();
277273
inflater.inflate(R.menu.main_activity_multi_choice, menu);
278274
mode.setTitle("Select Items");
@@ -281,10 +277,15 @@ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
281277
return true;
282278
}
283279

280+
281+
282+
@Override
284283
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
284+
gridAdapter.selectedViewsPositions.clear();
285285
return true;
286286
}
287287

288+
@Override
288289
public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
289290

290291
switch (item.getItemId()) {
@@ -347,10 +348,10 @@ public void onClick(DialogInterface dialog, int which) {
347348
displayData("");
348349
pd.hide();
349350
pd.cancel();
350-
351-
Toast.makeText(MainActivity.this, "Deleted " + gridAdapter.selectedViewsPositions.size() + " saved pages",Toast.LENGTH_LONG).show();
352351

353-
352+
Toast.makeText(MainActivity.this, "Deleted " + gridAdapter.selectedViewsPositions.size() + " saved pages", Toast.LENGTH_LONG).show();
353+
354+
354355
mode.finish();
355356
}
356357
});
@@ -370,18 +371,20 @@ public void onClick(DialogInterface dialog,
370371

371372
break;
372373
default:
373-
374+
374375
break;
375376
}
376377
return true;
377378
}
378379

380+
@Override
379381
public void onDestroyActionMode(ActionMode mode) {
380-
381-
gridAdapter.selectedViewsPositions.clear();
382-
382+
383+
gridAdapter.selectedViewsPositions.clear();
384+
383385
}
384386

387+
@Override
385388
public void onItemCheckedStateChanged(ActionMode mode,
386389
int position, long itemId, boolean checked) {
387390
Integer pos = position;
@@ -409,14 +412,16 @@ public void onItemCheckedStateChanged(ActionMode mode,
409412

410413
switch (checkedCount) {
411414
case 0:
412-
mode.setSubtitle("Select items");
413-
Log.w("MainActivity / Gridview", "Should never happen: nothing selected");
415+
mode.setSubtitle("Tap to select items");
416+
findViewById(R.id.action_delete).setEnabled(false);
414417
break;
415418
case 1:
416419
mode.setSubtitle("One item selected");
420+
findViewById(R.id.action_delete).setEnabled(true);
417421
break;
418422
default:
419-
mode.setSubtitle("" + checkedCount + " items selected");
423+
mode.setSubtitle(checkedCount + " items selected");
424+
findViewById(R.id.action_delete).setEnabled(true);
420425
break;
421426
}
422427
}

app/src/main/java/jonas/tool/saveForOffline/Preferences.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void onClick(DialogInterface dialog, int which) {
4747
} else {
4848
Preference advancedSavingOptions = getPreferenceScreen().findPreference("saving_advanced_opts");
4949
advancedSavingOptions.setEnabled(true);
50-
advancedSavingOptions.setSummary("Choose how errors should be handled and what parts of a webpage to save (images, scripts...) ");
50+
advancedSavingOptions.setSummary("Choose how errors should be handled and what parts of a webpage to save (images, scripts...). Use with care");
5151
}
5252
//disabled for now
5353
}

app/src/main/java/jonas/tool/saveForOffline/SaveActivity.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,10 @@ public void onCreate(Bundle savedInstanceState)
6666

6767
if (ua.equals("desktop")) {
6868
webview.getSettings().setUserAgentString("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.517 Safari/537.36");
69-
Log.d("saveActivity", "using desktop ua");
7069
}
7170
if (ua.equals("ipad")) {
7271
webview.getSettings().setUserAgentString("todo:iPad ua");
73-
Log.w("saveActivity", "iPad ua not implemented yet");
72+
7473
}
7574

7675

app/src/main/java/jonas/tool/saveForOffline/SaveService.java

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -269,18 +269,6 @@ private void grabPage(String url, String outputDirPath) throws Exception {
269269

270270
}
271271

272-
for (String f: GrabUtility.framesToGrab) {
273-
lt.d(f);
274-
}
275-
for (String f: GrabUtility.cssToGrab) {
276-
lt.d(f);
277-
}
278-
for (String f: GrabUtility.extraCssToGrab) {
279-
lt.d(f);
280-
}
281-
for (String f: GrabUtility.filesToGrab) {
282-
lt.d(f);
283-
}
284272
//download extra files, such as images / scripts
285273
for (String urlToDownload: GrabUtility.filesToGrab) {
286274

@@ -729,8 +717,8 @@ private void getExtraFile(String urlToDownload, File outputDir) {
729717
}
730718

731719
/**
732-
* @author Pramod Khare & improved by Jonas Czec
733-
* Contains all the utility methods used in above GrabWebPage class
720+
* @author Pramod Khare & improved by Jonas Czech
721+
* Contains all the utility methods used in above class
734722
*/
735723
class GrabUtility{
736724
// 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) {
762750
try {
763751
fromHTMLPageUrl = new URL(baseUrl);
764752
noBaseUrl = false;
765-
} catch (java.net.MalformedURLException e) {
753+
} catch (MalformedURLException e) {
766754
fromHTMLPageUrl = null;
767755
noBaseUrl = true;
768756
}
@@ -872,14 +860,24 @@ public static String parseHtmlForLinks(String htmlToParse, String baseUrl) {
872860
}
873861

874862
if (saveVideo) {
875-
links = parsedHtml.select("video");
863+
//video src is sometimes in a child element
864+
links = parsedHtml.select("video:not([src])");
876865
for (Element link: links.select("[src]")){
877866
urlToGrab = link.attr("abs:src");
878867
addLinkToList(urlToGrab);
879868

880869
String replacedURL = urlToGrab.substring(urlToGrab.lastIndexOf("/") + 1).replaceAll("[^a-zA-Z0-9-_\\.]", "_");
881870
link.attr("src", replacedURL);
882871
}
872+
873+
links = parsedHtml.select("video[src]");
874+
for (Element link: links){
875+
urlToGrab = link.attr("abs:src");
876+
addLinkToList(urlToGrab);
877+
878+
String replacedURL = urlToGrab.substring(urlToGrab.lastIndexOf("/") + 1).replaceAll("[^a-zA-Z0-9-_\\.]", "_");
879+
link.attr("src", replacedURL);
880+
}
883881
}
884882

885883
if (makeLinksAbsolute) {
@@ -896,8 +894,6 @@ public static String parseHtmlForLinks(String htmlToParse, String baseUrl) {
896894

897895
public static String parseCssForLinks(String cssToParse, String baseUrl) {
898896

899-
900-
String importString = "@(import\\s*['\"])()([^ '\"]*)";
901897
String patternString = "url(\\s*\\(\\s*['\"]*\\s*)(.*?)\\s*['\"]*\\s*\\)"; //I hate regexes...
902898

903899
Pattern pattern = Pattern.compile(patternString);
@@ -915,9 +911,11 @@ public static String parseCssForLinks(String cssToParse, String baseUrl) {
915911

916912
}
917913

918-
addLinkToList(makeLinkRelative(matcher.group().replaceAll(patternString, "$2").trim(), baseUrl));
914+
addLinkToList(makeLinkAbsolute(matcher.group().replaceAll(patternString, "$2").trim(), baseUrl));
919915
}
920916

917+
// find css linked with @import - needs testing
918+
String importString = "@(import\\s*['\"])()([^ '\"]*)";
921919
pattern = Pattern.compile(importString);
922920
matcher = pattern.matcher(cssToParse);
923921
matcher.reset();
@@ -930,30 +928,38 @@ public static String parseCssForLinks(String cssToParse, String baseUrl) {
930928

931929
}
932930

933-
extraCssToGrab.add(makeLinkRelative(matcher.group().replaceAll(patternString, "$2").trim(), baseUrl));
931+
extraCssToGrab.add(makeLinkAbsolute(matcher.group().replaceAll(patternString, "$2").trim(), baseUrl));
934932
}
935933

936934
return cssToParse;
937935
}
938936

939937
public static void addLinkToList(String link) {
938+
//no multithreading for now
940939
synchronized (filesToGrab) {
941940
if (!filesToGrab.contains(link)) {
942941
filesToGrab.add(link);
943942
}
944943
}
945944
}
946945

947-
public static String makeLinkRelative(String link, String baseurl) {
948-
//jsoup figures out the absolute url for me...
949-
Document d = Document.createShell(baseurl);
950-
d.body().appendElement("img").attr("src", link);
951-
return d.body().child(0).attr("abs:src");
946+
public static String makeLinkAbsolute(String link, String baseurl) {
952947

948+
try {
949+
URL u = new URL(new URL(baseurl), link);
950+
return u.toString();
951+
} catch (MalformedURLException e) {
952+
lt.e("MalformedURLException while making url absolute");
953+
lt.e("Link: " + link);
954+
lt.e("BaseURL: " + baseurl);
955+
return null;
956+
}
957+
953958
}
954959
}
955960

956961
class lt {
962+
//log messages are sent here
957963
public static void e (String message) {
958964
Log.e("SaveService", message);
959965
}

app/src/main/res/menu/main_activity_actions.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
<item android:id="@+id/action_sort_by"
1515
android:icon="@drawable/ic_action_sort"
16-
android:title="Sort by"
17-
android:showAsAction="ifRoom"/>
16+
android:title="Sort items by"
17+
android:showAsAction="never"/>
1818

1919
<item android:id="@+id/ic_action_settings"
2020
android:title="Settings"

app/src/main/res/values/styles_theme_main_yellow.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<item name="android:actionBarTabStyle">@style/ActionBarTabStyle.Theme_main_yellow</item>
2727
<item name="android:actionDropDownStyle">@style/DropDownNav.Theme_main_yellow</item>
2828
<item name="android:actionBarStyle">@style/ActionBar.Solid.Theme_main_yellow</item>
29-
<item name="android:actionModeBackground">@drawable/cab_background_top_theme_main_yellow</item>
29+
<item name="android:actionModeStyle">@style/ActionBar.Solid.Theme_main_yellow</item>
3030
<item name="android:actionModeSplitBackground">@drawable/cab_background_bottom_theme_main_yellow</item>
3131
<item name="android:actionModeCloseButtonStyle">@style/ActionButton.CloseMode.Theme_main_yellow</item>
3232

@@ -77,4 +77,4 @@
7777
<item name="android:dropDownListViewStyle">@style/DropDownListView.Theme_main_yellow</item>
7878
</style>
7979

80-
</resources>
80+
</resources>

app/src/main/res/xml/preferences.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<PreferenceScreen
6868
xmlns:android="http://schemas.android.com/apk/res/android"
6969
android:title="Advanced options for saving"
70-
android:summary="DONT play with these unless you are doing! Changimg these options may result in the app not working as expected"
70+
android:summary="Choose how errors should be handled and what parts of a webpage to save (images, scripts...). Use with care"
7171
android:key="saving_advanced_opts">
7272
<PreferenceCategory
7373
android:title="Saving options">

0 commit comments

Comments
 (0)