First submission of all source files related to the project

This commit is contained in:
Tejaswi 2012-08-18 14:27:49 +05:30
parent 31bee2f180
commit 81bf3d6fe1
627 changed files with 23504 additions and 0 deletions

7
ComicReader/.classpath Executable file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

33
ComicReader/.project Executable file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ComicReader</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

39
ComicReader/AndroidManifest.xml Executable file
View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.blogspot.applications4android.comicreader"
android:versionCode="23"
android:versionName="2.0.42" >
<uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".ActivityComicReader" android:label="@string/app_name" android:configChanges="orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ActivityComicSelector" android:label="@string/select_comics_label" android:configChanges="orientation" />
<activity android:name=".ActivitySettingsPage" android:label="@string/settings_label" android:configChanges="orientation" />
<activity android:name=".ComicStripViewer" android:configChanges="orientation" />
<activity android:name=".ActivitySaveStrip" android:configChanges="orientation" />
<activity android:name=".ActivityPageViewer" android:configChanges="orientation" />
<receiver android:name=".BackgroundCacheReciever" />
<receiver android:name=".SyncNowReciever" />
<receiver android:name=".BackgroundCacheBootReciever">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name=".BackgroundCacheIntentService" />
</application>
</manifest>

148
ComicReader/assets/About.html Executable file
View File

@ -0,0 +1,148 @@
<html>
<body bgcolor=#ffff00>
<img src='file:///android_asset/a4a.png' align=right />
<h1>About:</h1>
<p>An all-in-one web-comic reader for android phones. Tested for Android 2.1 and above.</p>
<h1>Version:</h1>
<p>2.0.42</p>
<h1>Author:</h1>
<p>applications4android</p>
<h1>Contact:</h1>
applications4android@gmail.com
<h1>Release Notes:</h1>
<h2>Version 2.0.40</h2>
<li>Fixes for Date not showing in some comcics.</li>
<li>Fix for comic list disappearing</li>
<li>Fix date in Last Synced message</li>
<li>Fixes for Tundra, Bugcomic, Wondermark, FlashGordon and Hazel.</li>
<li>Added Channelate, ExtraOrdinary, Beardo and IrregularWebComic</li>
<h2>Version 2.0.34</h2>
<li>Fix for another FC issue</li>
<li>Fix for Save Strip issue</li>
<li>Fix for A softer world comics not opening</li>
<h2>Version 2.0.29</h2>
<li>Fixed an FC issue with the previous release</li>
<h2>Version 2.0.28</h2>
<li>Fixed a FC issue with the previous release</li>
<li>Fixed a couple of bugs in save-strip and zoom features</li>
<li>Fixed a bug while sharing strip over in facebook</li>
<li>Fix for the background-sync issue</li>
<h2>Version 2.0.20</h2>
<li>Fixed a bug in background caching</li>
<li>Updated the main UI</li>
<h2>Version 2.0.17</h2>
<li>Fixed a bug in background caching</li>
<li>Fixed a bug while saving/restoring default zoom of a comic</li>
<li>Updated the main UI</li>
<h2>Version 2.0.15</h2>
<li>Totally revamped UI!</li>
<li>Background caching for offline access later!</li>
<li>Notification on availability of new comics!</li>
<li>Easy access to your last viewed strip in the comic</li>
<li>All of the 'latest', 'previous-session' and 'favorite' strips in a comic are accessible from one single place</li>
<li>A preview for every comic before you can choose it to be your favorite</li>
<li>A settings page to control and customize the behavior of 'ComicReader' to suit your purpose</li>
<li>21 new comics</li>
<li>All other previously supported features will continue to work as before</li>
<h2>Version 1.6.8</h2>
<li>Up-down to goto Next/Previous comics</li>
<li>Backup and restore my comics list</li>
<li>New Comics: "Something of that Ilk", "Surviving the world", "Wondermark"</li>
<li>68 Editorial Comics</li>
<li>Fix for crash in Previous Session in Sinfest</li>
<li>Fix Title in Xkcd</li>
<li>Fix for Network notification, when connected in Wifi, and 3G toggles</li>
<h2>Version 1.6.1</h2>
<li>Fast Scrolling in All Comics (Select Comics) tab</li>
<li>New tab for newly added comics in current version</li>
<li>Fixes in "Flash Gordon", "Least I Could Do", "Questionable Content" and "Tundra"</li>
<li>Added "Misfile" and "Hazel"</li>
<h2>Version 1.5.45</h2>
<li>Fix for "Geek and Poke" and "Penny Arcade"</li>
<li>Some other bug fixes</li>
<li>15 more comics</li>
<h2>Version 1.5.31</h2>
<li>Fix to the crash on several comics such as Garfield, Calvin and Hobbes, B.C. and Luann etc</li>
<li>Some other bug fixes</li>
<li>72 more comics</li>
<h2>Version 1.5.14</h2>
<li>Fix to the crash on several comics such as Garfield, Calvin and Hobbes, B.C. and Luann etc</li>
<h2>Version 1.5.12</h2>
<li>Fix to the latest crash on several comics like GetFuzzy, BigNate etc</li>
<li>Added 16 more comics</li>
<li>Added on-screen traversal buttons for easier navigation on next/previous comic</li>
<h2>Version 1.5.1</h2>
<li>Number of comics increased to 244</li>
<li>Removed Cyanide and Happiness</li>
<li>Added a save strip feature</li>
<li>Added a comic request feature</li>
<li>Added a send bug report feature</li>
<h2>Version 1.3.2</h2>
<li>Fix for Garfield, Calvin & Hobbes, BC and few more comics</li>
<li>2 more comics</li>
<h2>Version 1.3.1</h2>
<li>12 more comics</li>
<li>Bug Fixes</li>
<h2>Version 1.2.16</h2>
<li>Save/Restore the last session</li>
<li>Bug Fixes</li>
<h2>Version 1.2.14</h2>
<li>Navigation Bug Fixes</li>
<h2>Version 1.2.8</h2>
<li>5 more comics</li>
<li>Dialog to select specific comic</li>
<li>Minor bug fixes in the UI</li>
<h2>Version 1.2.8</h2>
<li>5 more comics</li>
<li>Dialog to select specific comic</li>
<li>Minor bug fixes in the UI</li>
<h2>Version 1.0.28</h2>
<li>12 more comics</li>
<li>Background caching</li>
<li>Add/remove favorites</li>
<li>Default zoom</li>
<li>On-screen buttons</li>
<li>Faster image loading</li>
<li>Sharing a strip</li>
<h2>Version 0.3.0</h2>
<li>Fixed the annoying network connectivity toast message issue</li>
<h2>Version 0.2.27</h2>
<li>38 Comics Series</li>
<li>Pinch-Zoom</li>
<li>Fling to Pan or Traverse Previous/Next</li>
<li>Traverse to Random Comics</li>
<li>Image Text</li>
<li>First and Latest Comics</li>
<li>Clear Cache</li>
</body>
</html>

View File

@ -0,0 +1,32 @@
<html>
<title>DISCLAIMER</title>
<body bgcolor=#ffff00>
<img src='file:///android_asset/a4a.png' align=right />
<h1>Disclaimer!</h1>
Some of the comics may occasionally contain:
<li>strong language (which is unsuitable for children)</li>
<li>unusual humor (which may be unsuitable for some)</li>
<li>advanced mathematics (which may be unsuitable for liberal-arts majors)</li>
<li>comics of artistic values (which may degrade the 'intelligence' of people from technical background)</li>
<p>
Also, most of these comics are highly addictive! The repercussions are:
<li>Poor performance in exams/qualifiers.</li>
<li>Reduced productivity at work.</li>
<li>Decreased attention to your personal life and hygiene.</li>
</p>
<p>
Authors of this app take no responsibility whatsoever for the
physical/psychological damage caused due to reading those comic-strips.
User discretion is strongly advised before reading them or even before
starting to read on them!
</p>
<p>
This application only downloads and displays the comic images from various hosts on the internet.
Authors of this application do NOT own any of these strips. All trademarks, logos and strips related
to the comic series are owned by their respective authors. Also, one can visit the homepages
of those comic strips by long-touching on the comic series and selecting 'OK' on the subsequent
alert-dialog (in the main menu). Any issues with licensing is purely unintentional and those comic
series will be removed if contacted.
</p>
</body>
</html>

65
ComicReader/assets/Help.html Executable file
View File

@ -0,0 +1,65 @@
<html>
<body bgcolor=#ffff00>
<img src='file:///android_asset/a4a.png' align=right />
<h1>Help:</h1>
<br>
<h2>Favorite comics</h2>
The main page displayed when the app starts is the place where you'll find all your favorite comics. Each row contains
3 buttons which provide you with 3 alternate choices of browsing that comic. Each of them will be described in detail below.
<h3>Latest</h3>
This will take you to the latest comic-strip for that comic
<h3>Pre</h3>
This will take you straight to where you left off when the last time you read that comic. This is a very useful feature
especially when you visit back to the comic after a long time. You don't have to remember where you left off. Our app does
that for you!
<h3>Fav</h3>
This can be used to browse all those strips which you had marked as favorite, for that comic.
<p>
You can store your favorite comic list and restore them back later (while you are busy experimenting with new comics!), by
doing the following from the main screen: Menu -> 'Backup my list' and Menu -> 'Restore my list'.
For an exhaustive list of features, just browse through the list which opens when you press menu button while in the main-screen
</p>
<br>
<h2>Selecting your favorite comics:</h2>
You can select your favorite comics by doing the following from the main-screen: Menu -> Select Comic.
This will open a list of all comics currently supported by this app. BTW, the list is still growing!
If you aren't sure whether you like a comic by its name, then you can try our new feature called 'preview'.
This will open the comic which you can browse, read some strips and then decide whether you like this comic or not.
Cool! isn't it?
In order to save your favorite list, just press the 'Save Changes', else press 'Cancel', both at the top of the list.
You can also select all/none of the comics by pressing Menu -> 'Select All' or 'Select None' respectively.
Last but not the least, if you have any cool comic series in mind, shoot a request at us by: Menu -> Comic Request.
In case you want to visit the actual website where this comic is hosted on, just long press on the comic name.
<br>
<h2>Settings</h2>
You can find a whole list of settings used to configure how ComicReader behaves. To go to the settings page, do the
following from the main-screen: Menu -> Settings
Please be aware of the fact that some of the settings might make ComicReader to run very frequently thereby draining
the battery of your phone! Use discretion while working in this page!!
<br>
<h2>Reading Comic Strips</h2>
<h3>Traversal when comic image is fit-screen</h3>
<li>Swipe right/left to goto previous/next comic of the same comic series</li>
<li>Swipe up/down to goto previous/next favorite comic series!</li>
<li>Pinch to zoom-in and zoom-out. Or you can use on screen buttons which shows up when you touch screen.</li>
<h3>Traversal when comic image is zoomed</h3>
<li>Double tap will bring up a text-button at the top of the screen.
<li>Then swipe left/right to goto previous/next comic of the same comic series</li>
<li>Swipe up/down to goto previous/next favorite comic series!</li>
<h3>Viewing mouse-hover text</h3>
<li>Touch screen and look for image text button (bottom leftmost). Button will be shown only when hover text appears.
Tap on the button to see the text.</li>
<h3>Mark comic strip as favourite</h3>
<li>Touch screen and tap on "Favorite" button (star). Star will turn green. This strip will be accessible when enter
the comic from the main screen and press 'Fav' button for that comic.</li>
<li>Touch on green colored Star button to remove strip from your favorite list.</li>
<h3>Share a comic strip</h3>
<li>Touch screen and tap on share button. Select Messaging/Email/Gmail/Facebook/Twitter to start the corresponding application.</li>
<h3>Comic Strip Picker</h3>
<li>Press "Menu", tap on "Select Strip", choose Date or Index from dialog box and enjoy reading the comics from there!</li>
</body>
</html>

BIN
ComicReader/assets/a4a.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

457
ComicReader/assets/classes.json Executable file
View File

@ -0,0 +1,457 @@
{
"package": "com.blogspot.applications4android.comicreader.comics",
"classes":
[
{"class" : "GoComics.TwoCowsandaChicken" , "name" : "2 Cows and a Chicken" , "pref" : "2cowsandachickenPref"},
{"class" : "GoComics.NineChickweedLane" , "name" : "9 Chickweed Lane" , "pref" : "ninechickweedlanePref"},
{"class" : "GoComics.Nineto5" , "name" : "9 to 5" , "pref" : "9to5Pref"},
{"class" : "AGirlandHerFed" , "name" : "A Girl and Her Fed" , "pref" : "agirlandherfedPref"},
{"class" : "ASofterWorld" , "name" : "A Softer World" , "pref" : "asofterworldPref"},
{"class" : "AbstruseGoose" , "name" : "Abstruse Goose", "pref" : "abstrusegoosePref"},
{"class" : "GoComics.AdamatHome" , "name" : "Adam@Home" , "pref" : "adamathomePref"},
{"class" : "GoComics.Agnes" , "name" : "Agnes" , "pref" : "agnesPref"},
{"class" : "GoComics.AlleyOop" , "name" : "Alley Oop" , "pref" : "alleyoopPref"},
{"class" : "AmazingSuperpowers" , "name" : "Amazing Superpowers" , "pref" : "amazingsuperpowersPref"},
{"class" : "GoComics.AndyCapp" , "name" : "Andy Capp" , "pref" : "andycappPref"},
{"class" : "GoComics.AnimalCrackers" , "name" : "Animal Crackers" , "pref" : "animalcrackersPref"},
{"class" : "OregonLive.Apartment3G" , "name" : "Apartment3-G" , "pref" : "apartment3gPref"},
{"class" : "OregonLive.Arctic" , "name" : "Arctic Circle" , "pref" : "arcticPref"},
{"class" : "GoComics.ArlonJanis" , "name" : "Arlo & Janis" , "pref" : "arlo&janisPref"},
{"class" : "GoComics.AskShagg" , "name" : "Ask Shagg" , "pref" : "askshaggPref"},
{"class" : "OregonLive.BabyBlues" , "name" : "Baby Blues" , "pref" : "babybluesPref"},
{"class" : "GoComics.BC" , "name" : "B.C." , "pref" : "bcPref"},
{"class" : "GoComics.BackintheDay" , "name" : "Back in the Day" , "pref" : "backinthedayPref"},
{"class" : "GoComics.BadReporter" , "name" : "Bad Reporter" , "pref" : "badreporterPref"},
{"class" : "GoComics.Baldo" , "name" : "Baldo" , "pref" : "baldoPref"},
{"class" : "GoComics.BallardStreet" , "name" : "Ballard Street" , "pref" : "ballardstreetPref"},
{"class" : "GoComics.BarkeaterLake" , "name" : "Barkeater Lake" , "pref" : "barkeaterlakePref"},
{"class" : "GoComics.BarneynClyde" , "name" : "Barney & Clyde" , "pref" : "barneyandclydePref"},
{"class" : "OregonLive.BarneyGoogle" , "name" : "Barney Google and Snuffy Smith" , "pref" : "barneygooglePref"},
{"class" : "GoComics.BasicInstructions" , "name" : "Basic Instructions" , "pref" : "basicinstructionsPref"},
{"class" : "OregonLive.BeetleBailey" , "name" : "Beetle Bailey" , "pref" : "beetlebaileyPref"},
{"class" : "GoComics.Ben" , "name" : "Ben" , "pref" : "benPref"},
{"class" : "OregonLive.BetterHalf" , "name" : "Better Half" , "pref" : "betterhalfPref"},
{"class" : "GoComics.Betty" , "name" : "Betty" , "pref" : "bettyPref"},
{"class" : "OregonLive.BetweenFriends" , "name" : "Between Friends" , "pref" : "betweenfriendsPref"},
{"class" : "GoComics.Bewley" , "name" : "Bewley" , "pref" : "bewleyPref"},
{"class" : "GoComics.BigNate" , "name" : "Big Nate" , "pref" : "bignatePref"},
{"class" : "GoComics.BigTop" , "name" : "Big Top" , "pref" : "bigtopPref"},
{"class" : "GoComics.Biographic" , "name" : "Biographic" , "pref" : "biographicPref"},
{"class" : "GoComics.Birdbrains" , "name" : "Birdbrains" , "pref" : "birdbrainsPref"},
{"class" : "OregonLive.Bizarro" , "name" : "Bizarro" , "pref" : "bizarroPref"},
{"class" : "GoComics.Bliss" , "name" : "Bliss" , "pref" : "blissPref"},
{"class" : "OregonLive.Bleeker" , "name" : "Bleeker the Rechargeable Dog" , "pref" : "bleekerPref"},
{"class" : "Blondie" , "name" : "Blondie" , "pref" : "blondiePref"},
{"class" : "GoComics.BloomCounty" , "name" : "Bloom County" , "pref" : "bloomcountyPref"},
{"class" : "GoComics.BoNanas" , "name" : "Bo Nanas" , "pref" : "bonanasPref"},
{"class" : "GoComics.BobtheSquirrel" , "name" : "Bob the Squirrel" , "pref" : "bobthesquirrelPref"},
{"class" : "GoComics.Boomerangs" , "name" : "Boomerangs" , "pref" : "boomerangsPref"},
{"class" : "GoComics.Bottomliners" , "name" : "Bottomliners" , "pref" : "bottomlinersPref"},
{"class" : "GoComics.BoundandGagged" , "name" : "Bound and Gagged" , "pref" : "boundandgaggedPref"},
{"class" : "GoComics.Brainwaves" , "name" : "Brainwaves" , "pref" : "brainwavesPref"},
{"class" : "GoComics.Brevity" , "name" : "Brevity Panel" , "pref" : "brevityPref"},
{"class" : "GoComics.BrewsterRockit" , "name" : "Brewster Rockit" , "pref" : "brewsterrockitPref"},
{"class" : "OregonLive.Edison" , "name" : "Brilliant Mind of Edison Lee" , "pref" : "edisonPref"},
{"class" : "GoComics.BroomHilda" , "name" : "Broom Hilda" , "pref" : "broomhildaPref"},
{"class" : "OregonLive.Buckles" , "name" : "Buckles" , "pref" : "bucklesPref"},
{"class" : "BugComic" , "name" : "Bug Comic" , "pref" : "bugcomicPref"},
{"class" : "Bunbuns" , "name" : "Bunbuns" , "pref" : "bunbunPref"},
{"class" : "Buttersafe" , "name" : "Buttersafe" , "pref" : "buttersafePref"},
{"class" : "GoComics.CafeconLeche" , "name" : "Cafe con Leche" , "pref" : "cafeconlechePref"},
{"class" : "CalamitiesOfNature" , "name" : "Calamities Of Nature" , "pref" : "calamitiesofnaturePref"},
{"class" : "GoComics.CalvinandHobbes" , "name" : "Calvin and Hobbes" , "pref" : "calvinandhobbesPref"},
{"class" : "GoComics.Candorville" , "name" : "Candorville" , "pref" : "candorvillePref"},
{"class" : "GoComics.Cathy" , "name" : "Cathy" , "pref" : "cathyPref"},
{"class" : "GoComics.CestlaVie" , "name" : "C'est la Vie" , "pref" : "cestlaviePref"},
{"class" : "ChamberoftheArcanum" , "name" : "Chamber of the Arcanum" , "pref" : "chamberofthearcanumPref"},
{"class" : "GoComics.CheapThrillsCuisine" , "name" : "Cheap Thrills Cuisine" , "pref" : "cheapthrillscuisinePref"},
{"class" : "GoComics.ChuckleBros" , "name" : "Chuckle Bros" , "pref" : "chucklebrosPref"},
{"class" : "GoComics.CitizenDog" , "name" : "Citizen Dog" , "pref" : "citizendogPref"},
{"class" : "GoComics.Cleats" , "name" : "Cleats" , "pref" : "cleatsPref"},
{"class" : "GoComics.ClosetoHome" , "name" : "Close to Home" , "pref" : "closetohomePref"},
{"class" : "GoComics.Committed" , "name" : "Committed" , "pref" : "committedPref"},
{"class" : "GoComics.Computoon" , "name" : "Compu-toon" , "pref" : "computoonPref"},
{"class" : "GoComics.Cornered" , "name" : "Cornered" , "pref" : "corneredPref"},
{"class" : "GoComics.CowTown" , "name" : "CowTown" , "pref" : "cowtownPref"},
{"class" : "GoComics.CownBoy" , "name" : "Cow & Boy" , "pref" : "cow&boyPref"},
{"class" : "OregonLive.Crankshaft" , "name" : "Crankshaft" , "pref" : "crankshaftPref"},
{"class" : "OregonLive.Crock" , "name" : "Crock" , "pref" : "crockPref"},
{"class" : "CtrlAltDel" , "name" : "Ctrl+Alt+Del" , "pref" : "ctrlaltdelPref"},
{"class" : "CtrlAltDelSillies" , "name" : "Ctrl+Alt+Del Sillies" , "pref" : "ctrlaltdelsilliesPref"},
{"class" : "GoComics.CuldeSac" , "name" : "Cul de Sac" , "pref" : "culdesacPref"},
{"class" : "OregonLive.Curtis" , "name" : "Curtis" , "pref" : "curtisPref"},
{"class" : "Cyanide" , "name" : "Cyanide and Happiness" , "pref" : "cyanidePref"},
{"class" : "GoComics.DaddysHome" , "name" : "Daddy's Home" , "pref" : "daddyshomePref"},
{"class" : "DarkLegacy" , "name" : "Dark Legacy" , "pref" : "darklegacyPref"},
{"class" : "GoComics.DarkSideoftheHorse" , "name" : "Dark Side of the Horse" , "pref" : "darksideofthehorsePref"},
{"class" : "DarthsandDroids" , "name" : "Darths & Droids" , "pref" : "darthsanddroidsPref"},
{"class" : "DayByDay" , "name" : "Day By Day" , "pref" : "daybydayPref"},
{"class" : "GoComics.DeepCover" , "name" : "Deep Cover" , "pref" : "deepcoverPref"},
{"class" : "OregonLive.Deflocked" , "name" : "DeFlocked" , "pref" : "deflockedPref"},
{"class" : "OregonLive.DennisTheMenace" , "name" : "Dennis The Menace" , "pref" : "dennisthemenacePref"},
{"class" : "GoComics.DiamondLil" , "name" : "Diamond Lil" , "pref" : "diamondlilPref"},
{"class" : "GoComics.DickTracy" , "name" : "Dick Tracy" , "pref" : "dicktracyPref"},
{"class" : "Dilbert" , "name" : "Dilbert" , "pref" : "dilbertPref"},
{"class" : "Dinosaur" , "name" : "Dinosaur" , "pref" : "dinosaurPref"},
{"class" : "GoComics.DogEatDoug" , "name" : "Dog Eat Doug" , "pref" : "dogeatdougPref"},
{"class" : "DogHouseDiaries" , "name" : "Doghouse Diaries" , "pref" : "doghousediariesPref"},
{"class" : "GoComics.DogsofCKennel" , "name" : "Dogs of C-Kennel" , "pref" : "dogsofckennelPref"},
{"class" : "GoComics.DomesticAbuse" , "name" : "Domestic Abuse" , "pref" : "domesticabusePref"},
{"class" : "GoComics.Doodles" , "name" : "Doodles" , "pref" : "doodlesPref"},
{"class" : "GoComics.Doonesbury" , "name" : "Doonesbury" , "pref" : "doonesburyPref"},
{"class" : "GoComics.Drabble" , "name" : "Drabble" , "pref" : "drabblePref"},
{"class" : "GoComics.DudeandDude" , "name" : "Dude and Dude" , "pref" : "dudedudePref"},
{"class" : "DumbingofAge" , "name" : "Dumbing of Age" , "pref" : "dumbingofagePref"},
{"class" : "OregonLive.Dustin" , "name" : "Dustin" , "pref" : "dustinPref"},
{"class" : "OregonLive.EdgeCity" , "name" : "Edge City!" , "pref" : "edgecityPref"},
{"class" : "GoComics.Eek" , "name" : "Eek!" , "pref" : "eekPref"},
{"class" : "GoComics.Endtown" , "name" : "Endtown" , "pref" : "endtownPref"},
{"class" : "GoComics.FMinus" , "name" : "F Minus" , "pref" : "fminusPref"},
{"class" : "OregonLive.FamilyCircus" , "name" : "Family Circus" , "pref" : "familycircusPref"},
{"class" : "GoComics.FamilyTree" , "name" : "Family Tree" , "pref" : "familytreePref"},
{"class" : "GoComics.Farcus" , "name" : "Farcus" , "pref" : "farcusPref"},
{"class" : "GoComics.FatCats" , "name" : "Fat Cats" , "pref" : "fatcatsPref"},
{"class" : "GoComics.Ferdnand" , "name" : "Ferd'nand" , "pref" : "ferdnandPref"},
{"class" : "FeyWinds" , "name" : "Fey Winds" , "pref" : "feywindsPref"},
{"class" : "OregonLive.FlashGordon" , "name" : "Flash Gordon" , "pref" : "flashgordonPref"},
{"class" : "GoComics.FlightDeck" , "name" : "Flight Deck" , "pref" : "flightdeckPref"},
{"class" : "GoComics.FloandFriends" , "name" : "Flo and Friends" , "pref" : "floandfriendsPref"},
{"class" : "GoComics.ForBetterorForWorse" , "name" : "For Better or For Worse" , "pref" : "forbetterorforworsePref"},
{"class" : "GoComics.ForHeavensSake" , "name" : "For Heaven's Sake" , "pref" : "forheavenssakePref"},
{"class" : "GoComics.FortKnox" , "name" : "Fort Knox" , "pref" : "fortknoxPref"},
{"class" : "GoComics.FoxTrot" , "name" : "FoxTrot" , "pref" : "foxtrotPref"},
{"class" : "GoComics.FoxTrotClassics" , "name" : "FoxTrot Classics" , "pref" : "foxtrotclassicsPref"},
{"class" : "GoComics.Frazz" , "name" : "Frazz" , "pref" : "frazzPref"},
{"class" : "GoComics.FranknErnest" , "name" : "Frank & Ernest" , "pref" : "frankandernestPref"},
{"class" : "GoComics.FredBasset" , "name" : "Fred Basset" , "pref" : "fredbassetPref"},
{"class" : "FreeFall" , "name" : "Free Fall" , "pref" : "freefallPref"},
{"class" : "GoComics.FreeRange" , "name" : "Free Range" , "pref" : "freerangePref"},
{"class" : "GoComics.FreshlySqueezed" , "name" : "Freshly Squeezed" , "pref" : "freshlysqueezedPref"},
{"class" : "GoComics.FrogApplause" , "name" : "Frog Applause" , "pref" : "frogapplausePref"},
{"class" : "OregonLive.FunkyWinkerbean" , "name" : "Funky Winkerbean" , "pref" : "funkywinkerbeanPref"},
{"class" : "GoComics.Garfield" , "name" : "Garfield" , "pref" : "garfieldPref"},
{"class" : "GoComics.GarfieldMinusGarfield" , "name" : "Garfield Minus Garfield" , "pref" : "garfieldminusgarfieldPref"},
{"class" : "GoComics.GasolineAlley" , "name" : "Gasoline Alley" , "pref" : "gasolinealleyPref"},
{"class" : "GoComics.Geech" , "name" : "Geech" , "pref" : "geechPref"},
{"class" : "GeekAndPoke" , "name" : "Geek And Poke" , "pref" : "geeknpokePref"},
{"class" : "GoComics.GetFuzzy" , "name" : "Get Fuzzy" , "pref" : "getfuzzyPref"},
{"class" : "GoComics.GetaLife" , "name" : "Get a Life" , "pref" : "getalifePref"},
{"class" : "GoComics.GilThorp" , "name" : "Gil Thorp" , "pref" : "gilthorpPref"},
{"class" : "GoComics.GingerMeggs" , "name" : "Ginger Meggs" , "pref" : "gingermeggsPref"},
{"class" : "GirlGenius" , "name" : "Girl Genius" , "pref" : "girlgeniusPref"},
{"class" : "GirlswithSlingshots" , "name" : "Girls with Slingshots" , "pref" : "girlswithslingshotsPref"},
{"class" : "GoComics.Graffiti" , "name" : "Graffiti" , "pref" : "graffitiPref"},
{"class" : "GoComics.GrandAvenue" , "name" : "Grand Avenue" , "pref" : "grandavenuePref"},
{"class" : "OregonLive.GrinandBearIt" , "name" : "Grin and Bear It" , "pref" : "grinandbearitPref"},
{"class" : "GuComics" , "name" : "Gu Comics" , "pref" : "gucomicsPref"},
{"class" : "GunnerkriggCourt" , "name" : "Gunnerkrigg Court" , "pref" : "gunnerkriggcourtPref"},
{"class" : "OregonLive.HagarTheHorrible" , "name" : "Hagar The Horrible" , "pref" : "hagarthehorriblePref"},
{"class" : "GoComics.HaikuEwe" , "name" : "Haiku Ewe" , "pref" : "haikuewePref"},
{"class" : "OregonLive.Hazel" , "name" : "Hazel" , "pref" : "hazelPref"},
{"class" : "GoComics.HeartoftheCity" , "name" : "Heart of the City" , "pref" : "heartofthecityPref"},
{"class" : "GoComics.Heathcliff" , "name" : "Heathcliff" , "pref" : "heathcliffPref"},
{"class" : "OregonLive.Henry" , "name" : "Henry" , "pref" : "henryPref"},
{"class" : "GoComics.HerbandJamaal" , "name" : "Herb and Jamaal" , "pref" : "herbandjamaalPref"},
{"class" : "GoComics.Herman" , "name" : "Herman" , "pref" : "hermanPref"},
{"class" : "OregonLive.HiandLois" , "name" : "Hi and Lois" , "pref" : "hiandloisPref"},
{"class" : "GoComics.HomeandAway" , "name" : "Home and Away" , "pref" : "homeandawayPref"},
{"class" : "GoComics.HubertandAbby" , "name" : "Hubert and Abby" , "pref" : "hubertandabbyPref"},
{"class" : "GoComics.ImagineThis" , "name" : "Imagine This" , "pref" : "imaginethisPref"},
{"class" : "GoComics.IncidentalComics" , "name" : "Incidental Comics" , "pref" : "incidentalcomicsPref"},
{"class" : "GoComics.InkPen" , "name" : "Ink Pen" , "pref" : "inkpenPref"},
{"class" : "GoComics.IntheBleachers" , "name" : "In the Bleachers" , "pref" : "inthebleachersPref"},
{"class" : "GoComics.IntheSticks" , "name" : "In the Sticks" , "pref" : "inthesticksPref"},
{"class" : "GoComics.ItsAllAboutYou" , "name" : "It's All About You" , "pref" : "itsallaboutyouPref"},
{"class" : "GoComics.JanesWorld" , "name" : "Jane's World" , "pref" : "janesworldPref"},
{"class" : "GoComics.JimsJournal" , "name" : "Jim's Journal" , "pref" : "jimsjournalPref"},
{"class" : "JoeAndMonkey" , "name" : "Joe And Monkey" , "pref" : "joeandmonkeyPref"},
{"class" : "GoComics.JoeVanilla" , "name" : "Joe Vanilla" , "pref" : "joevanillaPref"},
{"class" : "OregonLive.JudgeParker" , "name" : "Judge Parker" , "pref" : "judgeparkerPref"},
{"class" : "GoComics.JumpStart" , "name" : "Jump Start" , "pref" : "jumpstartPref"},
{"class" : "GoComics.KidSpot" , "name" : "KidSpot" , "pref" : "kidspotPref"},
{"class" : "GoComics.KitNCarlyle" , "name" : "Kit 'N' Carlyle" , "pref" : "kitn_carlylePref"},
{"class" : "GoComics.LaCucaracha" , "name" : "La Cucaracha" , "pref" : "lacucarachaPref"},
{"class" : "GoComics.LastKiss" , "name" : "Last Kiss" , "pref" : "lastkissPref"},
{"class" : "LeastICouldDo" , "name" : "Least I Could Do" , "pref" : "leasticoulddoPref"},
{"class" : "GoComics.LegendofBill" , "name" : "Legend of Bill" , "pref" : "legendofbillPref"},
{"class" : "GoComics.LilAbner" , "name" : "Li'l Abner" , "pref" : "lilabnerPref"},
{"class" : "GoComics.LibertyMeadows" , "name" : "Liberty Meadows" , "pref" : "libertymeadowsPref"},
{"class" : "GoComics.Lio" , "name" : "Lio" , "pref" : "lioPref"},
{"class" : "GoComics.LittleDogLost" , "name" : "Little Dog Lost" , "pref" : "littledoglostPref"},
{"class" : "OregonLive.Lockhorns" , "name" : "Lockhorns" , "pref" : "lockhornsPref"},
{"class" : "GoComics.Lola" , "name" : "Lola" , "pref" : "lolaPref"},
{"class" : "LookingForGroup" , "name" : "Looking For Group" , "pref" : "lookingforgroupPref"},
{"class" : "GoComics.LooseParts" , "name" : "Loose Parts" , "pref" : "loosepartsPref"},
{"class" : "GoComics.LostSideofSuburbia" , "name" : "Lost Side of Suburbia" , "pref" : "lostsideofsuburbiaPref"},
{"class" : "GoComics.LoveIs" , "name" : "Love Is..." , "pref" : "loveisPref"},
{"class" : "GoComics.Luann" , "name" : "Luann" , "pref" : "luannPref"},
{"class" : "GoComics.LuckyCow" , "name" : "Lucky Cow" , "pref" : "luckycowPref"},
{"class" : "GoComics.Maintaining" , "name" : "Maintaining" , "pref" : "maintainingPref"},
{"class" : "OregonLive.MallardFillmore" , "name" : "Mallard Fillmore" , "pref" : "mallardfillmorePref"},
{"class" : "OregonLive.Mandrake" , "name" : "Mandrake" , "pref" : "mandrakePref"},
{"class" : "OregonLive.MarkTrail" , "name" : "Mark Trail" , "pref" : "marktrailPref"},
{"class" : "GoComics.Marmaduke" , "name" : "Marmaduke" , "pref" : "marmadukePref"},
{"class" : "OregonLive.Marvin" , "name" : "Marvin" , "pref" : "marvinPref"},
{"class" : "OregonLive.MaryWorth" , "name" : "Mary Worth" , "pref" : "maryworthPref"},
{"class" : "GoComics.MegClassics" , "name" : "Meg Classics" , "pref" : "megclassicsPref"},
{"class" : "GoComics.MinimumSecurity" , "name" : "Minimum Security" , "pref" : "minimumsecurityPref"},
{"class" : "Misfile" , "name" : "Misfile" , "pref" : "misfilePref"},
{"class" : "GoComics.ModeratelyConfused" , "name" : "Moderately Confused" , "pref" : "moderatelyconfusedPref"},
{"class" : "GoComics.MollyandtheBear" , "name" : "Molly and the Bear" , "pref" : "mollyandthebearPref"},
{"class" : "GoComics.Momma" , "name" : "Momma" , "pref" : "mommaPref"},
{"class" : "GoComics.Monty" , "name" : "Monty" , "pref" : "montyPref"},
{"class" : "OregonLive.Moose" , "name" : "Moose and Molly" , "pref" : "moosePref"},
{"class" : "MotherGooseandGrimm" , "name" : "Mother Goose & Grimm" , "pref" : "mothergooseandgrimmPref"},
{"class" : "GoComics.MuttnJeff" , "name" : "Mutt & Jeff" , "pref" : "muttandjeffPref"},
{"class" : "OregonLive.Mutts" , "name" : "Mutts" , "pref" : "muttsPref"},
{"class" : "GoComics.MyCage" , "name" : "My Cage" , "pref" : "mycagePref"},
{"class" : "GoComics.MythTickle" , "name" : "MythTickle" , "pref" : "mythticklePref"},
{"class" : "GoComics.Neurotica" , "name" : "Neurotica" , "pref" : "neuroticaPref"},
{"class" : "GoComics.Nancy" , "name" : "Nancy" , "pref" : "nancyPref"},
{"class" : "GoComics.NestHeads" , "name" : "Nest Heads" , "pref" : "nestheadsPref"},
{"class" : "GoComics.NewAdventuresofQueenVictoria" , "name" : "New Adventures of Queen Victoria" , "pref" : "tnaoqvPref"},
{"class" : "GoComics.NonSequitur" , "name" : "Non Sequitur" , "pref" : "nonsequiturPref"},
{"class" : "OregonLive.OhBrother" , "name" : "Oh Brother" , "pref" : "ohbPref"},
{"class" : "OOTS" , "name" : "Order of the Stick" , "pref" : "ootsPref"},
{"class" : "OregonLive.FastTrack" , "name" : "On the Fastrack" , "pref" : "fasttrackPref"},
{"class" : "GoComics.OffTheMark" , "name" : "Off The Mark" , "pref" : "offthe_markPref"},
{"class" : "OregonLive.Ollie" , "name" : "Ollie and Quentin" , "pref" : "olliePref"},
{"class" : "GoComics.OnAClaireDay" , "name" : "On A Claire Day" , "pref" : "onaclairedayPref"},
{"class" : "GoComics.OneBigHappy" , "name" : "One Big Happy" , "pref" : "onebighappyPref"},
{"class" : "GoComics.Opus" , "name" : "Opus" , "pref" : "opusPref"},
{"class" : "GoComics.OutoftheGenePoolReRuns" , "name" : "Out of the Gene Pool Re-Runs" , "pref" : "outofthegenepoolPref"},
{"class" : "GoComics.Overboard" , "name" : "Overboard" , "pref" : "overboardPref"},
{"class" : "GoComics.OvertheHedge" , "name" : "Over the Hedge" , "pref" : "overthe_hedgePref"},
{"class" : "GoComics.PCandPixel" , "name" : "PC and Pixel" , "pref" : "pcand_pixelPref"},
{"class" : "OregonLive.Pajama" , "name" : "Pajama Diaries" , "pref" : "pajamaPref"},
{"class" : "OregonLive.PardonMyPlanet" , "name" : "Pardon My Planet" , "pref" : "pardonmyplanetPref"},
{"class" : "GoComics.Peanuts" , "name" : "Peanuts" , "pref" : "peanutsPref"},
{"class" : "GoComics.PearlsBeforeSwine" , "name" : "Pearls Before Swine" , "pref" : "pearlsbefore_swinePref"},
{"class" : "PennyArcade" , "name" : "Penny Arcade" , "pref" : "pennyarcadePref"},
{"class" : "PhDComics" , "name" : "PhD Comics" , "pref" : "phdcomicsPref"},
{"class" : "GoComics.Pibgorn" , "name" : "Pibgorn" , "pref" : "pibgornPref"},
{"class" : "GoComics.PibgornSketches" , "name" : "Pibgorn Sketches" , "pref" : "pibgornsketchesPref"},
{"class" : "GoComics.Pickles" , "name" : "Pickles" , "pref" : "picklesPref"},
{"class" : "GoComics.Pinkerton" , "name" : "Pinkerton" , "pref" : "pinkertonPref"},
{"class" : "OregonLive.Piranha" , "name" : "Piranha Club" , "pref" : "piranhaPref"},
{"class" : "GoComics.Pluggers" , "name" : "Pluggers" , "pref" : "pluggersPref"},
{"class" : "GoComics.PoochCafe" , "name" : "Pooch Cafe" , "pref" : "poochcafePref"},
{"class" : "OregonLive.Popeye" , "name" : "Popeye" , "pref" : "popeyePref"},
{"class" : "GoComics.PreTeena" , "name" : "PreTeena" , "pref" : "preteenaPref"},
{"class" : "GoComics.PricklyCity" , "name" : "Prickly City" , "pref" : "pricklycityPref"},
{"class" : "QuestionableContent" , "name" : "Questionable Content" , "pref" : "questionablecontentPref"},
{"class" : "GoComics.RabbitsAgainstMagic" , "name" : "Rabbits Against Magic" , "pref" : "rabbitsagainstmagicPref"},
{"class" : "GoComics.RaisingDuncan" , "name" : "Raising Duncan" , "pref" : "raisingduncanPref"},
{"class" : "GoComics.RealLifeAdventures" , "name" : "Real Life Adventures" , "pref" : "reallifeadventuresPref"},
{"class" : "GoComics.RealityCheck" , "name" : "Reality Check" , "pref" : "realitycheckPref"},
{"class" : "GoComics.RedMeat" , "name" : "Red Meat" , "pref" : "redmeatPref"},
{"class" : "GoComics.RedandRover" , "name" : "Red and Rover" , "pref" : "redandroverPref"},
{"class" : "GoComics.ReplyAll" , "name" : "Reply All" , "pref" : "replyallPref"},
{"class" : "OregonLive.Retail" , "name" : "Retail" , "pref" : "retailPref"},
{"class" : "OregonLive.RexMorgan" , "name" : "Rex Morgan M.D." , "pref" : "rexmorganPref"},
{"class" : "OregonLive.RhymeswithOrange" , "name" : "Rhymes with Orange" , "pref" : "rhymeswithorangePref"},
{"class" : "GoComics.RipHaywire" , "name" : "Rip Haywire" , "pref" : "riphaywirePref"},
{"class" : "GoComics.RipleysBelieveItorNot" , "name" : "Ripley's Believe It or Not!" , "pref" : "ripleysbelieve_it_or_notPref"},
{"class" : "GoComics.RonaldinhoGaucho" , "name" : "Ronaldinho Gaucho" , "pref" : "ronaldinhogauchoPref"},
{"class" : "GoComics.RoseisRose" , "name" : "Rose is Rose" , "pref" : "roseis_rosePref"},
{"class" : "GoComics.Rubes" , "name" : "Rubes" , "pref" : "rubesPref"},
{"class" : "GoComics.RudyPark" , "name" : "Rudy Park" , "pref" : "rudyparkPref"},
{"class" : "SMBC" , "name" : "Saturday Morning Breakfast Cereal" , "pref" : "smbcPref"},
{"class" : "OregonLive.SafeHavens" , "name" : "Safe Havens" , "pref" : "safehavensPref"},
{"class" : "OregonLive.SallyForth" , "name" : "Sally Forth" , "pref" : "sallyforthPref"},
{"class" : "GoComics.ScaryGary" , "name" : "Scary Gary" , "pref" : "scarygaryPref"},
{"class" : "Sheldon" , "name" : "Sheldon" , "pref" : "sheldonPref"},
{"class" : "OregonLive.ShermansLagoon" , "name" : "Sherman's Lagoon" , "pref" : "cslagoonPref"},
{"class" : "GoComics.ShirleyandSonClassics" , "name" : "Shirley and Son Classics" , "pref" : "shirleyandsonclassicsPref"},
{"class" : "GoComics.Shoe" , "name" : "Shoe" , "pref" : "shoePref"},
{"class" : "GoComics.Shoecabbage" , "name" : "Shoecabbage" , "pref" : "shoecabbagePref"},
{"class" : "GoComics.Shortcuts" , "name" : "Shortcuts" , "pref" : "shortcutsPref"},
{"class" : "Sinfest" , "name" : "Sinfest" , "pref" : "sinfestPref"},
{"class" : "OregonLive.SixChix" , "name" : "Six Chix" , "pref" : "sixchixPref"},
{"class" : "GoComics.SkinHorse" , "name" : "Skin Horse" , "pref" : "skinhorsePref"},
{"class" : "OregonLive.Slylock" , "name" : "Slylock Fox" , "pref" : "slylockPref"},
{"class" : "GoComics.Slowpoke" , "name" : "Slowpoke" , "pref" : "slowpokePref"},
{"class" : "SomethingofthatIlk" , "name" : "Something Of That Ilk" , "pref" : "somethingofthatilkPref"},
{"class" : "SomethingPositive" , "name" : "Something Positive" , "pref" : "somethingpositivePref"},
{"class" : "GoComics.SoupToNutz" , "name" : "Soup To Nutz" , "pref" : "soupto_nutzPref"},
{"class" : "GoComics.SpeedBump" , "name" : "Speed Bump" , "pref" : "speedbumpPref"},
{"class" : "OregonLive.SpiderMan" , "name" : "Spider-Man" , "pref" : "spidermanPref"},
{"class" : "SpikedMath" , "name" : "Spiked Math" , "pref" : "spikedmathPref"},
{"class" : "GoComics.SpottheFrog" , "name" : "Spot the Frog" , "pref" : "spotthefrogPref"},
{"class" : "SpudComics" , "name" : "Spud Comics" , "pref" : "spudcomicsPref"},
{"class" : "StickyComics" , "name" : "Sticky Comics" , "pref" : "stickycomicsPref"},
{"class" : "GoComics.StoneSoup" , "name" : "Stone Soup" , "pref" : "stonesoupPref"},
{"class" : "GoComics.StrangeBrew" , "name" : "Strange Brew" , "pref" : "strangebrewPref"},
{"class" : "SurvivingtheWorld" , "name" : "Surviving the World" , "pref" : "survivingtheworldPref"},
{"class" : "GoComics.Sylvia" , "name" : "Sylvia" , "pref" : "sylviaPref"},
{"class" : "GoComics.Toby" , "name" : "Toby" , "pref" : "tobyPref"},
{"class" : "GoComics.TankMcNamara" , "name" : "Tank McNamara" , "pref" : "tankmcnamaraPref"},
{"class" : "GoComics.TarzanClassics" , "name" : "Tarzan" , "pref" : "tarzanclassicsPref"},
{"class" : "GoComics.Thatababy" , "name" : "Thatababy" , "pref" : "thatababyPref"},
{"class" : "GoComics.ThatsLife" , "name" : "That's Life" , "pref" : "thatslifePref"},
{"class" : "GoComics.TheAcademiaWaltz" , "name" : "The Academia Waltz" , "pref" : "academiawaltzPref"},
{"class" : "GoComics.TheArgyleSweater" , "name" : "The Argyle Sweater" , "pref" : "theargylesweaterPref"},
{"class" : "GoComics.TheBarn" , "name" : "The Barn" , "pref" : "thebarnPref"},
{"class" : "GoComics.TheBigPicture" , "name" : "The Big Picture" , "pref" : "thebigpicturePref"},
{"class" : "TheBookOfBiff" , "name" : "The Book of Biff" , "pref" : "thebookofbiffPref"},
{"class" : "GoComics.TheBoondocks" , "name" : "The Boondocks" , "pref" : "boondocksPref"},
{"class" : "GoComics.TheBornLoser" , "name" : "The Born Loser" , "pref" : "theborn_loserPref"},
{"class" : "GoComics.TheBuckets" , "name" : "The Buckets" , "pref" : "thebucketsPref"},
{"class" : "GoComics.TheCity" , "name" : "The City" , "pref" : "thecityPref"},
{"class" : "TheDevilsPanties" , "name" : "The Devil's Panties" , "pref" : "thedevilspantiesPref"},
{"class" : "GoComics.TheDinetteSet" , "name" : "The Dinette Set" , "pref" : "thedinette_setPref"},
{"class" : "GoComics.TheDoozies" , "name" : "The Doozies" , "pref" : "thedooziesPref"},
{"class" : "GoComics.TheDuplex" , "name" : "The Duplex" , "pref" : "duplexPref"},
{"class" : "GoComics.TheElderberries" , "name" : "The Elderberries" , "pref" : "theelderberriesPref"},
{"class" : "GoComics.TheFuscoBrothers" , "name" : "The Fusco Brothers" , "pref" : "thefuscobrothersPref"},
{"class" : "GoComics.TheFlyingMcCoys" , "name" : "The Flying McCoys" , "pref" : "theflyingmccoysPref"},
{"class" : "GoComics.TheGrizzwells" , "name" : "The Grizzwells" , "pref" : "thegrizzwellsPref"},
{"class" : "GoComics.TheHumbleStumble" , "name" : "The Humble Stumble" , "pref" : "humblestumblePref"},
{"class" : "GoComics.TheKChronicles" , "name" : "The K Chronicles" , "pref" : "thekchroniclesPref"},
{"class" : "GoComics.TheKnightLife" , "name" : "The Knight Life" , "pref" : "theknight_lifePref"},
{"class" : "GoComics.TheLeftyBoscoPictureShow" , "name" : "The LeftyBosco Picture Show" , "pref" : "leftyboscopictureshowPref"},
{"class" : "GoComics.TheMeaningofLila" , "name" : "The Meaning of Lila" , "pref" : "meaningoflilaPref"},
{"class" : "GoComics.TheMiddletons" , "name" : "The Middletons" , "pref" : "themiddletonsPref"},
{"class" : "GoComics.TheNorm" , "name" : "The Norm" , "pref" : "thenormPref"},
{"class" : "GoComics.TheSunshineClub" , "name" : "The Sunshine Club" , "pref" : "thesunshineclubPref"},
{"class" : "GoComics.TheOtherCoast" , "name" : "The Other Coast" , "pref" : "theothercoastPref"},
{"class" : "OregonLive.ThePhantom" , "name" : "The Phantom" , "pref" : "thephantomPref"},
{"class" : "GoComics.ThinLines" , "name" : "Thin Lines" , "pref" : "thinlinesPref"},
{"class" : "OregonLive.Tiger" , "name" : "Tiger" , "pref" : "tigerPref"},
{"class" : "TimeTrabble" , "name" : "Time Trabble" , "pref" : "timetrabblePref"},
{"class" : "OregonLive.TinasGroove" , "name" : "Tina's Groove" , "pref" : "tinaGroovePref"},
{"class" : "GoComics.TinySepuku" , "name" : "Tiny Sepuku" , "pref" : "tinysepukuPref"},
{"class" : "GoComics.TodaysDogg" , "name" : "Today's Dogg" , "pref" : "todaysdoggPref"},
{"class" : "OregonLive.Todd" , "name" : "Todd the Dinosaur" , "pref" : "toddPref"},
{"class" : "GoComics.TomtheDancingBug" , "name" : "Tom the Dancing Bug" , "pref" : "tomthedancingbugPref"},
{"class" : "GoComics.TooMuchCoffeeMan" , "name" : "Too Much Coffee Man" , "pref" : "toomuchcoffeemanPref"},
{"class" : "Tundra" , "name" : "Tundra" , "pref" : "tundraPref"},
{"class" : "GoComics.UncleArtsFunland" , "name" : "Uncle Art's Funland" , "pref" : "uncleartsfunlandPref"},
{"class" : "GoComics.UnstrangePhenomena" , "name" : "Unstrange Phenomena" , "pref" : "unstrangephenomenaPref"},
{"class" : "USAcres" , "name" : "U.S. Acres" , "pref" : "usacresPref"},
{"class" : "Userfriendly" , "name" : "Userfriendly" , "pref" : "userfriendlyPref"},
{"class" : "VGCats" , "name" : "VG Cats" , "pref" : "vgcatsPref"},
{"class" : "VirtualShackles" , "name" : "Virtual Shackles" , "pref" : "virtualshacklesPref"},
{"class" : "GoComics.WTDuck" , "name" : "W.T. Duck" , "pref" : "wtduckPref"},
{"class" : "WapsiSquare" , "name" : "Wapsi Square" , "pref" : "wapsisquarePref"},
{"class" : "GoComics.WatchYourHead" , "name" : "Watch Your Head" , "pref" : "watchyourheadPref"},
{"class" : "WaywardSons" , "name" : "Wayward Sons" , "pref" : "waywardsonsPref"},
{"class" : "GoComics.WeePals" , "name" : "Wee Pals" , "pref" : "weepalsPref"},
{"class" : "WhiteNinja" , "name" : "White Ninja" , "pref" : "whiteninjaPref"},
{"class" : "GoComics.WizardofId" , "name" : "Wizard of Id" , "pref" : "wizardofidPref"},
{"class" : "Wondermark" , "name" : "Wondermark" , "pref" : "wondermarkPref"},
{"class" : "GoComics.WorkingDaze" , "name" : "Working Daze" , "pref" : "workingdazePref"},
{"class" : "GoComics.WorkingItOut" , "name" : "Working It Out" , "pref" : "workingitoutPref"},
{"class" : "Wulffmorgenthaler" , "name" : "Wulffmorgenthaler" , "pref" : "wulffmorgenthalerPref"},
{"class" : "Xkcd" , "name" : "Xkcd" , "pref" : "xkcdPref"},
{"class" : "Yafgc" , "name" : "Yet Another Fantasy Gamer Comic" , "pref" : "yafgcPref"},
{"class" : "GoComics.ZackHill" , "name" : "Zack Hill" , "pref" : "zackhillPref"},
{"class" : "Zap" , "name" : "Zap!" , "pref" : "zapPref"},
{"class" : "GoComics.Ziggy" , "name" : "Ziggy" , "pref" : "ziggyPref"},
{"class" : "OregonLive.ZippythePinhead" , "name" : "Zippy the Pinhead" , "pref" : "zippythepinheadPref"},
{"class" : "OregonLive.Zits" , "name" : "Zits" , "pref" : "zitsPref"},
{"class" : "GoComics.Think", "name" : "Editorial : (th)ink", "pref" : "thinkPref"},
{"class" : "GoComics.BenSargent", "name" : "Editorial : Ben Sargent", "pref" : "bensargentPref"},
{"class" : "GoComics.BillDay", "name" : "Editorial : Bill Day", "pref" : "billdayPref"},
{"class" : "GoComics.BobGorrell", "name" : "Editorial : Bob Gorrell", "pref" : "bobgorrellPref"},
{"class" : "GoComics.BruceBeattie", "name" : "Editorial : Bruce Beattie", "pref" : "brucebeattiePref"},
{"class" : "GoComics.CaricaturesbyKerryWaghorn", "name" :"Editorial : Caricatures by Kerry Waghorn","pref" : "facesinthenewsPref"},
{"class" : "GoComics.ChanLowe", "name" : "Editorial : Chan Lowe", "pref" : "chanlowePref"},
{"class" : "GoComics.ChipBok", "name" : "Editorial : Chip Bok", "pref" : "chipbokPref"},
{"class" : "GoComics.ChrisBritt", "name" : "Editorial : Chris Britt", "pref" : "chrisbrittPref"},
{"class" : "GoComics.ChuckAsay", "name" : "Editorial : Chuck Asay", "pref" : "chuckasayPref"},
{"class" : "GoComics.ClayBennett", "name" : "Editorial : Clay Bennett", "pref" : "claybennettPref"},
{"class" : "GoComics.ClayJones", "name" : "Editorial : Clay Jones", "pref" : "clayjonesPref"},
{"class" : "GoComics.DanWasserman", "name" : "Editorial : Dan Wasserman", "pref" : "danwassermanPref"},
{"class" : "GoComics.DanaSummers", "name" : "Editorial : Dana Summers", "pref" : "danasummersPref"},
{"class" : "GoComics.DickLocher", "name" : "Editorial : Dick Locher", "pref" : "dicklocherPref"},
{"class" : "GoComics.DrewLitton", "name" : "Editorial : Drew Litton", "pref" : "drewlittonPref"},
{"class" : "GoComics.DrewSheneman", "name" : "Editorial : Drew Sheneman", "pref" : "drewshenemanPref"},
{"class" : "GoComics.DonWright", "name" : "Editorial : Don Wright", "pref" : "donwrightPref"},
{"class" : "GoComics.EdStein", "name" : "Editorial : Ed Stein", "pref" : "ed-steinPref"},
{"class" : "GoComics.GaryMarkstein", "name" : "Editorial : Gary Markstein", "pref" : "garymarksteinPref"},
{"class" : "GoComics.GaryVarvel", "name" : "Editorial : Gary Varvel", "pref" : "garyvarvelPref"},
{"class" : "GoComics.GlennMcCoy", "name" : "Editorial : Glenn McCoy", "pref" : "glennmccoyPref"},
{"class" : "GoComics.HenryPayne", "name" : "Editorial : Henry Payne", "pref" : "henrypaynePref"},
{"class" : "GoComics.JackOhman", "name" : "Editorial : Jack Ohman", "pref" : "jackohmanPref"},
{"class" : "GoComics.JeffDanziger", "name" : "Editorial : Jeff Danziger", "pref" : "jeffdanzigerPref"},
{"class" : "GoComics.JeffStahler", "name" : "Editorial : Jeff Stahler", "pref" : "jeffstahlerPref"},
{"class" : "GoComics.JerryHolbert", "name" : "Editorial : Jerry Holbert", "pref" : "jerryholbertPref"},
{"class" : "GoComics.JimMorin", "name" : "Editorial : Jim Morin", "pref" : "jimmorinPref"},
{"class" : "GoComics.JoelPett", "name" : "Editorial : Joel Pett", "pref" : "joelpettPref"},
{"class" : "GoComics.JohnDeering", "name" : "Editorial : John Deering", "pref" : "johndeeringPref"},
{"class" : "GoComics.KenCatalino", "name" : "Editorial : Ken Catalino", "pref" : "kencatalinoPref"},
{"class" : "GoComics.KevinKallaugher", "name" : "Editorial : Kevin Kallaugher", "pref" : "kevinkallaugherPref"},
{"class" : "GoComics.LaloAlcaraz", "name" : "Editorial : Lalo Alcaraz", "pref" : "laloalcarazPref"},
{"class" : "GoComics.LisaBenson", "name" : "Editorial : Lisa Benson", "pref" : "lisabensonPref"},
{"class" : "GoComics.MattBors", "name" : "Editorial : Matt Bors", "pref" : "matt-borsPref"},
{"class" : "GoComics.MattDavies", "name" : "Editorial : Matt Davies", "pref" : "mattdaviesPref"},
{"class" : "GoComics.MattWuerker", "name" : "Editorial : Matt Wuerker", "pref" : "mattwuerkerPref"},
{"class" : "GoComics.MarshallRamsey", "name" : "Editorial : Marshall Ramsey", "pref" : "marshallramseyPref"},
{"class" : "GoComics.MichaelRamirez", "name" : "Editorial : Michael Ramirez", "pref" : "michaelramirezPref"},
{"class" : "GoComics.MikeLester", "name" : "Editorial : Mike Lester", "pref" : "mike-lesterPref"},
{"class" : "GoComics.MikeLuckovich", "name" : "Editorial : Mike Luckovich", "pref" : "mikeluckovichPref"},
{"class" : "GoComics.MikeThompson", "name" : "Editorial : Mike Thompson", "pref" : "mikethompsonPref"},
{"class" : "GoComics.NickAnderson", "name" : "Editorial : Nick Anderson", "pref" : "nickandersonPref"},
{"class" : "GoComics.PatOliphant", "name" : "Editorial : Pat Oliphant", "pref" : "patoliphantPref"},
{"class" : "GoComics.PaulSzep", "name" : "Editorial : Paul Szep", "pref" : "paulszepPref"},
{"class" : "GoComics.RobRogers", "name" : "Editorial : Rob Rogers", "pref" : "robrogersPref"},
{"class" : "GoComics.RobertAriail", "name" : "Editorial : Robert Ariail", "pref" : "robert-ariailPref"},
{"class" : "GoComics.ScottStantis", "name" : "Editorial : Scott Stantis", "pref" : "scottstantisPref"},
{"class" : "GoComics.SigneWilkinson", "name" : "Editorial : Signe Wilkinson", "pref" : "signewilkinsonPref"},
{"class" : "GoComics.SmallWorld", "name" : "Editorial : Small World", "pref" : "smallworldPref"},
{"class" : "GoComics.SteveBenson", "name" : "Editorial : Steve Benson", "pref" : "stevebensonPref"},
{"class" : "GoComics.SteveBreen", "name" : "Editorial : Steve Breen", "pref" : "stevebreenPref"},
{"class" : "GoComics.SteveKelley", "name" : "Editorial : Steve Kelley", "pref" : "stevekelleyPref"},
{"class" : "GoComics.SteveSack", "name" : "Editorial : Steve Sack", "pref" : "stevesackPref"},
{"class" : "GoComics.StuartCarlson", "name" : "Editorial : Stuart Carlson", "pref" : "stuartcarlsonPref"},
{"class" : "GoComics.TedRall", "name" : "Editorial : Ted Rall", "pref" : "tedrallPref"},
{"class" : "GoComics.TomToles", "name" : "Editorial : Tom Toles", "pref" : "tomtolesPref"},
{"class" : "GoComics.TonyAuth", "name" : "Editorial : Tony Auth", "pref" : "tonyauthPref"},
{"class" : "GoComics.ViewsAfrica", "name" : "Editorial : Views Africa", "pref" : "viewsafricaPref"},
{"class" : "GoComics.ViewsAmerica", "name" : "Editorial : Views America", "pref" : "viewsamericaPref"},
{"class" : "GoComics.ViewsAsia", "name" : "Editorial : Views Asia", "pref" : "viewsasiaPref"},
{"class" : "GoComics.ViewsBusiness", "name" : "Editorial : Views Business", "pref" : "viewsbusinessPref"},
{"class" : "GoComics.ViewsEurope", "name" : "Editorial : Views Europe", "pref" : "viewseuropePref"},
{"class" : "GoComics.ViewsLatinAmerica", "name" : "Editorial : Views Latin America", "pref" : "viewslatinamericaPref"},
{"class" : "GoComics.ViewsMidEast", "name" : "Editorial : Views Mid East", "pref" : "viewsmideastPref"},
{"class" : "GoComics.ViewsoftheWorld", "name" : "Editorial : Views of the World", "pref" : "viewsoftheworldPref"},
{"class" : "GoComics.WaltHandelsman", "name" : "Editorial : Walt Handelsman", "pref" : "walthandelsmanPref"},
{"class" : "GoComics.WitoftheWorld", "name" : "Editorial : Wit of the World", "pref" : "witoftheworldPref"},
{"class" : "GoComics.Twaggies", "name" : "Twaggies", "pref" : "twaggiesPref"},
{"class" : "GoComics.TheLostBear", "name" : "The Lost Bear", "pref" : "thelostbearPref"},
{"class" : "GoComics.ThatisPriceless", "name" : "That is Priceless", "pref" : "thatispricelessPref"},
{"class" : "GoComics.TenCats", "name" : "Ten Cats", "pref" : "tencatsPref"},
{"class" : "GoComics.TalesofTerraTopia", "name" : "Tales of Terra Topia", "pref" : "talesofterratopiaPref"},
{"class" : "GoComics.MotleyClassics", "name" : "Motley Classics", "pref" : "motleyclassicsPref"},
{"class" : "GoComics.ModestyBlaise", "name" : "Modesty Blaise", "pref" : "modestyblaisePref"},
{"class" : "GoComics.MagicinaMinute", "name" : "Magicina Minute", "pref" : "magicinaminutePref"},
{"class" : "GoComics.KidCity", "name" : "Kid City", "pref" : "kidcityPref"},
{"class" : "GoComics.HamShears", "name" : "Ham Shears", "pref" : "hamshearsPref"},
{"class" : "GoComics.GorDominical", "name" : "Gor Dominical", "pref" : "gordominicalPref"},
{"class" : "GoComics.Crumb", "name" : "Crumb", "pref" : "crumbPref"},
{"class" : "GoComics.Buni", "name" : "Buni", "pref" : "buniPref"},
{"class" : "GoComics.BreakofDay", "name" : "Break of Day", "pref" : "breakofdayPref"},
{"class" : "GoComics.BananaTriangle", "name" : "Banana Triangle", "pref" : "bananatrianglePref"},
{"class" : "GoComics.Annie", "name" : "Annie", "pref" : "anniePref"},
{"class" : "GoComics.AngryLittleGirls", "name" : "Angry Little Girls", "pref" : "angrylittlegirlsPref"},
{"class" : "GoComics.Andertoons", "name" : "Andertoons", "pref" : "andertoonsPref"},
{"class" : "GoComics.BiffnRiley", "name" : "Biff-and-Riley", "pref" : "biffandrileyPref"},
{"class" : "GoComics.GingerMeggsenEspanol", "name" : "Ginger Meggsen Espanol", "pref" : "gingermeggsenespanolPref"},
{"class" : "GoComics.InspectorDangersCrimeQuiz", "name" : "Inspector Dangers Crime Quiz", "pref" :"nspectordangerscrimequizPref"},
{"class" : "Channelate", "name" : "Channelate", "pref" : "channelatePref"},
{"class" : "ExtraOrdinary", "name" : "Extra Ordinary", "pref" : "extraOrdinaryPref"},
{"class" : "GoComics.Beardo", "name" : "Beardo", "pref" : "beardoPref"},
{"class" : "IrregularWebComic", "name" : "Irregular Web Comic", "pref" : "irregularWebComicPref"},
{"class" : "PbfComics", "name" : "PBF Comics", "pref" : "pbfComicsPref", new : "1" },
{"class" : "GoComics.MacComic", "name" : "Mac", "pref" : "macComicPref", new : "1" },
{"class" : "GoComics.DaltonDog", "name" : "Dalton Dog", "pref" : "daltonDogPref", new : "1" },
{"class" : "GoComics.BarkingCrayon", "name" : "Barking Crayon", "pref" : "barkingCrayonPref", new : "1" },
{"class" : "GoComics.KSquaredComics", "name" : "K Squared Comics", "pref" : "kSquaredComicsPref", new : "1" },
{"class" : "GoComics.AndNow", "name" : "And Now", "pref" : "andNowPref", new : "1" },
{"class" : "GoComics.MustardAndBolony", "name" : "Mustard And Bolony", "pref" : "mustardAndBolonyPref", new : "1" },
{"class" : "GoComics.NedAndLarry", "name" : "Ned And Larry", "pref" : "nedAndLarryPref", new : "1" },
{"class" : "AgentXComics", "name" : "Agent X Comics", "pref" : "agentXComicsPref", new : "1" }
]
}

36
ComicReader/proguard.cfg Executable file
View File

@ -0,0 +1,36 @@
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

11
ComicReader/project.properties Executable file
View File

@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-7

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="true"
android:drawable="@drawable/butt_pressed" />
<item android:state_focused="false" android:state_pressed="true"
android:drawable="@drawable/butt_pressed" />
<item android:drawable="@drawable/butt_unpressed" />
</selector>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:type="linear"
android:endColor="#688a00"
android:startColor="#688a00"
android:angle="270" />
</shape>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:type="linear"
android:startColor="#ff0000"
android:endColor="#222222"
android:angle="270" />
</shape>

BIN
ComicReader/res/drawable/icon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="true"
android:drawable="@drawable/left_pr" />
<item
android:drawable="@drawable/left_un" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="true"
android:drawable="@drawable/minus_pr" />
<item
android:drawable="@drawable/minus_un" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="true"
android:drawable="@drawable/plus_pr" />
<item
android:drawable="@drawable/plus_un" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="true"
android:drawable="@drawable/preview_press" />
<item android:state_focused="false" android:state_pressed="true"
android:drawable="@drawable/preview_press" />
<item android:drawable="@drawable/preview" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="true"
android:drawable="@drawable/reset_pr" />
<item
android:drawable="@drawable/reset_un" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="true"
android:drawable="@drawable/right_pr" />
<item
android:drawable="@drawable/right_un" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="true"
android:drawable="@drawable/share_pr" />
<item
android:drawable="@drawable/share_un" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:state_pressed="true"
android:drawable="@drawable/text_pr" />
<item
android:drawable="@drawable/text_un" />
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="false" android:drawable="@drawable/timepicker_down_normal" />
<item android:state_pressed="true" android:state_enabled="true"
android:drawable="@drawable/timepicker_down_pressed" />
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="true" android:drawable="@drawable/timepicker_down_selected" />
<item android:state_pressed="false" android:state_enabled="false"
android:state_focused="false" android:drawable="@drawable/timepicker_down_disabled" />
<item android:state_pressed="false" android:state_enabled="false"
android:state_focused="true" android:drawable="@drawable/timepicker_down_disabled_focused" />
</selector>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="false" android:drawable="@drawable/timepicker_input_normal" />
<item android:state_pressed="true" android:state_enabled="true"
android:drawable="@drawable/timepicker_input_pressed" />
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="true" android:drawable="@drawable/timepicker_input_selected" />
<item android:state_pressed="false" android:state_enabled="false"
android:state_focused="false" android:drawable="@drawable/timepicker_input_disabled" />
<item android:state_pressed="false" android:state_enabled="false"
android:state_focused="true" android:drawable="@drawable/timepicker_input_normal" />
</selector>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="false" android:drawable="@drawable/timepicker_up_normal" />
<item android:state_pressed="true" android:state_enabled="true"
android:drawable="@drawable/timepicker_up_pressed" />
<item android:state_pressed="false" android:state_enabled="true"
android:state_focused="true" android:drawable="@drawable/timepicker_up_selected" />
<item android:state_pressed="false" android:state_enabled="false"
android:state_focused="false" android:drawable="@drawable/timepicker_up_disabled" />
<item android:state_pressed="false" android:state_enabled="false"
android:state_focused="true" android:drawable="@drawable/timepicker_up_disabled_focused" />
</selector>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="3dip" >
<TextView
android:id="@+id/bg_cache_text"
android:text="@string/bg_cache_progress_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000" />
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:max="0"
android:progress="0"
android:layout_marginLeft="10dip"
android:id="@+id/bg_cache_progress_bar" />
</LinearLayout>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/my_comics_title" />
<ListView
android:id="@+id/main_list_view"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:fastScrollEnabled="true" />
</LinearLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:text="@string/empty_favorite_series"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:text="@string/comic_selector_save"
android:onClick="saveChangesAndExit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:text="@string/comic_selector_cancel"
android:onClick="cancelChangesAndExit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/comic_settings_title" />
<ListView
android:id="@+id/comic_settings_list_view"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:fastScrollEnabled="true" />
</LinearLayout>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:paddingRight="10dp"
android:paddingLeft="10dp"
android:paddingTop="1dp"
android:paddingBottom="1dp"
>
<TextView
android:id="@+id/comic_settings_item_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="16sp"
android:typeface="serif"
android:textStyle="bold"
android:layout_weight="1"
android:gravity="center_vertical"
android:lines="3"
android:textColor="#ffffff" />
<CheckBox
android:id="@+id/comic_settings_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp" />
<Button
android:id="@+id/comic_settings_item_preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/preview_back" />
</LinearLayout>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.blogspot.applications4android.comicreader.zoom.PanZoomView
android:id="@+id/image_viewer"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<Button
android:layout_alignParentTop="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/reset_button_text"
android:background="@drawable/reset"
android:textStyle="bold"
android:id="@+id/reset_button" />
<LinearLayout
android:id="@+id/view_control"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true" >
<Button
android:layout_marginRight="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/left"
android:id="@+id/strip_prev" />
<Button
android:layout_marginRight="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/text"
android:id="@+id/image_text" />
<Button
android:layout_marginRight="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/strip_favorite"
android:background="@drawable/star_nonfav"
android:text=" " />
<Button
android:layout_marginRight="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/strip_share"
android:background="@drawable/share" />
<Button
android:layout_marginRight="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/zoom_out_button"
android:background="@drawable/minus" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/zoom_in_button"
android:background="@drawable/plus" />
<Button
android:layout_marginRight="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/right"
android:id="@+id/strip_next" />
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:orientation="horizontal"
android:gravity="center_horizontal" >
<Button
android:id="@+id/comic_item_latest"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/butt"
android:lines="3"
android:layout_marginRight="1dp"
android:layout_gravity="fill"
android:typeface="serif"
android:textStyle="bold"
android:textColor="#ffffff"
android:gravity="center_vertical|center_horizontal" />
<Button
android:gravity="center_vertical|center_horizontal"
android:id="@+id/comic_item_prev"
android:layout_width="45dp"
android:layout_height="wrap_content"
android:text="Prev"
android:background="@drawable/butt"
android:lines="3"
android:typeface="serif"
android:textStyle="bold"
android:textColor="#ffffff"
android:layout_marginRight="1dp" />
<Button
android:gravity="center_vertical|center_horizontal"
android:id="@+id/comic_item_fav"
android:layout_width="45dp"
android:layout_height="wrap_content"
android:text="Fav"
android:background="@drawable/butt"
android:lines="3"
android:typeface="serif"
android:textStyle="bold"
android:textColor="#ffffff"
android:layout_marginRight="1dp" />
</LinearLayout>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical|center_horizontal" >
<com.blogspot.applications4android.comicreader.numpicker.NumberPickerButton
android:id="@+id/increment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/timepicker_up_btn" />
<EditText android:id="@+id/timepicker_input"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:singleLine="true"
style="?android:attr/textAppearanceLargeInverse"
android:textColor="@android:color/primary_text_light"
android:textSize="30sp"
android:background="@drawable/timepicker_input"
android:inputType="numberDecimal" />
<com.blogspot.applications4android.comicreader.numpicker.NumberPickerButton
android:id="@+id/decrement"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/timepicker_down_btn" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/numpicker_set"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="@string/number_picker_set_text" />
<Button
android:id="@+id/numpicker_cancel"
android:layout_width="110dp"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="@string/number_picker_cancel_text" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* Copyright (C) 2009 Michael Novak <mike@androidnerds.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip"
>
<com.example.widget.NumberPicker
android:id="@+id/pref_num_picker"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/web_viewer"
android:layout_height="fill_parent"
android:layout_width="fill_parent" />

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/ss_header" />
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/ss_location" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/ss_disclaimer" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/ss_ok"
android:text="OK"
android:onClick="saveStrip" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/ss_cancel"
android:text="Cancel"
android:onClick="cancelSaveStrip" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/select"
android:title="Select Comics" />
<item
android:id="@+id/settings"
android:title="Settings" />
<item
android:id="@+id/backup_favs"
android:title="Backup my list" />
<item
android:id="@+id/restore_favs"
android:title="Restore my list" />
<item
android:id="@+id/sync_now"
android:title="Sync now" />
<item
android:id="@+id/clear_all_cache"
android:title="Clear All Cache" />
<item
android:id="@+id/last_synced_time"
android:title="Last Synced" />
<item
android:id="@+id/share"
android:title="Share App" />
<item
android:id="@+id/disclaimer"
android:title="Disclaimer" />
<item
android:id="@+id/about"
android:title="About" />
<item
android:id="@+id/help"
android:title="Help" />
</menu>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/select_all"
android:title="Select All" />
<item
android:id="@+id/select_none"
android:title="Select None" />
<item
android:id="@+id/comic_request"
android:title="Comic Request" />
</menu>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/comic_first"
android:title="First" />
<item
android:id="@+id/comic_rand"
android:title="Random" />
<item
android:id="@+id/comic_latest"
android:title="Latest" />
<item
android:id="@+id/comic_select"
android:title="Select Strip" />
<item
android:id="@+id/comic_save"
android:title="Save Strip" />
<item
android:id="@+id/comic_clear_cache"
android:title="Clear Cache" />
</menu>

168
ComicReader/res/values/arrays.xml Executable file
View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="sync_type">
<item>Backwards from latest</item>
<item>Forward from previous session</item>
<item>Both</item>
</string-array>
<string-array name="sync_type_values">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="freq">
<item>1 (every 24 hrs)</item>
<item>2 (every 12 hrs)</item>
<item>3 (every 8 hrs)</item>
<item>4 (every 6 hrs)</item>
<item>6 (every 4 hrs)</item>
<item>8 (every 3 hrs)</item>
<item>12 (every 2 hrs)</item>
<item>24 (every hour!)</item>
<item>48 (every 30 mins!!)</item>
<item>96 (every 15 mins!!!)</item>
</string-array>
<string-array name="freq_values">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>6</item>
<item>8</item>
<item>12</item>
<item>24</item>
<item>48</item>
<item>96</item>
</string-array>
<string-array name="start_time">
<item>0 (12 am)</item>
<item>1 ( 1 am)</item>
<item>2 ( 2 am)</item>
<item>3 ( 3 am)</item>
<item>4 ( 4 am)</item>
<item>5 ( 5 am)</item>
<item>6 ( 6 am)</item>
<item>7 ( 7 am)</item>
<item>8 ( 8 am)</item>
<item>9 ( 9 am)</item>
<item>10 (10 am)</item>
<item>11 (11 am)</item>
<item>12 (12 pm)</item>
<item>13 ( 1 pm)</item>
<item>14 ( 2 pm)</item>
<item>15 ( 3 pm)</item>
<item>16 ( 4 pm)</item>
<item>17 ( 5 pm)</item>
<item>18 ( 6 pm)</item>
<item>19 ( 7 pm)</item>
<item>20 ( 8 pm)</item>
<item>21 ( 9 pm)</item>
<item>22 (10 pm)</item>
<item>23 (11 pm)</item>
</string-array>
<string-array name="start_time_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
<item>20</item>
<item>21</item>
<item>22</item>
<item>23</item>
</string-array>
<string-array name="num_cache">
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
<item>20</item>
</string-array>
<string-array name="num_cache_values">
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
<item>20</item>
</string-array>
<string-array name="select_sort_order">
<item>Alphabetical</item>
<item>Ignore Articles</item>
<item>Editorial at Last</item>
<item>New on Top</item>
<item>Selected on Top</item>
</string-array>
<string-array name="select_sort_order_values">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
</string-array>
<string-array name="my_sort_order">
<item>Alphabetical</item>
<item>Ignore Articles</item>
<item>Editorial at Last</item>
</string-array>
<string-array name="my_sort_order_values">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
</resources>

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Comic Reader</string>
<string name="my_comics_label">Comic Reader - My Comics</string>
<string name="select_comics_label">Comic Reader - Select Comics</string>
<string name="settings_label">Comic Reader - Settings</string>
<string name="share_header">ComicReader - A Great App</string>
<string name="ss_header">You are about to save this strip to</string>
<string name="my_comics_title">Select the comic to read the strips</string>
<string name="comic_settings_title">Click on the Comic to Add to My Comics</string>
<string name="my_comics_setup_msg">Getting the list of favorite comics....</string>
<string name="comics_selector_setup_msg">"Getting the list of all comics....</string>
<string name="comic_select_all_msg">Selecting all comics....</string>
<string name="comic_select_none_msg">Deselecting all comics....</string>
<string name="number_picker_set_text">Set</string>
<string name="number_picker_cancel_text">Cancel</string>
<string name="network_disconnected_message">ComicReader: Network disconnected, please connect to a network in order to continue reading comics</string>
<string name="network_connected_message">ComicReader: Network restored, enjoy reading your favorite comics!</string>
<string name="empty_favorite_series">\nNo comics selected.\n\nSelect comics from Menu -> Select Comics</string>
<string name="app_blog_url">https://market.android.com/details?id=com.blogspot.applications4android.comicreader</string>
<string name="dev_email">applications4android@gmail.com</string>
<string name="comic_request_msg">Hi,\n Please add the following comic(s) in this app:\n</string>
<string name="comic_request_subj">Comic Request</string>
<string name="comic_bug_report_subj">Comic Reader --- Bug Report</string>
<string name="reset_button_text">Traverse mode! Swipe left/right anywhere on the image to read next/previous strip. Swipe up/down to move to next/previous comic. Touch here to cancel.</string>
<string name="comic_selector_save">Save Changes</string>
<string name="comic_selector_cancel">Cancel</string>
<string name="comic_dnld_msg">Downloading the comic-strip....</string>
<string name="comic_clear_cache_msg">Clearing the comic cache....</string>
<string name="comic_cache_clean_confirmation">Are you sure you want to clean the comic\'s cache?</string>
<string name="comic_cache_clean_abort">Comic cache cleaning aborted</string>
<string name="clear_all_cache_success">Successfully cleaned all the caches of all comics!</string>
<string name="clear_all_cache_confirmation">Are you sure you want to clean the cache of all the comics?</string>
<string name="clear_all_cache_abort">All comic cache cleaning aborted</string>
<string name="recursive_folder_delete_msg">Deleting the directory....</string>
<string name="dnld_failed_msg">Network connection broken!\n\n 1. Please check your network connection and then press \'Retry\' to clear the cache and try again.\n\n 2. If the problem persists, then only please send us the bug-report and we\'ll look into it.</string>
<string name="sd_card_full_msg">Not enough space in SD-Card!\n\n 1. Please press \'OK\' to clear the cache and retry.\n\n 2. If this doesn\'t work then, please press \'Cancel\', goto sdcard and manually create space for ComicReader.</string>
<string name="my_comic_restore_confirmation">Are you sure you want to restore \'My Comics\' list?</string>
<string name="my_comic_restore_abort">Restoration of \'My Comics\' list aborted</string>
<string name="bg_cache_progress_msg">ComicReader: Syncing comics</string>
<string name="help_title">Welcome to ComicReader!</string>
<string name="help_msg">If you are facing any issues, look at out FAQs at: http://applications4android.blogspot.in/2012/02/version-2020-faqs.html\n\nFor info on how to use this app, refer to the \'Help\' page in Menu.\n\nCheck \'About Page\' in Menu to know what\'s new in this version.</string>
<string name="faq_url">http://applications4android.blogspot.in/2012/02/version-2020-faqs.html</string>
<string name="comic_bound_fetch_msg">Fetching the comic bound....</string>
</resources>

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="backgroundCacheEnabledPref"
android:title="Enable Caching"
android:summary="Enable caching in background for offline access"
android:defaultValue="true" />
<ListPreference
android:title="Cache Frequency"
android:summary="Number of times to sync in a day"
android:dependency="backgroundCacheEnabledPref"
android:key="backgroundCacheFreqPref"
android:defaultValue="4"
android:entries="@array/freq"
android:entryValues="@array/freq_values" />
<ListPreference
android:title="Cache Start Time"
android:summary="When does the first sync happen in a day (default is 6am)"
android:dependency="backgroundCacheEnabledPref"
android:key="backgroundCacheStartTimePref"
android:defaultValue="6"
android:entries="@array/start_time"
android:entryValues="@array/start_time_values" />
<CheckBoxPreference
android:key="mobileDataCacheEnabledPref"
android:title="Mobile network"
android:summary="Use mobile network for caching (if Wifi not available)"
android:defaultValue="false"
android:dependency="backgroundCacheEnabledPref" />
<ListPreference
android:key="numStripsCachePref"
android:title="Cache size"
android:summary="Number of strips to cache per comic"
android:defaultValue="3"
android:entries="@array/num_cache"
android:entryValues="@array/num_cache_values"
android:dependency="backgroundCacheEnabledPref" />
<ListPreference
android:key="syncTypePref"
android:title="Sync Type"
android:summary="Order of syncing the strips"
android:defaultValue="1"
android:entries="@array/sync_type"
android:entryValues="@array/sync_type_values"
android:dependency="backgroundCacheEnabledPref" />
<ListPreference
android:title="Sort (My Comics)"
android:summary="Sort Order in My Comics Page"
android:key="mySortPref"
android:defaultValue="1"
android:entries="@array/my_sort_order"
android:entryValues="@array/my_sort_order_values" />
<ListPreference
android:title="Sort (All Comics)"
android:summary="Sort Order in Select Comics Page"
android:key="selectSortPref"
android:defaultValue="1"
android:entries="@array/select_sort_order"
android:entryValues="@array/select_sort_order_values" />
</PreferenceScreen>

View File

@ -0,0 +1,492 @@
package com.blogspot.applications4android.comicreader;
import java.io.File;
import java.util.Calendar;
import com.blogspot.applications4android.comicreader.core.Cache;
import com.blogspot.applications4android.comicreader.core.Comic;
import com.blogspot.applications4android.comicreader.core.ComicActivity;
import com.blogspot.applications4android.comicreader.core.ComicClassList;
import com.blogspot.applications4android.comicreader.core.FileUtils;
import com.blogspot.applications4android.comicreader.core.IntentGen;
import com.blogspot.applications4android.comicreader.exceptions.ComicNotFoundException;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
/**
* Main activity which will displayed to the user.
* This will contain all the comic strips which the user can click to
* browse through them.
*/
public class ActivityComicReader extends ComicActivity {
/** for logging purposes only */
private static String TAG = "ComicReader";
/** location of the listview during the last time it was read */
private static final String ITEM_POSITION_PREF = "myComicsListViewPosPref";
/** pref-key for welcome message */
private static final String WELCOME_KEY = "welcomeMsg_1";
/** perf-key for first run */
private static final String FIRST_RUN = "firstRun_1";
/** list of comics */
protected static int[] mComicItems;
/** comic list */
protected static ComicClassList mList;
/** latest activity */
protected static LatestLauncher mLL = null;
/** favorites activity */
protected static FavoriteLauncher mFL = null;
/** prev-session activity */
protected static PrevSessionLauncher mPL = null;
/** sort type */
protected int mType;
/** to launch the strip viewer activity in latest mode */
private class LatestLauncher implements OnClickListener {
@Override
public void onClick(View v) {
Log.d(TAG, "LatestLauncher getting triggered...");
Intent i = new Intent();
i.setClass(ActivityComicReader.this, ComicStripViewer.class);
i.putExtra("title", (String)v.getTag());
i.putExtra("mode", Comic.TYPE_LATEST);
startActivityForResult(i, 0);
}
}
/** to launch the strip viewer activity in prev-session mode */
private class PrevSessionLauncher implements OnClickListener {
@Override
public void onClick(View v) {
Log.d(TAG, "PrevSessionLauncher getting triggered...");
Intent i = new Intent();
i.setClass(ActivityComicReader.this, ComicStripViewer.class);
i.putExtra("title", (String)v.getTag());
i.putExtra("mode", Comic.TYPE_PREV_SESSION);
startActivityForResult(i, 0);
}
}
/** to launch the strip viewer activity in favorite strips mode */
private class FavoriteLauncher implements OnClickListener {
@Override
public void onClick(View v) {
Log.d(TAG, "FavoriteLauncher getting triggered...");
Intent i = new Intent();
i.setClass(ActivityComicReader.this, ComicStripViewer.class);
i.putExtra("title", (String)v.getTag());
i.putExtra("mode", Comic.TYPE_FAVORITE);
startActivityForResult(i, 0);
}
}
/**
* adapter class for efficient traversal of list items displayed in the main activity
*/
private static class EfficientAdapter extends BaseAdapter {
/** Used to inflate the layout */
private LayoutInflater mInflater;
public EfficientAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mComicItems.length;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.main_listview_content, null);
holder = new ViewHolder();
holder.latest = (Button) convertView.findViewById(R.id.comic_item_latest);
holder.latest.setOnClickListener(mLL);
holder.favorite = (Button) convertView.findViewById(R.id.comic_item_fav);
holder.favorite.setOnClickListener(mFL);
holder.previous = (Button) convertView.findViewById(R.id.comic_item_prev);
holder.previous.setOnClickListener(mPL);
convertView.setTag(holder);
convertView.setBackgroundColor(mColor1);
}
else {
holder = (ViewHolder) convertView.getTag();
}
try {
String txt = mList.getComicClassFromIndex(mComicItems[position]).mName;
holder.latest.setText(txt);
holder.latest.setTag(txt);
holder.favorite.setTag(txt);
holder.previous.setTag(txt);
}
catch(ComicNotFoundException e) { // This should never occur!
e.printStackTrace();
}
return convertView;
}
/**
* A private class to hold the view which will be displayed in one row of the listview.
*/
static class ViewHolder {
/** Previous button*/
public Button previous;
/** Favorite button*/
public Button favorite;
/** Latest button*/
public Button latest;
}
}
@Override
protected void onResume() {
Log.d(TAG, "on resume...");
super.onResume();
if(mLL == null) {
mLL = new LatestLauncher();
}
if(mFL == null) {
mFL = new FavoriteLauncher();
}
if(mPL == null) {
mPL = new PrevSessionLauncher();
}
GetComicsTask get_task = new GetComicsTask();
get_task.execute((Void[])null);
}
@Override
protected void onPause() {
ListView l1 = (ListView) findViewById(R.id.main_list_view);
if(l1 != null) {
int last = l1.getFirstVisiblePosition();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor ed = sp.edit();
ed.putInt(ITEM_POSITION_PREF, last);
ed.commit();
}
try {
storeComicClassList(mList, true);
}
catch(Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
super.onPause();
Log.d(TAG, "on pause...");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inf = getMenuInflater();
inf.inflate(R.menu.comic_reader_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final Resources res = getResources();
Intent i = new Intent();
switch(item.getItemId()) {
case R.id.select:
i.setClass(ActivityComicReader.this, ActivityComicSelector.class);
startActivityForResult(i, 0);
return true;
case R.id.settings:
i.setClass(ActivityComicReader.this, ActivitySettingsPage.class);
startActivityForResult(i, 0);
return true;
case R.id.backup_favs:
{
String msg = "";
try {
mList.storeSelected();
File src = mList.selectedFile();
File dst = new File(FileUtils.getSdcard(), "backup_selected.json");
dst.delete();
if(FileUtils.copyFile(src, dst)) {
msg = "Successfully backed up 'My Comics' list to '" + dst.getPath() + "'";
}
else {
msg = "Failed to backup 'My Comics' list to '" + dst.getPath() + "'";
}
}
catch(Exception e) {
e.printStackTrace();
msg = "Failed to backup 'My Comics' list. Reason:" + e.getMessage();
}
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
return true;
case R.id.restore_favs:
{
final File dst = mList.selectedFile();
dst.delete();
final File src = new File(FileUtils.getSdcard(), "backup_selected.json");
AlertDialog.Builder alertbox = new AlertDialog.Builder(ActivityComicReader.this);
alertbox.setMessage(res.getString(R.string.my_comic_restore_confirmation));
alertbox.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(ActivityComicReader.this, res.getString(R.string.my_comic_restore_abort), Toast.LENGTH_LONG).show();
}
});
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
String msg;
if(FileUtils.copyFile(src, dst)) {
msg = "Successfully restored 'My Comics' list from '" + src.getPath() + "' to" + dst.getPath();
}
else {
msg = "Failed to restore 'My Comics' list from '" + src.getPath() + "'";
}
Toast.makeText(ActivityComicReader.this, msg, Toast.LENGTH_LONG).show();
GetComicsTask get_task = new GetComicsTask();
get_task.execute((Void[])null);
}
});
alertbox.show();
return true;
}
case R.id.sync_now:
_syncNow();
return true;
case R.id.clear_all_cache:
{
AlertDialog.Builder alertbox = new AlertDialog.Builder(ActivityComicReader.this);
alertbox.setMessage(res.getString(R.string.clear_all_cache_confirmation));
alertbox.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(ActivityComicReader.this, res.getString(R.string.clear_all_cache_abort), Toast.LENGTH_LONG).show();
}
});
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
FolderDeleteUpdater fdu = new FolderDeleteUpdater();
fdu.setActivity(ActivityComicReader.this);
fdu.setSuccessId(R.string.clear_all_cache_success);
fdu.execute(new File(FileUtils.getComicRoot(), Cache.CACHE),
new File(FileUtils.getComicRoot(), Comic.PROPS));
}
});
alertbox.show();
return true;
}
case R.id.last_synced_time:
{
AlertDialog.Builder alertbox = new AlertDialog.Builder(ActivityComicReader.this);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String last = sp.getString(ActivitySettingsPage.LAST_SYNC_STRING_PREF, "Never");
String msg = "Last synced on: " + last;
msg += "\n Press 'Sync' to forcefully retrieve the latest strips.";
alertbox.setMessage(msg);
alertbox.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertbox.setPositiveButton("Sync", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
_syncNow();
}
});
alertbox.show();
return true;
}
case R.id.disclaimer:
i.putExtra("page", "file:///android_asset/Disclaimer.html");
i.setClass(ActivityComicReader.this, ActivityPageViewer.class);
startActivityForResult(i, 0);
return true;
case R.id.about:
i.putExtra("page", "file:///android_asset/About.html");
i.setClass(ActivityComicReader.this, ActivityPageViewer.class);
startActivityForResult(i, 0);
return true;
case R.id.help:
i.putExtra("page", "file:///android_asset/Help.html");
i.setClass(ActivityComicReader.this, ActivityPageViewer.class);
startActivityForResult(i, 0);
return true;
case R.id.share:
ActivityComicReader.this.startActivity(
IntentGen.shareLinkChooserIntent(res.getString(R.string.share_header),
res.getString(R.string.app_blog_url),
"Share this app..."));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Helper function to initialize the list view containing all comics
* which the user wants to see. This will read the preferences set by
* the user in the settings activity.
* Also updates the callbacks for various UI elements in the activity
*/
protected void initListView() {
_showWelcomeMessage();
if((mComicItems == null) || (mComicItems.length == 0)) {
setContentView(R.layout.comic_reader_empty_list);
return;
}
setContentView(R.layout.comic_reader);
ListView l1 = (ListView) findViewById(R.id.main_list_view);
if(l1.getAdapter() == null) {
l1.setAdapter(new EfficientAdapter(this));
}
else {
EfficientAdapter ea = (EfficientAdapter) l1.getAdapter();
ea.notifyDataSetChanged();
}
ColorDrawable divcolor = new ColorDrawable(Color.WHITE);
l1.setDivider(divcolor);
l1.setDividerHeight(1);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
int last = sp.getInt(ITEM_POSITION_PREF, 0);
l1.setSelection(last);
if(ActivitySettingsPage.checkForLastSynced(getApplicationContext())) {
_syncNow();
}
}
/**
* Things to be performed when running for the first time
*/
private void _firstRun() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if(!sp.getBoolean(FIRST_RUN, true)) {
return;
}
Log.d(TAG, "Running this app for the first time!");
ActivitySettingsPage.setupDefaults(this);
SharedPreferences.Editor e = sp.edit();
e.putBoolean(FIRST_RUN, false);
e.commit();
}
/**
* Display a welcome message for the first time users!
*/
private void _showWelcomeMessage() {
_firstRun();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
final SharedPreferences.Editor e = sp.edit();
ActivitySettingsPage.launchRepeatedCaching(this, true);
if(!sp.getBoolean(WELCOME_KEY, true)) {
return;
}
AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
alertbox.setTitle(getResources().getString(R.string.help_title));
alertbox.setMessage(getResources().getString(R.string.help_msg));
alertbox.setPositiveButton("Show Again", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
e.putBoolean(FIRST_RUN, false);
e.putBoolean(WELCOME_KEY, true);
e.commit();
}
});
alertbox.setNeutralButton("Go to FAQs", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
String url = ActivityComicReader.this.getResources().getString(R.string.faq_url);
ActivityComicReader.this.startActivity(IntentGen.linkViewIntent(url));
}
});
alertbox.setNegativeButton("Don't Show", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
e.putBoolean(FIRST_RUN, false);
e.putBoolean(WELCOME_KEY, false);
e.commit();
}
});
alertbox.show();
}
/**
* Sync now
*/
private void _syncNow() {
Log.d(TAG, "Syncing starting now...");
Intent i = new Intent();
i.setClass(this, SyncNowReciever.class);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0);
AlarmManager mgr = (AlarmManager) getSystemService(ALARM_SERVICE);
mgr.set(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(), pi);
}
/**
* Asynctask responsible for getting the list of comics
*/
private class GetComicsTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog m_pdia;
private Exception mExp = null;
@Override
protected void onPreExecute() {
m_pdia = new ProgressDialog(ActivityComicReader.this);
m_pdia.setCancelable(true);
m_pdia.setMessage(getResources().getString(R.string.my_comics_setup_msg));
m_pdia.show();
}
@Override
protected Void doInBackground(Void... params) {
try {
mList = setupComicsList("mySortPref");
mComicItems = mList.getSelectedComicList();
}
catch(Exception e) {
mExp = e;
}
return null;
}
@Override
protected void onProgressUpdate(Void... arg0) {
}
@Override
protected void onPostExecute(Void arg0) {
if(mExp != null) {
mExp.printStackTrace();
Toast.makeText(getApplicationContext(), "Failed to 'setupComicsList'! Reason: "+mExp.getMessage(), Toast.LENGTH_LONG).show();
}
initListView();
m_pdia.dismiss();
}
};
}

View File

@ -0,0 +1,359 @@
package com.blogspot.applications4android.comicreader;
import com.blogspot.applications4android.comicreader.core.Comic;
import com.blogspot.applications4android.comicreader.core.ComicActivity;
import com.blogspot.applications4android.comicreader.core.ComicClass;
import com.blogspot.applications4android.comicreader.core.ComicClassList;
import com.blogspot.applications4android.comicreader.core.IntentGen;
import com.blogspot.applications4android.comicreader.exceptions.ComicNotFoundException;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
/**
* Activity to select your favorite comics
*/
public class ActivityComicSelector extends ComicActivity {
/** for logging purposes only */
private static final String TAG = "ComicSelector";
/** location of the listview during the last time it was read */
private static final String ITEM_POSITION_PREF = "selectComicsListViewPosPref";
/** comic list */
protected static ComicClassList mList;
/** preview activity */
protected static PreviewLauncher mPL = null;
/** web page display activity */
protected static ComicMainWebPageDisplay mWP = null;
/** sort type */
protected int mType;
/** whether or not to store the comic class list */
private boolean mStoreList = true;
/** to launch the strip viewer activity in preview mode */
private class PreviewLauncher implements OnClickListener {
@Override
public void onClick(View v) {
Log.d(TAG, "PreviewLauncher getting triggered...");
Intent i = new Intent();
i.setClass(ActivityComicSelector.this, ComicStripViewer.class);
i.putExtra("title", (String)v.getTag());
i.putExtra("mode", Comic.TYPE_PREVIEW);
startActivityForResult(i, 0);
}
}
/** to launch the alertdialog for opening the comic in a web page */
private class ComicMainWebPageDisplay implements OnLongClickListener {
public boolean onLongClick(View v) {
String title = (String) v.getTag();
try {
Comic c = mList.getComicFromTitle(title);
if(c == null) {
Log.e(TAG, "no comic found for title="+title);
return false;
}
final String url = c.getComicWebPageUrl();
AlertDialog.Builder alertbox = new AlertDialog.Builder(ActivityComicSelector.this);
alertbox.setMessage("Visit website of '" + title + "'?");
alertbox.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
ActivityComicSelector.this.startActivity(IntentGen.linkViewIntent(url));
}
});
alertbox.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
}
});
alertbox.show();
return true;
}
catch(Exception e) {
e.printStackTrace();
return false;
}
}
}
/**
* adapter class for efficient traversal of list items displayed in the main activity
*/
public static class EfficientAdapter extends BaseAdapter {
/** Used to inflate the layout */
private LayoutInflater mInflater;
public EfficientAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mList.length();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.comic_selector_listview_content, null);
holder = new ViewHolder();
// comic select checkbox
OnClickListener ocl = new OnClickListener() {
public void onClick(View v) {
try {
int pos = (Integer) v.getTag();
mList.toggleSelected(pos);
}
catch (ComicNotFoundException e) {
e.printStackTrace();
}
notifyDataSetChanged();
}
};
holder.text_name = (TextView) convertView.findViewById(R.id.comic_settings_item_name);
holder.text_name.setOnLongClickListener(mWP);
holder.sel = (CheckBox) convertView.findViewById(R.id.comic_settings_item);
holder.sel.setOnClickListener(ocl);
holder.preview = (Button) convertView.findViewById(R.id.comic_settings_item_preview);
holder.preview.setOnClickListener(mPL);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
try {
ComicClass clz = mList.getComicClassFromIndex(position);
holder.text_name.setText(clz.mName);
holder.text_name.setTag(clz.mName);
holder.sel.setChecked(clz.mSel);
holder.sel.setTag(position);
holder.preview.setTag(clz.mName);
}
catch(ComicNotFoundException e) {
e.printStackTrace();
}
convertView.setBackgroundColor((position & 1) == 1 ? mColor1 : mColor2);
return convertView;
}
/**
* A private class to hold the view which will be displayed in one row of the listview.
*/
static class ViewHolder {
/** stores and displays the comic name */
TextView text_name;
/** whether this comic is selected or not */
CheckBox sel;
/** preview button */
Button preview;
}
}
@Override
protected void onResume() {
Log.d(TAG, "on resume...");
super.onResume();
if(mPL == null) {
mPL = new PreviewLauncher();
}
if(mWP == null) {
mWP = new ComicMainWebPageDisplay();
}
GetAllComicsTask get_task = new GetAllComicsTask();
get_task.execute((Void[])null);
}
@Override
protected void onPause() {
super.onPause();
try {
storeComicClassList(mList, mStoreList);
}
catch(Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
ListView l1 = (ListView) findViewById(R.id.comic_settings_list_view);
int last = l1.getFirstVisiblePosition();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor ed = sp.edit();
ed.putInt(ITEM_POSITION_PREF, last);
ed.commit();
Log.d(TAG, "on pause...");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inf = getMenuInflater();
inf.inflate(R.menu.comic_selector_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Resources res = getResources();
switch(item.getItemId()) {
case R.id.select_all:
SelectAllComics sac = new SelectAllComics();
sac.setMessage(res.getString(R.string.comic_select_all_msg));
sac.execute(true);
return true;
case R.id.select_none:
SelectAllComics dac = new SelectAllComics();
dac.setMessage(res.getString(R.string.comic_select_none_msg));
dac.execute(false);
return true;
case R.id.comic_request:
String msg = res.getString(R.string.comic_request_msg);
String[] email = new String[] { res.getString(R.string.dev_email) };
String subj = res.getString(R.string.comic_request_subj);
Intent i = IntentGen.emailChooserIntent(email, subj, msg, false, "Send request...");
ActivityComicSelector.this.startActivity(i);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* Callback for the button to save changes and exit this activity
* @param v button
*/
public void saveChangesAndExit(View v) {
finish();
}
/**
* Callback for the button to cancel the changes made and exit this activity
* @param v button
*/
public void cancelChangesAndExit(View v) {
mStoreList = false;
finish();
}
/**
* Helper function to initialize the list view containing all comics
* which the user wants to see. This will read the preferences set by
* the user in the settings activity.
* Also updates the callbacks for various UI elements in the activity
*/
protected void initListView() {
setContentView(R.layout.comic_selector);
ListView l1 = (ListView) findViewById(R.id.comic_settings_list_view);
l1.setAdapter(new EfficientAdapter(this));
ColorDrawable divcolor = new ColorDrawable(Color.WHITE);
l1.setDivider(divcolor);
l1.setDividerHeight(1);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
int last = sp.getInt(ITEM_POSITION_PREF, 0);
l1.setSelection(last);
}
/**
* Async task for selecting/deselecting all comics.
*/
private class SelectAllComics extends AsyncTask<Boolean, Void, Void> {
private ProgressDialog mPdiag;
private String mMsg;
public void setMessage(String msg) {
mMsg = msg;
}
@Override
protected void onPreExecute() {
mPdiag = new ProgressDialog(ActivityComicSelector.this);
mPdiag.setCancelable(false);
mPdiag.setMessage(mMsg);
mPdiag.show();
}
@Override
protected Void doInBackground(Boolean... params) {
mList.setAllSelected(params[0]);
return null;
}
@Override
protected void onProgressUpdate(Void... arg0) {
}
@Override
protected void onPostExecute(Void arg0) {
mPdiag.dismiss();
ListView l1 = (ListView) findViewById(R.id.comic_settings_list_view);
EfficientAdapter ea = (EfficientAdapter) l1.getAdapter();
ea.notifyDataSetChanged();
}
}
/**
* Asynctask responsible for getting the list of comics
*/
private class GetAllComicsTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog mPdiag;
private Exception mExp = null;
@Override
protected void onPreExecute() {
mPdiag = new ProgressDialog(ActivityComicSelector.this);
mPdiag.setCancelable(true);
mPdiag.setMessage(getResources().getString(R.string.comics_selector_setup_msg));
mPdiag.show();
}
@Override
protected Void doInBackground(Void... params) {
try {
mList = setupComicsList("selectSortPref");
}
catch(Exception e) {
mExp = e;
}
return null;
}
@Override
protected void onProgressUpdate(Void... arg0) {
}
@Override
protected void onPostExecute(Void arg0) {
if(mExp != null) {
mExp.printStackTrace();
Toast.makeText(getApplicationContext(), "Failed to 'setupComicsList'! Reason: "+mExp.getMessage(), Toast.LENGTH_LONG).show();
}
initListView();
mPdiag.dismiss();
}
};
}

View File

@ -0,0 +1,26 @@
package com.blogspot.applications4android.comicreader;
import com.blogspot.applications4android.comicreader.core.ComicActivity;
import android.os.Bundle;
/**
* Generic activity to display only a webview widget.
* To display a html page, just pass it in the 'extras' bundle
* under the key named 'page'.
*/
public class ActivityPageViewer extends ComicActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if(extras != null) {
String page = extras.getString("page");
displayHtml(R.layout.page_viewer, R.id.web_viewer, page);
}
}
}

View File

@ -0,0 +1,93 @@
package com.blogspot.applications4android.comicreader;
import java.io.File;
import com.blogspot.applications4android.comicreader.core.FileUtils;
import android.app.Activity;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
/**
* Activity to save the strip onto sdcard on user's request
* Pass the source file in 'src_file' and destination in 'dest_file'
*/
public class ActivitySaveStrip extends Activity {
/** file where to save the strip */
private String mDestFile;
/** file from where to save the strip */
private String mSrcFile;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.save_strip);
Bundle extras = getIntent().getExtras();
if(extras != null) {
mSrcFile = extras.getString("src_file");
mDestFile = extras.getString("dest_file");
}
else {
Toast.makeText(getApplicationContext(),
"You did not pass 'file' in the extras for this intent!",
Toast.LENGTH_SHORT).show();
finish();
}
TextView dis = (TextView) findViewById(R.id.ss_disclaimer);
dis.setText(_getDisclaimer());
EditText et = (EditText) findViewById(R.id.ss_location);
et.setText(mDestFile);
}
/**
* Callback for saving the strip
* @param v view which is calling back
*/
public void saveStrip(View v) {
EditText et = (EditText) findViewById(R.id.ss_location);
mDestFile = et.getText().toString();
File src = new File(mSrcFile);
File dest = new File(mDestFile);
String msg;
if(FileUtils.copyFile(src, dest)) {
msg = "Successfully saved the strip to '"+mDestFile+"'";
}
else {
msg = "Failed to store the strip to '"+mDestFile+"'";
}
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
finish();
}
/**
* Callback for cancelling saving the strip
* @param v view which is calling back
*/
public void cancelSaveStrip(View v) {
String msg = "Save strip has been cancelled";
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
finish();
}
/**
* Returns the disclaimer associated with saving the strips
* @return disclaimer as html formatted string
*/
private Spanned _getDisclaimer() {
StringBuilder sb = new StringBuilder();
sb.append("<b>DISCLAIMER:</b><br>");
sb.append("1. Authors of this app are not the authors of this strip.<br>");
sb.append("2. Authors of this app are in no way responsible for misusing the strips saved from here.<br>");
sb.append("3. Strips saved from here are for personal use only.<br>");
sb.append("4. By pressing 'OK' below, you are agreeing to the above points.<br>");
sb.append("5. By pressing 'OK' below, you are agreeing to the copyright/licenses associated with this strip.<br>");
Spanned data = Html.fromHtml(sb.toString());
return data;
}
}

View File

@ -0,0 +1,121 @@
package com.blogspot.applications4android.comicreader;
import java.util.Calendar;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.util.Log;
/**
* Main class for comic-reader settings
*/
public class ActivitySettingsPage extends PreferenceActivity {
/** for logging purposes only */
private static final String TAG = "ComicReaderSettings";
/** milliseconds in a day */
public static final long ONE_DAY = 24 * 60 * 60 * 1000;
/** key storing the last time synced */
public static final String LAST_SYNC_PREF = "lastTimeSyncedPref";
/** key storing the last time synced as a string */
public static final String LAST_SYNC_STRING_PREF = "lastTimeSyncedStringPref";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
protected void onPause() {
launchRepeatedCaching(this, false);
super.onPause();
}
/**
* Sets up the default values for background caching
* @param act activity calling this function
*/
public static void setupDefaults(Activity act) {
Log.d(TAG, "Setting up the default values for ComicReader...");
Context ctx = act.getApplicationContext();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(ctx);
SharedPreferences.Editor e = sp.edit();
e.putBoolean("backgroundCacheEnabledPref", true);
e.putString("backgroundCacheFreqPref", "4");
e.putString("numStripsCachePref", "3");
e.commit();
}
/**
* Start/setup the caching service
* @param ctx context used
* @param force forcefully setup the alarm even if background caching is currently disabled
* This will NOT cache the strips, but'll only setup the alarm
*/
public static void launchRepeatedCaching(Context ctx, boolean force) {
Intent i = new Intent(ctx, BackgroundCacheReciever.class);
PendingIntent pi = PendingIntent.getBroadcast(ctx, 0, i, 0);
AlarmManager mgr = (AlarmManager) ctx.getSystemService(ALARM_SERVICE);
Log.d(TAG, "Cancelling the previous alarm...");
mgr.cancel(pi);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(ctx);
if(!sp.getBoolean("backgroundCacheEnabledPref", false) && !force) {
Log.d(TAG, "Caching disabled. Returning back...");
return;
}
int hour = Integer.parseInt(sp.getString("backgroundCacheStartTimePref", "6"));
int cacheFreq = Integer.parseInt(sp.getString("backgroundCacheFreqPref", "1"));
long interval = ONE_DAY / cacheFreq;
Calendar cal = Calendar.getInstance();
long now = System.currentTimeMillis();
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
long sixAm = cal.getTimeInMillis();
long gap = now - sixAm;
if(gap < 0) {
cal.add(Calendar.DAY_OF_MONTH, -1);
sixAm = cal.getTimeInMillis();
gap = now - sixAm;
}
long next = ((gap / interval) + 1) * interval;
next += sixAm;
long diff = next - now;
Log.d(TAG, "Alarm for interval="+interval+" firstTime="+next+" now="+now+" diff="+diff);
mgr.setRepeating(AlarmManager.RTC_WAKEUP, next, interval, pi);
return;
}
/**
* Checks when was the last time sync was performed
* @param ctx context
* @return true if there needs to be a sync to be performed now
*/
public static boolean checkForLastSynced(Context ctx) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(ctx);
long last = sp.getLong(LAST_SYNC_PREF, 0);
long now = System.currentTimeMillis();
long diff = now - last;
long freq = Long.parseLong(sp.getString("backgroundCacheFreqPref", "1"));
freq = ActivitySettingsPage.ONE_DAY / freq;
if(diff > freq) {
Log.d(TAG, "lastsynced="+last+" now="+now+" diff="+diff+" freq="+freq+". So syncing now...");
return true;
}
else {
Log.d(TAG, "lastsynced="+last+" now="+now+" diff="+diff+" freq="+freq+". So NOT syncing now...");
return false;
}
}
}

View File

@ -0,0 +1,23 @@
package com.blogspot.applications4android.comicreader;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
* Receives the on-boot complete
*/
public class BackgroundCacheBootReciever extends BroadcastReceiver {
/** for logging purposes only */
private final static String TAG = "BGCacheOnBootComplete";
@Override
public void onReceive(Context arg0, Intent arg1) {
Log.d(TAG, "On Boot complete received. Setting up the alarm...");
ActivitySettingsPage.launchRepeatedCaching(arg0, false);
}
}

View File

@ -0,0 +1,357 @@
package com.blogspot.applications4android.comicreader;
import java.util.Calendar;
import com.blogspot.applications4android.comicreader.R;
import com.blogspot.applications4android.comicreader.core.Comic;
import com.blogspot.applications4android.comicreader.core.ComicClass;
import com.blogspot.applications4android.comicreader.core.ComicClassList;
import com.blogspot.applications4android.comicreader.core.FullyAwakeIntentService;
import com.blogspot.applications4android.comicreader.core.Strip;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
/**
* Actual class for background caching
*/
public class BackgroundCacheIntentService extends FullyAwakeIntentService {
/** for logging purposes only */
private static final String TAG = "BackgroundCache";
/** sync backwards from latest */
public static final int SYNC_FROM_LATEST = 1;
/** sync forwards from previous session */
public static final int SYNC_FROM_PREV_SESSION = 2;
/** both the above */
public static final int SYNC_BOTH = 3;
/** id for notification manager */
private static final int NOTIFY_ID = 123456;
/** id for notification manager for sync progress */
private static final int PROGRESS_NOTIFY_ID = 456789;
/** sleep duration in await of wifi (in ms) */
private static long SLEEP_DURATION = 45000;
/** sync type */
private int mSyncType;
/** sort type */
private int mSortType;
/** number of strips to be cached for each comic */
private int mNumStrips;
/** number of strips actually downloaded */
private int mNumDnlds;
/** context */
private Context mCtx;
/** notificatio */
private Notification mNotify;
/** class list */
private ComicClassList mList;
/** total number of strips to be downloaded */
private int mTotal;
/** number of strips checked so far */
private int mChecked;
/** notification manager */
private NotificationManager mMgr;
/** progress message */
private String mStr;
/**
* Constructor
*/
public BackgroundCacheIntentService() {
super(TAG);
}
@Override
protected void doWork(Intent intent) {
_mutexCall();
}
/**
* Waits for connectivity to come up
*/
private void _waitForConnectivity() {
if(!_isOnWifi(mCtx) && !_isOnMobileData(mCtx)) {
Log.d(TAG, "Sleeping for "+SLEEP_DURATION+" ms hoping that the network will turn on...");
try {
Thread.sleep(SLEEP_DURATION);
}
catch(Exception e) {
e.printStackTrace();
}
Log.d(TAG, "Sleeping is over...");
}
}
/**
* This sync should be run mutually exclusively!
*/
synchronized private void _mutexCall() {
mCtx = getApplicationContext();
Log.d(TAG, "starting the service for caching comic strips in background ...");
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mCtx);
if(!sp.getBoolean("backgroundCacheEnabledPref", false)) {
Log.d(TAG, "Background caching not enabled. Returing back...");
return;
}
_waitForConnectivity();
if(_isOnWifi(mCtx)) {
_cacheStrips(sp);
}
else if(_isOnMobileData(mCtx)) {
if(sp.getBoolean("mobileDataCacheEnabledPref", false)) {
_cacheStrips(sp);
}
else {
Log.d(TAG, "You're on mobile-data, but caching is disabled on this network. So, returning back...");
}
}
else {
Log.d(TAG, "No wifi + no mobile-data. So, returing back...");
}
Log.d(TAG, "background comic cache service ended ...");
}
/**
* Callback for cancelling this progress
* @param v view generating this callback
*/
public void onCancelClick(View v) {
final Resources res = mCtx.getResources();
AlertDialog.Builder alertbox = new AlertDialog.Builder(mCtx);
alertbox.setMessage(res.getString(R.string.my_comic_restore_confirmation));
alertbox.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
stopSelf();
mMgr.cancel(PROGRESS_NOTIFY_ID);
}
});
}
/**
* Caching the strips
* @param sp shared preferences
*/
private void _cacheStrips(SharedPreferences sp) {
mSortType = Integer.parseInt(sp.getString("mySortPref", Integer.toString(ComicClassList.SORT_ALPHABETICAL)));
mNumStrips = Integer.parseInt(sp.getString("numStripsCachePref", "5"));
mSyncType = Integer.parseInt(sp.getString("syncTypePref", Integer.toString(SYNC_FROM_LATEST)));
Log.d(TAG, "Setting up the progress bar for notifying sync updates...");
try {
mList = new ComicClassList(mCtx.getAssets());
}
catch(Exception e) {
e.printStackTrace();
return;
}
mMgr = (NotificationManager) mCtx.getSystemService(Context.NOTIFICATION_SERVICE);
mTotal = mList.numSelected() * mNumStrips;
if(mSyncType == SYNC_BOTH) {
mTotal *= 2;
}
mChecked = 0;
mStr = mCtx.getResources().getString(R.string.bg_cache_progress_msg);
mNotify = new Notification(R.drawable.icon, "ComicReader", System.currentTimeMillis());
Intent in = new Intent(mCtx, ActivityComicReader.class);
mNotify.contentIntent = PendingIntent.getActivity(mCtx, 0, in, 0);
mNotify.contentView = new RemoteViews(mCtx.getPackageName(), R.layout.bg_cache_progress);
mNotify.flags = Notification.FLAG_ONGOING_EVENT;
_updateProgress();
try {
mNumDnlds = 0;
mList.sortClasses(mSortType);
int num = mList.length();
for(int i=0;i<num;++i) {
ComicClass clz = mList.getComicClassFromIndex(i);
if(!clz.mSel) {
continue;
}
Log.d(TAG, "Working on comic = "+clz.mName);
Comic com = mList.getComicFromIndex(i);
com.setComicName(clz.mName);
com.readProperties();
com.setLaunchType(Comic.TYPE_CACHING);
boolean status = _syncAcomic(com, mNumStrips, mSyncType);
com.writeProperties();
Log.d(TAG, "Finished working on comic = "+clz.mName+" status="+status);
Log.d(TAG, "Number of downloads so far="+mNumDnlds);
}
}
catch(Exception e) {
mMgr.cancel(PROGRESS_NOTIFY_ID);
e.printStackTrace();
}
mMgr.cancel(PROGRESS_NOTIFY_ID);
if(mNumDnlds <= 0) {
Log.d(TAG, "No new strips to be read. So, not setting up a notification...");
_commitLastSyncTime();
return;
}
Intent i = new Intent(mCtx, ActivityComicReader.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(mCtx, 0, i, 0);
mNotify = new Notification(R.drawable.icon, "ComicReader", System.currentTimeMillis());
mNotify.flags = Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
mNotify.setLatestEventInfo(mCtx, "Comic Reader", "Total of "+mNumDnlds+" newly downloaded strips", pi);
Log.d(TAG, "Notifying the manager of this new notification...");
mMgr.notify(NOTIFY_ID, mNotify);
_commitLastSyncTime();
}
/**
* Store the last sync time
*/
private void _commitLastSyncTime() {
long lastSync = System.currentTimeMillis();
Log.d(TAG, "last sync time = "+lastSync);
SharedPreferences.Editor ed = PreferenceManager.getDefaultSharedPreferences(mCtx).edit();
ed.putLong(ActivitySettingsPage.LAST_SYNC_PREF, lastSync);
Calendar now = Calendar.getInstance();
int mon = now.get(Calendar.MONTH) + 1;
String str = "'" + now.get(Calendar.YEAR) + "/" + mon + "/" + now.get(Calendar.DAY_OF_MONTH);
str += " " + now.get(Calendar.HOUR_OF_DAY) + ":" + now.get(Calendar.MINUTE) + ":" + now.get(Calendar.SECOND) + "'";
ed.putString(ActivitySettingsPage.LAST_SYNC_STRING_PREF, str);
ed.commit();
}
/**
* Helper function to check whether we are on WIFI or not
* @param ctxt application context
* @return true if we are
*/
private boolean _isOnWifi(Context ctxt) {
ConnectivityManager cm = (ConnectivityManager) ctxt.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifi = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return wifi.isConnected();
}
/**
* Helper function to check whether we are on Mobile-data or not
* @param ctxt application context
* @return true if we are
*/
private boolean _isOnMobileData(Context ctxt) {
ConnectivityManager cm = (ConnectivityManager) ctxt.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobile = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
return mobile.isConnected();
}
/**
* Updates the view for progress bar
*/
private void _updateProgress() {
++mChecked;
RemoteViews view = mNotify.contentView;
view.setProgressBar(R.id.bg_cache_progress_bar, mTotal, mChecked, false);
String s = mStr + " (" + mChecked + " of " + mTotal + ")";
view.setTextViewText(R.id.bg_cache_text, s);
mMgr.notify(PROGRESS_NOTIFY_ID, mNotify);
}
/**
* Syncs for a comic
* @param com comic
* @param numStrips number of strips to be synced
* @param sType sync type
* @return true if the sync succeeded
*/
private boolean _syncAcomic(Comic com, int numStrips, int sType) {
switch(sType) {
case SYNC_FROM_LATEST:
return _syncFromLatest(com, numStrips);
case SYNC_FROM_PREV_SESSION:
return _syncFromPrevSession(com, numStrips);
case SYNC_BOTH:
return _syncBoth(com, numStrips);
default:
Log.e(TAG, "Bad sync type passed! ("+sType+")");
return false;
}
}
/**
* Syncs for a comic from latest strip onwards
* @param com comic
* @param numStrips number of strips to be synced
* @return true if the sync succeeded
*/
private boolean _syncFromLatest(Comic com, int numStrips) {
if(!_getStrip(com, Comic.NAV_LATEST_FORCE)) {
return false;
}
boolean status = true;
for(int i=1;i<numStrips;++i) {
status = status && _getStrip(com, Comic.NAV_PREVIOUS);
}
return status;
}
/**
* Syncs for a comic from previous session strip onwards
* @param com comic
* @param numStrips number of strips to be synced
* @return true if the sync succeeded
*/
private boolean _syncFromPrevSession(Comic com, int numStrips) {
if(!_getStrip(com, Comic.NAV_PREV_SESSION)) {
return false;
}
boolean status = true;
for(int i=1;i<numStrips;++i) {
status = status && _getStrip(com, Comic.NAV_NEXT);
}
return status;
}
/**
* Syncs for a comic from both latest strip onwards and previous session strip onwards
* @param com comic
* @param numStrips number of strips to be synced in each direction
* @return true if the sync succeeded
*/
private boolean _syncBoth(Comic com, int numStrips) {
return (_syncFromLatest(com, numStrips) && _syncFromPrevSession(com, numStrips));
}
/**
* Helper function to download the strip
* @param com comic
* @param type strip type
* @return true if download is successful
*/
private boolean _getStrip(Comic com, int type) {
try {
Strip s = com.navigateStrip(type);
if(s.downloadImage(com)) {
mNumDnlds++;
}
_updateProgress();
return true;
}
catch(Exception e) {
e.printStackTrace();
return false;
}
}
}

View File

@ -0,0 +1,26 @@
package com.blogspot.applications4android.comicreader;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
* Receives the alarm-off broadcast event and starts a fully-awake intent service
*/
public class BackgroundCacheReciever extends BroadcastReceiver {
/** for logging purposes only */
private static final String TAG = "BgCacheReceiver";
@Override
public void onReceive(Context arg0, Intent arg1) {
Log.d(TAG, "BackgroundCacheReciever has started...");
BackgroundCacheIntentService.acquireStaticLock(arg0);
Intent i = new Intent(arg0, BackgroundCacheIntentService.class);
arg0.startService(i);
Log.d(TAG, "BackgroundCacheReciever has ended...");
}
}

View File

@ -0,0 +1,78 @@
package com.blogspot.applications4android.comicreader;
import com.blogspot.applications4android.comicreader.R;
import com.blogspot.applications4android.comicreader.core.Comic;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.util.Log;
/**
* Class responsible for downloading the comic-strip while displaying a progress dialog
*/
public class ClearCacheUpdater extends AsyncTask<Comic, Void, Void> {
/** for logging purposes */
private static final String TAG = "ClearCacheUpdater";
/** progress dialog to be shown in case of downloading a new strip */
private ProgressDialog mPdiag;
/** activity */
private ComicStripViewer mMain;
/** navigation type */
private int mType;
/**
* Set the activity
* @param a activity
*/
public void setActivity(ComicStripViewer a) {
mMain = a;
}
/**
* Navigation type
* @param type type
*/
public void setType(int type) {
mType = type;
}
@Override
protected Void doInBackground(Comic... arg0) {
try {
Comic c = arg0[0];
c.clearCache();
c.clearHistory();
return null;
}
catch(Exception e) {
Log.e(TAG, "doInBackground failed: "+e);
e.printStackTrace();
return null;
}
}
@Override
protected void onPreExecute() {
mPdiag = new ProgressDialog(mMain);
mPdiag.setCancelable(true);
mPdiag.setMessage(mMain.getResources().getString(R.string.comic_clear_cache_msg));
mPdiag.show();
}
@Override
protected void onPostExecute(Void arg0) {
if(mType > 0) {
mMain.displayStrip(mType);
}
if(mPdiag.isShowing()) {
mPdiag.dismiss();
}
}
@Override
protected void onProgressUpdate(Void... arg0) {
}
}

View File

@ -0,0 +1,166 @@
package com.blogspot.applications4android.comicreader;
import com.blogspot.applications4android.comicreader.R;
import com.blogspot.applications4android.comicreader.core.AppInfo;
import com.blogspot.applications4android.comicreader.core.IntentGen;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.util.Log;
/**
* Class responsible for updating the 'bound' for the current comic
*/
public class ComicBoundUpdater extends AsyncTask<Void, Void, Void> {
/** for logging purposes */
private static final String TAG = "ComicBoundUpdater";
/** progress dialog to be shown in case of downloading a new strip */
private ProgressDialog mPdiag;
/** activity upon which to display the progress */
private ComicStripViewer mMain;
/** exception thrown by doInBackground */
private Exception mExp = null;
/**
* Set the activity upon which to display the progress dialog
* @param a the desired activity
*/
public void setActivity(ComicStripViewer a) {
mMain = a;
}
/**
* Main function responsible for downloading the strip in another thread
* @param arg0 null
* @return null
*/
@Override
protected Void doInBackground(Void... arg0) {
try {
mMain.getComic().getBound();
return null;
}
catch(Exception e) {
mExp = e;
Log.e(TAG, "doInBackground failed! " + e);
e.printStackTrace();
return null;
}
}
@Override
protected void onPreExecute() {
mPdiag = new ProgressDialog(mMain);
mPdiag.setCancelable(true);
mPdiag.setMessage(mMain.getResources().getString(R.string.comic_bound_fetch_msg));
mPdiag.show();
}
@Override
protected void onPostExecute(Void arg0) {
if(mExp != null) {
if(!mMain.isFinishing()) {
showError(mExp);
}
mExp.printStackTrace();
}
if(mPdiag.isShowing()) {
mPdiag.dismiss();
}
}
@Override
protected void onProgressUpdate(Void... arg0) {
}
/**
* Creates error message from exception
* @param msg initial message
* @param sb string builder
* @param e exception
*/
private void createMessageFromException(String msg, StringBuilder sb, Exception e) {
if(e != null) {
String ver = AppInfo.getVersion(mMain.getApplicationContext(), mMain.getClass());
sb.append(msg + " comic=" + mMain.getComic().getComicName() + " version=" + ver + " " + e + "\n");
StackTraceElement[] trace = e.getStackTrace();
if(trace.length > 0) {
sb.append("Stack Trace follows:\n");
int i = 1;
for(StackTraceElement ste : e.getStackTrace()) {
sb.append(" "+i+". "+ste+"\n");
i++;
}
}
else {
sb.append("No stack trace!\n");
}
}
}
/**
* Showing an alertbox in case of errors
* @param e exception caused
*/
private void showError(Exception e) {
if((mExp != null) && (mExp.getClass().getSimpleName().equals("ComicSDCardFull"))) {
AlertDialog.Builder alertbox = new AlertDialog.Builder(mMain);
alertbox.setMessage(mMain.getResources().getString(R.string.sd_card_full_msg));
alertbox.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
// TODO:
/*
Janitor clean = new Janitor();
clean.setActivity(mMain);
clean.execute((Void)null);
mComic.displayStrip(mType);
*/
}
});
alertbox.show();
return;
}
// all other errors!
StringBuilder sb = new StringBuilder();
createMessageFromException("ComicUpdater.onPostExecute failed! Reason: ", sb, e);
createMessageFromException("ComicUpdater.doInBackground failed! Reason: ", sb, mExp);
final String body = sb.toString();
Log.e(TAG, body);
AlertDialog.Builder alertbox = new AlertDialog.Builder(mMain);
alertbox.setMessage(mMain.getResources().getString(R.string.dnld_failed_msg));
alertbox.setNegativeButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertbox.setPositiveButton("Send Report", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
Resources res = mMain.getResources();
String[] email = new String[] { res.getString(R.string.dev_email) };
String subj = res.getString(R.string.comic_bug_report_subj);
mMain.startActivity(IntentGen.emailChooserIntent(email, subj, body, false, "Send Report..."));
}
});
alertbox.setNeutralButton("Retry", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO:
/*
Janitor clean = new Janitor();
clean.setActivity(mMain);
clean.execute((Void)null);
mComic.displayStrip(mType);
*/
}
});
alertbox.show();
}
}

View File

@ -0,0 +1,164 @@
package com.blogspot.applications4android.comicreader;
import com.blogspot.applications4android.comicreader.R;
import com.blogspot.applications4android.comicreader.core.AppInfo;
import com.blogspot.applications4android.comicreader.core.Comic;
import com.blogspot.applications4android.comicreader.core.IntentGen;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.util.Log;
/**
* Class responsible for downloading the comic-strip while displaying a progress dialog
*/
public class ComicSelectUpdater extends AsyncTask<String, Void, Void> {
/** for logging purposes */
private static final String TAG = "ComicSelectUpdater";
/** progress dialog to be shown in case of downloading a new strip */
private ProgressDialog mPdiag;
/** activity upon which to display the progress */
private ComicStripViewer mMain;
/** exception thrown by doInBackground */
private Exception mExp;
/**
* Set the activity upon which to display the progress dialog
* @param a the desired activity
*/
public void setActivity(ComicStripViewer a) {
mMain = a;
}
/**
* Main function responsible for downloading the strip in another thread
* @param arg0[0] the comic url of interest
* @return the desired comic-strip
*/
@Override
protected Void doInBackground(String... arg0) {
try {
mMain.getStripFromUrl(arg0[0]);
return null;
}
catch(Exception e) {
mExp = e;
Log.e(TAG, "doInBackground failed! " + e);
e.printStackTrace();
return null;
}
}
@Override
protected void onPreExecute() {
mPdiag = new ProgressDialog(mMain);
mPdiag.setCancelable(true);
mPdiag.setMessage(mMain.getResources().getString(R.string.comic_dnld_msg));
mPdiag.show();
}
@Override
protected void onPostExecute(Void arg0) {
try {
mMain.updateBitmap();
}
catch (Exception e) {
if(!mMain.isFinishing()) {
showError(e);
}
e.printStackTrace();
}
if(mPdiag.isShowing()) {
mPdiag.dismiss();
}
}
@Override
protected void onProgressUpdate(Void... arg0) {
}
/**
* Creates error message from exception
* @param msg initial message
* @param sb string builder
* @param e exception
*/
private void createMessageFromException(String msg, StringBuilder sb, Exception e) {
if(e != null) {
String ver = AppInfo.getVersion(mMain.getApplicationContext(), mMain.getClass());
sb.append(msg + " comic=" + mMain.getComic().getComicName() + " version=" + ver + " " + e + "\n");
StackTraceElement[] trace = e.getStackTrace();
if(trace.length > 0) {
sb.append("Stack Trace follows:\n");
int i = 1;
for(StackTraceElement ste : e.getStackTrace()) {
sb.append(" "+i+". "+ste+"\n");
i++;
}
}
else {
sb.append("No stack trace!\n");
}
}
}
/**
* Showing an alertbox in case of errors
* @param e exception caused
*/
private void showError(Exception e) {
if((mExp != null) && (mExp.getClass().getSimpleName().equals("ComicSDCardFull"))) {
AlertDialog.Builder alertbox = new AlertDialog.Builder(mMain);
alertbox.setMessage(mMain.getResources().getString(R.string.sd_card_full_msg));
alertbox.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
// TODO:
/*
Janitor clean = new Janitor();
clean.setActivity(mMain);
clean.execute((Void)null);
mComic.displayStrip(mType);
*/
}
});
alertbox.show();
return;
}
// all other errors!
StringBuilder sb = new StringBuilder();
createMessageFromException("ComicUpdater.onPostExecute failed! Reason: ", sb, e);
createMessageFromException("ComicUpdater.doInBackground failed! Reason: ", sb, mExp);
final String body = sb.toString();
Log.e(TAG, body);
AlertDialog.Builder alertbox = new AlertDialog.Builder(mMain);
alertbox.setMessage(mMain.getResources().getString(R.string.dnld_failed_msg));
alertbox.setNegativeButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
alertbox.setPositiveButton("Send Report", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
Resources res = mMain.getResources();
String[] email = new String[] { res.getString(R.string.dev_email) };
String subj = res.getString(R.string.comic_bug_report_subj);
mMain.startActivity(IntentGen.emailChooserIntent(email, subj, body, false, "Send Report..."));
}
});
alertbox.setNeutralButton("Retry", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mMain.cacheCleaner(Comic.NAV_CURRENT);
}
});
alertbox.show();
}
}

View File

@ -0,0 +1,614 @@
package com.blogspot.applications4android.comicreader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Date;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import com.blogspot.applications4android.comicreader.comictypes.DailyComic;
import com.blogspot.applications4android.comicreader.comictypes.IndexedComic;
import com.blogspot.applications4android.comicreader.core.Bound;
import com.blogspot.applications4android.comicreader.core.Comic;
import com.blogspot.applications4android.comicreader.core.ComicActivity;
import com.blogspot.applications4android.comicreader.core.ComicClassList;
import com.blogspot.applications4android.comicreader.core.FileUtils;
import com.blogspot.applications4android.comicreader.core.ImageType;
import com.blogspot.applications4android.comicreader.core.IntentGen;
import com.blogspot.applications4android.comicreader.core.Strip;
import com.blogspot.applications4android.comicreader.exceptions.BitMapException;
import com.blogspot.applications4android.comicreader.exceptions.ComicNotFoundException;
import com.blogspot.applications4android.comicreader.exceptions.ComicSDCardFull;
import com.blogspot.applications4android.comicreader.numpicker.NumberPicker;
import com.blogspot.applications4android.comicreader.numpicker.NumberPickerDialog;
import com.blogspot.applications4android.comicreader.zoom.PanZoomControl;
import com.blogspot.applications4android.comicreader.zoom.PanZoomListener;
import com.blogspot.applications4android.comicreader.zoom.PanZoomView;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.Toast;
/**
* Activity which is responsible for displaying a comic-series.
* This also provides the UI for 'navigating' in this comic-series.
*/
// TODO: add unit-tests
public class ComicStripViewer extends ComicActivity {
/** for logging purposes only */
private static final String TAG = "StripViewer";
/** Holds the comic series responsible for providing the requested comic-strip */
private Comic mComic;
/** The imageView where to display the current comic strip */
private PanZoomView mPzv;
/** title for this viewer */
private String mTitle;
/** listener for the activity */
private PanZoomListener mPzl;
/** controller for the view */
private PanZoomControl mPzc;
/** layout containing the zoom controls */
private LinearLayout mCtrls;
/** view mode */
private int mMode = Comic.TYPE_LATEST;
/** comic list for navigation */
private ComicClassList mList;
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "on create ....");
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if(extras != null) {
mTitle = extras.getString("title");
mMode = extras.getInt("mode");
}
Log.d(TAG, "on create finished ...");
}
@Override
public void onResume() {
Log.d(TAG, "on resume ....");
super.onResume();
setContentView(R.layout.comic_strip_viewer);
setTitle(mTitle);
mCtrls = (LinearLayout) findViewById(R.id.view_control);
mPzv = (PanZoomView) findViewById(R.id.image_viewer);
mPzc = new PanZoomControl(mPzv);
mPzv.setController(mPzc);
mPzl = new PanZoomListener(mPzc, mCtrls);
mPzv.setOnTouchListener(mPzl);
try {
mList = setupComicsList("mSortPref");
}
catch(Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Failed to 'setupComicsList'! Reason: "+e.getMessage(), Toast.LENGTH_LONG).show();
}
_initComic();
Log.d(TAG, "on resume finished ...");
}
@Override
protected void onPause() {
Log.d(TAG, "on pause ....");
try {
_storeCurrentComic(true);
}
catch(Exception e) {
e.printStackTrace();
}
super.onPause();
Log.d(TAG, "on pause finished ....");
}
/**
* Returns the comic series being displayed right now
* @return comic series
*/
public Comic getComic() {
return mComic;
}
/**
* Returns the layout containing the controls for strip navigation
* @return layout
*/
public LinearLayout getControlsLayout() {
return mCtrls;
}
/**
* Tells whether the cucrent comic-strip being displayed is favorite or not
* @return true if it is
*/
public boolean isCurrentFavorite() {
if(mComic == null) {
return false;
}
Strip curr = mComic.getCurrentStrip();
if(curr == null) {
return false;
}
return curr.isFavorite();
}
/**
* Set the next comic in the list
* @throws IOException
* @throws ComicNotFoundException
* @throws JSONException
* @throws ComicSDCardFull
*/
public void setupNextComic() throws IOException, ComicNotFoundException, JSONException, ComicSDCardFull {
if(mComic == null) {
return;
}
String title = _storeCurrentComic(false);
mComic = (mMode == Comic.TYPE_PREVIEW)? mList.getNextComic(title) : mList.getNextMyComic(title);
int type = (mMode == Comic.TYPE_PREV_SESSION)? Comic.NAV_PREV_SESSION : Comic.NAV_LATEST;
_setupCurrentComic(type);
}
/**
* Set the previous comic in the list
* @throws ComicNotFoundException
* @throws IOException
* @throws JSONException
* @throws ComicSDCardFull
*/
public void setupPreviousComic() throws ComicNotFoundException, IOException, JSONException, ComicSDCardFull {
if(mComic == null) {
return;
}
String title = _storeCurrentComic(false);
mComic = (mMode == Comic.TYPE_PREVIEW)? mList.getPreviousComic(title) : mList.getPreviousMyComic(title);
int type = (mMode == Comic.TYPE_PREV_SESSION)? Comic.NAV_PREV_SESSION : Comic.NAV_LATEST;
_setupCurrentComic(type);
}
/**
* Setup the current comic
* @param type navigation type
* @throws FileNotFoundException
* @throws IOException
* @throws JSONException
*/
private void _setupCurrentComic(int type) throws FileNotFoundException, IOException, JSONException {
_initCurrentComic();
displayStrip(type);
}
/**
* Initialize the current comic
* @throws FileNotFoundException
* @throws IOException
* @throws JSONException
*/
private void _initCurrentComic() throws FileNotFoundException, IOException, JSONException {
mTitle = mComic.getComicName();
setTitle(mTitle);
mComic.readProperties();
mComic.setLaunchType(mMode);
if(mMode == Comic.TYPE_PREVIEW) {
mComic.setCacheEnabled(false);
}
else {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mComic.setCacheEnabled(sp.getBoolean("backgroundCacheEnabledPref", false));
}
mPzv.setZoom(mComic.getDefaultZoom());
mPzl.setComicActivity(this);
}
/**
* Store the current comic's properties, before loading a new one
* @param preserve do not delete the current comic.
* @return title of the current comic
* @throws IOException
* @throws ComicSDCardFull
*/
private String _storeCurrentComic(boolean preserve) throws IOException, ComicSDCardFull {
mComic.setDefaultZoom(mPzv.getZoom());
mComic.writeProperties();
String title = mComic.getComicName();
if(!preserve) {
mComic = null;
}
return title;
}
/**
* Helper function to setup a comic from title
*/
private void _initComic() {
int type = Comic.NAV_CURRENT;
try {
if(mComic == null) {
mComic = mList.getComicFromTitle(mTitle);
type = (mMode == Comic.TYPE_PREV_SESSION)? Comic.NAV_PREV_SESSION : Comic.NAV_LATEST;
}
_initCurrentComic();
setZoomButtonListeners();
Log.d(TAG, "type being displayed = "+type);
displayStrip(type);
}
catch(Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG);
}
}
/**
* This updates the view with the current comic-strip
* @throws BitMapException
* @throws FileNotFoundException
*/
public void updateBitmap() throws FileNotFoundException, BitMapException {
if(mComic == null) {
return;
}
Strip s = mComic.getCurrentStrip();
if(s == null) {
mPzv.setImageBitmap(null);
mPzv.invalidate();
return;
}
mPzv.invalidate();
mPzv.setImageBitmap(s.getBitmapFromFile());
Log.d(TAG, "Setting the title to be "+s.getTitle());
setTitle(s.getTitle());
mPzv.setPanXY(0, 0);
hideResetButton();
mPzv.invalidate();
}
/**
* Set listeners for zoom in/out buttons
*/
private void setZoomButtonListeners() {
Button text = (Button) findViewById(R.id.image_text);
text.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
mPzl.resetChangeVisibility();
AlertDialog.Builder alertbox = new AlertDialog.Builder(ComicStripViewer.this);
if(mComic.currentHasImageText()) {
alertbox.setMessage(mComic.getCurrentStrip().getText());
}
else {
alertbox.setMessage("-NA-");
}
alertbox.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
}
});
alertbox.show();
}
});
Button fav = (Button) findViewById(R.id.strip_favorite);
fav.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
mPzl.resetChangeVisibility();
Button b = (Button) arg0;
int id;
if(mComic.isCurrentFavorite()) {
mComic.setCurrentAsFavorite(false);
id = R.drawable.star_nonfav;
}
else {
mComic.setCurrentAsFavorite(true);
id = R.drawable.star_fav;
}
b.setBackgroundDrawable(getResources().getDrawable(id));
}
});
Button share = (Button) findViewById(R.id.strip_share);
share.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
mPzl.resetChangeVisibility();
if(mComic == null) {
return;
}
Strip s = mComic.getCurrentStrip();
if(s == null) {
return;
}
Log.d(TAG, "Share strip="+s.getTitle()+" uid="+s.uid());
String url = s.getStripUrl();
if(url == null) {
url = s.uid();
}
ComicStripViewer.this.startActivity(IntentGen.shareLinkChooserIntent("ComicReader- "+s.getTitle(), url, "Share this comic..."));
}
});
Button zout = (Button) findViewById(R.id.zoom_out_button);
zout.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
if(mComic == null) {
return;
}
if(mComic.getCurrentStrip() == null) {
return;
}
mPzl.resetChangeVisibility();
mPzl.setModeToZoom();
mPzc.zoom(PanZoomListener.ZOOM_FACTOR, PanZoomListener.MODE_ZOOM_OUT);
if(mPzc.isMinimumZoom()) {
mPzc.resetState();
}
}
});
Button zin = (Button) findViewById(R.id.zoom_in_button);
zin.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
if(mComic == null) {
return;
}
if(mComic.getCurrentStrip() == null) {
return;
}
mPzl.resetChangeVisibility();
mPzl.setModeToZoom();
mPzc.zoom(PanZoomListener.ZOOM_FACTOR, PanZoomListener.MODE_ZOOM_IN);
}
});
Button resetB = (Button) findViewById(R.id.reset_button);
resetB.setVisibility(View.INVISIBLE);
resetB.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mPzl.setModeToPan();
Button b = (Button) v;
b.setVisibility(View.INVISIBLE);
}
});
Button prev = (Button) findViewById(R.id.strip_prev);
prev.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
displayStrip(Comic.NAV_PREVIOUS);
}
});
Button next = (Button) findViewById(R.id.strip_next);
next.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
displayStrip(Comic.NAV_NEXT);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inf = getMenuInflater();
inf.inflate(R.menu.image_viewer_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final Resources res = getResources();
try {
switch(item.getItemId()) {
case R.id.comic_select:
_getUserInputAndDisplayStrip();
return true;
case R.id.comic_clear_cache:
{
AlertDialog.Builder alertbox = new AlertDialog.Builder(ComicStripViewer.this);
alertbox.setMessage(res.getString(R.string.comic_cache_clean_confirmation));
alertbox.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(ComicStripViewer.this, res.getString(R.string.comic_cache_clean_abort), Toast.LENGTH_LONG).show();
}
});
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
cacheCleaner(-1);
}
});
alertbox.show();
return true;
}
case R.id.comic_first:
displayStrip(Comic.NAV_FIRST);
return true;
case R.id.comic_latest:
displayStrip(Comic.NAV_LATEST);
return true;
case R.id.comic_rand:
displayStrip(Comic.NAV_RANDOM);
return true;
case R.id.comic_save:
if(mComic.getCurrentStrip() == null) {
return true;
}
File src = new File(mComic.getCurrentStrip().getImagePath());
Intent i = new Intent();
File root = new File(FileUtils.getSdcard(), "SavedComics");
root.mkdirs();
String fi = mComic.currentTitleAsValidFilename() + ImageType.getImageType(src.getPath()).toString();
File out = new File(root, fi);
i.putExtra("src_file", src.getPath());
i.putExtra("dest_file", out.getPath());
i.setClass(ComicStripViewer.this, ActivitySaveStrip.class);
ComicStripViewer.this.startActivityForResult(i, 0);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
catch(Exception e) {
Log.e(TAG, "onOptionsItemSelected: failed. Reason: "+e);
e.printStackTrace();
return false;
}
}
/**
* Updater to clear the cache
* @param type whether to update the strip (pass a value <0 to not update)
*/
public void cacheCleaner(int type) {
ClearCacheUpdater ccu = new ClearCacheUpdater();
ccu.setActivity(this);
ccu.setType(type);
ccu.execute(mComic);
}
/**
* Update the view in the given activity with the comic type
* @param comic_type type of comic to be fetched.
*/
public void displayStrip(int comic_type) {
try {
ComicUpdater cu = new ComicUpdater();
cu.setActivity(this);
cu.execute(comic_type);
}
catch(Exception e) {
Log.e(TAG, "displayStrip failed! Reason: " + e);
e.printStackTrace();
}
}
/**
* Update the view in the given activity with the comic selected by the user
* @param comic_url comic url to be displayed
*/
public void selectAndDisplayStrip(String comic_url) {
try {
ComicSelectUpdater csu = new ComicSelectUpdater();
csu.setActivity(this);
csu.execute(comic_url);
}
catch(Exception e) {
Log.e(TAG, "selectAndDisplayStrip failed! Reason: " + e);
e.printStackTrace();
}
}
/**
* Function responsible for asking user to input a comic strip id/calendar
* and display that strip.
*/
private void _getUserInputAndDisplayStrip() {
if(mComic == null) {
return;
}
_updateBound();
if(mComic.dialogType() == Comic.DIALOG_DATE) {
DailyComic dc = (DailyComic) mComic;
Calendar cal = dc.getCurrentCal();
int year = cal.get(Calendar.YEAR);
int monthOfYear = cal.get(Calendar.MONTH);
int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
DatePickerDialog dpd = new DatePickerDialog(this, mDatesetListener, year, monthOfYear, dayOfMonth);
dpd.show();
}
else {
IndexedComic ic = (IndexedComic) mComic;
Bound b = mComic.getBound();
NumberPickerDialog npd = new NumberPickerDialog(this, mNumsetListener, (int)b.min, (int)b.max, ic.getCurrentId());
npd.show();
}
}
/**
* Update the bound for the current comic
*/
private void _updateBound() {
try {
ComicBoundUpdater cbu = new ComicBoundUpdater();
cbu.setActivity(this);
cbu.execute((Void[])null);
}
catch(Exception e) {
Log.e(TAG, "updateBound failed! Reason: " + e);
e.printStackTrace();
}
}
/**
* Get the strip from the given url
* @param url url
* @return the strip
* @throws ClientProtocolException
* @throws URISyntaxException
* @throws IOException
* @throws ComicSDCardFull
*/
public Strip getStripFromUrl(String url) throws ClientProtocolException, URISyntaxException, IOException, ComicSDCardFull {
return mComic.getStripFromUrl(url);
}
/**
* NumberPicker onsetlistener for comics which use ints for indexing
*/
private NumberPickerDialog.OnSetListener mNumsetListener = new NumberPickerDialog.OnSetListener() {
public void onNumSet(NumberPicker view, int num) {
IndexedComic ic = (IndexedComic) mComic;
num = ic.addException(num, -1);
String url = ic.getStripUrlFromId(num);
selectAndDisplayStrip(url);
}
};
/**
* DatePicker onsetlistener for comics which use calendar for indexing
* This also has an option for bound check
*/
private DatePickerDialog.OnDateSetListener mDatesetListener = new DatePickerDialog.OnDateSetListener() {
private String getCalendarString(long millis) {
Date da = new Date(millis);
Calendar c = Calendar.getInstance();
c.setTime(da);
int y = c.get(Calendar.YEAR);
int m = c.get(Calendar.MONTH) + 1;
int d = c.get(Calendar.DAY_OF_MONTH);
return String.format("%4d-%02d-%02d", y, m, d);
}
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
Calendar cal = Calendar.getInstance();
cal.set(year, monthOfYear, dayOfMonth, 0, 0, 0);
long val = cal.getTimeInMillis();
Bound b = mComic.getBound();
if(b.isUnderLimit(val)) {
DailyComic dc = (DailyComic) mComic;
dc.addException(cal, -1);
String url = dc.getUrlFromTime(cal);
selectAndDisplayStrip(url);
}
else {
AlertDialog.Builder alertbox = new AlertDialog.Builder(ComicStripViewer.this);
alertbox.setTitle("Bad Date Selected!");
alertbox.setMessage("You should select dates which are within the range.\n"+
"First Comic Date = " + getCalendarString(b.min) + "\n"+
"Latest Comic Date = " + getCalendarString(b.max));
alertbox.setNeutralButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
arg0.cancel();
}
});
alertbox.show();
}
}
};
}

Some files were not shown because too many files have changed in this diff Show More