diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index 966c3e0..0000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index c3f4dc3..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1 +0,0 @@
-language: objective-c
diff --git a/README.md b/README.md
deleted file mode 100644
index 17ce999..0000000
--- a/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Rebuilt from ground up using swift, added pagination, highlights, bookmarks.
-
-
-
-What happens when you load an Epub into a UITextView, look into the ** 
-
-# Epub-Reader
-[](https://travis-ci.org/zeroCoder1/Epub-Reader)
-
-Reads an ePub document for iPad/ iPhone
-
-This is a very simple ePub Reader that will read some ePub files by parsing xml file.
-
-Just drop in a ePub 3.0 file into the resources and should get it parsed and displayed to you.
-
-
-
-
-
-It is better to download this ePub
-http://code.google.com/p/epub-revision/downloads/detail?name=9780316000000_MobyDick_r2.epub
-and add it to the project.
-
-More on Epub 3.0 features here
-
-http://idpf.org/epub/30
-
-Additional details.
-
- * Swipe to change chapters or tap on next and previous buttons.
- * There are text font size increase and decrese methods.
- * Day/Night reading Mode.
- * Search text on a current page.
- * Orientation support.
- * Minimal Pagination. -- Once the scrollstops, have to press the next button.
-
-The app will rememeber the size of the text and mode selected.
-
-
-
- If you add any enhancements to the existing code, please do those changes here as well.
-
-
-## GitAds Sponsored
-[](https://gitads.dev/v1/ad-track?source=zerocoder1/epub-reader@github)
-
diff --git a/images/checker.png b/images/checker.png
new file mode 100644
index 0000000..ab14540
Binary files /dev/null and b/images/checker.png differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..a134cb3
--- /dev/null
+++ b/index.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+ Epub-reader by zeroCoder1
+
+
+
+
+
+
+
+
+
+
+
+
+ Hello World.
+
+This is a sample ePub reader. I have added an CSS3 ePub.
+Although the commit description says deleted ePub.. :P
+
+It might not be a great code to reuse. But you can surely learn how an ePub is rendered.
+
+Thanks,
+zer01
+
+
+
+
+
+
\ No newline at end of file
diff --git a/javascripts/scale.fix.js b/javascripts/scale.fix.js
new file mode 100644
index 0000000..08716c0
--- /dev/null
+++ b/javascripts/scale.fix.js
@@ -0,0 +1,20 @@
+fixScale = function(doc) {
+
+ var addEvent = 'addEventListener',
+ type = 'gesturestart',
+ qsa = 'querySelectorAll',
+ scales = [1, 1],
+ meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : [];
+
+ function fix() {
+ meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1];
+ doc.removeEventListener(type, fix, true);
+ }
+
+ if ((meta = meta[meta.length - 1]) && addEvent in doc) {
+ fix();
+ scales = [.25, 1.6];
+ doc[addEvent](type, fix, true);
+ }
+
+};
\ No newline at end of file
diff --git a/params.json b/params.json
new file mode 100644
index 0000000..6b75475
--- /dev/null
+++ b/params.json
@@ -0,0 +1 @@
+{"name":"Epub-reader","body":"#### Hello World.\r\n\r\nThis is a sample ePub reader. I have added an CSS3 ePub.\r\nAlthough the commit description says deleted ePub.. :P\r\n\r\nIt might not be a great code to reuse. But you can surely learn how an ePub is rendered. \r\n\r\nThanks,\r\nzer01","tagline":"Reads an ePub document","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."}
\ No newline at end of file
diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css
new file mode 100644
index 0000000..1926cfd
--- /dev/null
+++ b/stylesheets/pygment_trac.css
@@ -0,0 +1,60 @@
+.highlight .hll { background-color: #49483e }
+.highlight { background: #3A3C42; color: #f8f8f2 }
+.highlight .c { color: #75715e } /* Comment */
+.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
+.highlight .k { color: #66d9ef } /* Keyword */
+.highlight .l { color: #ae81ff } /* Literal */
+.highlight .n { color: #f8f8f2 } /* Name */
+.highlight .o { color: #f92672 } /* Operator */
+.highlight .p { color: #f8f8f2 } /* Punctuation */
+.highlight .cm { color: #75715e } /* Comment.Multiline */
+.highlight .cp { color: #75715e } /* Comment.Preproc */
+.highlight .c1 { color: #75715e } /* Comment.Single */
+.highlight .cs { color: #75715e } /* Comment.Special */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .kc { color: #66d9ef } /* Keyword.Constant */
+.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
+.highlight .kn { color: #f92672 } /* Keyword.Namespace */
+.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
+.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
+.highlight .kt { color: #66d9ef } /* Keyword.Type */
+.highlight .ld { color: #e6db74 } /* Literal.Date */
+.highlight .m { color: #ae81ff } /* Literal.Number */
+.highlight .s { color: #e6db74 } /* Literal.String */
+.highlight .na { color: #a6e22e } /* Name.Attribute */
+.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
+.highlight .nc { color: #a6e22e } /* Name.Class */
+.highlight .no { color: #66d9ef } /* Name.Constant */
+.highlight .nd { color: #a6e22e } /* Name.Decorator */
+.highlight .ni { color: #f8f8f2 } /* Name.Entity */
+.highlight .ne { color: #a6e22e } /* Name.Exception */
+.highlight .nf { color: #a6e22e } /* Name.Function */
+.highlight .nl { color: #f8f8f2 } /* Name.Label */
+.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
+.highlight .nx { color: #a6e22e } /* Name.Other */
+.highlight .py { color: #f8f8f2 } /* Name.Property */
+.highlight .nt { color: #f92672 } /* Name.Tag */
+.highlight .nv { color: #f8f8f2 } /* Name.Variable */
+.highlight .ow { color: #f92672 } /* Operator.Word */
+.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
+.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
+.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
+.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
+.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
+.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
+.highlight .sc { color: #e6db74 } /* Literal.String.Char */
+.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
+.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
+.highlight .se { color: #ae81ff } /* Literal.String.Escape */
+.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
+.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
+.highlight .sx { color: #e6db74 } /* Literal.String.Other */
+.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
+.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
+.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
+.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
+.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
+.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
+.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/stylesheets/styles.css b/stylesheets/styles.css
new file mode 100644
index 0000000..1d14024
--- /dev/null
+++ b/stylesheets/styles.css
@@ -0,0 +1,363 @@
+@import url(https://fonts.googleapis.com/css?family=Lato:300italic,700italic,300,700);
+html {
+ background: #6C7989;
+ background: #6c7989 -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #6c7989), color-stop(100%, #434b55)) fixed;
+ background: #6c7989 -webkit-linear-gradient(#6c7989, #434b55) fixed;
+ background: #6c7989 -moz-linear-gradient(#6c7989, #434b55) fixed;
+ background: #6c7989 -o-linear-gradient(#6c7989, #434b55) fixed;
+ background: #6c7989 -ms-linear-gradient(#6c7989, #434b55) fixed;
+ background: #6c7989 linear-gradient(#6c7989, #434b55) fixed;
+}
+
+body {
+ padding: 50px 0;
+ margin: 0;
+ font: 14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif;
+ color: #555;
+ font-weight: 300;
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAeCAYAAABNChwpAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAAAUdEVYdENyZWF0aW9uIFRpbWUAMy82LzEygrTcTAAAAFRJREFUSIljfPDggZRf5RIGGNjUHsNATz6jXmSL1Kb2GLiAX+USBnrymRgGGDCORgFmoNAXjEbBaBSMRsFoFIxGwWgUjEbBaBSMRsFoFIxGwWgUAABYNujumib3wAAAAABJRU5ErkJggg==') fixed;
+}
+
+.wrapper {
+ width: 640px;
+ margin: 0 auto;
+ background: #DEDEDE;
+ -moz-border-radius: 8px;
+ -webkit-border-radius: 8px;
+ -o-border-radius: 8px;
+ -ms-border-radius: 8px;
+ -khtml-border-radius: 8px;
+ border-radius: 8px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px;
+ -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px;
+ -o-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px;
+ box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px;
+}
+
+header, section, footer {
+ display: block;
+}
+
+a {
+ color: #069;
+ text-decoration: none;
+}
+
+p {
+ margin: 0 0 20px;
+ padding: 0;
+}
+
+strong {
+ color: #222;
+ font-weight: 700;
+}
+
+header {
+ -moz-border-radius: 8px 8px 0 0;
+ -webkit-border-radius: 8px 8px 0 0;
+ -o-border-radius: 8px 8px 0 0;
+ -ms-border-radius: 8px 8px 0 0;
+ -khtml-border-radius: 8px 8px 0 0;
+ border-radius: 8px 8px 0 0;
+ background: #C6EAFA;
+ background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ddfbfc), color-stop(100%, #c6eafa));
+ background: -webkit-linear-gradient(#ddfbfc, #c6eafa);
+ background: -moz-linear-gradient(#ddfbfc, #c6eafa);
+ background: -o-linear-gradient(#ddfbfc, #c6eafa);
+ background: -ms-linear-gradient(#ddfbfc, #c6eafa);
+ background: linear-gradient(#ddfbfc, #c6eafa);
+ position: relative;
+ padding: 15px 20px;
+ border-bottom: 1px solid #B2D2E1;
+}
+header h1 {
+ margin: 0;
+ padding: 0;
+ font-size: 24px;
+ line-height: 1.2;
+ color: #069;
+ text-shadow: rgba(255, 255, 255, 0.9) 0 1px 0;
+}
+header.without-description h1 {
+ margin: 10px 0;
+}
+header p {
+ margin: 0;
+ color: #61778B;
+ width: 300px;
+ font-size: 13px;
+}
+header p.view {
+ display: none;
+ font-weight: 700;
+ text-shadow: rgba(255, 255, 255, 0.9) 0 1px 0;
+ -webkit-font-smoothing: antialiased;
+}
+header p.view a {
+ color: #06c;
+}
+header p.view small {
+ font-weight: 400;
+}
+header ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ position: absolute;
+ z-index: 1;
+ right: 20px;
+ top: 20px;
+ height: 38px;
+ padding: 1px 0;
+ background: #5198DF;
+ background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #77b9fb), color-stop(100%, #3782cd));
+ background: -webkit-linear-gradient(#77b9fb, #3782cd);
+ background: -moz-linear-gradient(#77b9fb, #3782cd);
+ background: -o-linear-gradient(#77b9fb, #3782cd);
+ background: -ms-linear-gradient(#77b9fb, #3782cd);
+ background: linear-gradient(#77b9fb, #3782cd);
+ border-radius: 5px;
+ -moz-box-shadow: inset rgba(255, 255, 255, 0.45) 0 1px 0, inset rgba(0, 0, 0, 0.2) 0 -1px 0;
+ -webkit-box-shadow: inset rgba(255, 255, 255, 0.45) 0 1px 0, inset rgba(0, 0, 0, 0.2) 0 -1px 0;
+ -o-box-shadow: inset rgba(255, 255, 255, 0.45) 0 1px 0, inset rgba(0, 0, 0, 0.2) 0 -1px 0;
+ box-shadow: inset rgba(255, 255, 255, 0.45) 0 1px 0, inset rgba(0, 0, 0, 0.2) 0 -1px 0;
+ width: 240px;
+}
+header ul:before {
+ content: '';
+ position: absolute;
+ z-index: -1;
+ left: -5px;
+ top: -4px;
+ right: -5px;
+ bottom: -6px;
+ background: rgba(0, 0, 0, 0.1);
+ -moz-border-radius: 8px;
+ -webkit-border-radius: 8px;
+ -o-border-radius: 8px;
+ -ms-border-radius: 8px;
+ -khtml-border-radius: 8px;
+ border-radius: 8px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0, inset rgba(255, 255, 255, 0.7) 0 -1px 0;
+ -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0, inset rgba(255, 255, 255, 0.7) 0 -1px 0;
+ -o-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0, inset rgba(255, 255, 255, 0.7) 0 -1px 0;
+ box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0, inset rgba(255, 255, 255, 0.7) 0 -1px 0;
+}
+header ul li {
+ width: 79px;
+ float: left;
+ border-right: 1px solid #3A7CBE;
+ height: 38px;
+}
+header ul li + li {
+ width: 78px;
+ border-left: 1px solid #8BBEF3;
+}
+header ul li + li + li {
+ border-right: none;
+ width: 79px;
+}
+header ul a {
+ line-height: 1;
+ font-size: 11px;
+ color: #fff;
+ color: rgba(255, 255, 255, 0.8);
+ display: block;
+ text-align: center;
+ font-weight: 400;
+ padding-top: 6px;
+ height: 40px;
+ text-shadow: rgba(0, 0, 0, 0.4) 0 -1px 0;
+}
+header ul a strong {
+ font-size: 14px;
+ display: block;
+ color: #fff;
+ -webkit-font-smoothing: antialiased;
+}
+
+section {
+ padding: 15px 20px;
+ font-size: 15px;
+ border-top: 1px solid #fff;
+ background: -webkit-gradient(linear, 50% 0%, 50% 700, color-stop(0%, #fafafa), color-stop(100%, #dedede));
+ background: -webkit-linear-gradient(#fafafa, #dedede 700px);
+ background: -moz-linear-gradient(#fafafa, #dedede 700px);
+ background: -o-linear-gradient(#fafafa, #dedede 700px);
+ background: -ms-linear-gradient(#fafafa, #dedede 700px);
+ background: linear-gradient(#fafafa, #dedede 700px);
+ -moz-border-radius: 0 0 8px 8px;
+ -webkit-border-radius: 0 0 8px 8px;
+ -o-border-radius: 0 0 8px 8px;
+ -ms-border-radius: 0 0 8px 8px;
+ -khtml-border-radius: 0 0 8px 8px;
+ border-radius: 0 0 8px 8px;
+ position: relative;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #222;
+ padding: 0;
+ margin: 0 0 20px;
+ line-height: 1.2;
+}
+
+p, ul, ol, table, pre, dl {
+ margin: 0 0 20px;
+}
+
+h1, h2, h3 {
+ line-height: 1.1;
+}
+
+h1 {
+ font-size: 28px;
+}
+
+h2 {
+ color: #393939;
+}
+
+h3, h4, h5, h6 {
+ color: #494949;
+}
+
+blockquote {
+ margin: 0 -20px 20px;
+ padding: 15px 20px 1px 40px;
+ font-style: italic;
+ background: #ccc;
+ background: rgba(0, 0, 0, 0.06);
+ color: #222;
+}
+
+img {
+ max-width:100%;
+}
+
+code, pre {
+ font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal;
+ color: #333;
+ font-size: 12px;
+}
+
+pre {
+ padding: 20px;
+ background: #3A3C42;
+ color: #f8f8f2;
+ margin: 0 -20px 20px;
+ overflow-x:auto;
+}
+pre code {
+ color: #f8f8f2;
+}
+li pre {
+ margin-left: -60px;
+ padding-left: 60px;
+}
+
+table {
+ width: 100%;
+ border-collapse: collapse;
+}
+
+th, td {
+ text-align: left;
+ padding: 5px 10px;
+ border-bottom: 1px solid #aaa;
+}
+
+dt {
+ color: #222;
+ font-weight: 700;
+}
+
+th {
+ color: #222;
+}
+
+small {
+ font-size: 11px;
+}
+
+hr {
+ border: 0;
+ background: #aaa;
+ height: 1px;
+ margin: 0 0 20px;
+}
+
+footer {
+ width: 640px;
+ margin: 0 auto;
+ padding: 20px 0 0;
+ color: #ccc;
+ overflow: hidden;
+}
+footer a {
+ color: #fff;
+ font-weight: bold;
+}
+footer p {
+ float: left;
+}
+footer p + p {
+ float: right;
+}
+
+@media print, screen and (max-width: 740px) {
+ body {
+ padding: 0;
+ }
+
+ .wrapper {
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ -o-border-radius: 0;
+ -ms-border-radius: 0;
+ -khtml-border-radius: 0;
+ border-radius: 0;
+ -moz-box-shadow: none;
+ -webkit-box-shadow: none;
+ -o-box-shadow: none;
+ box-shadow: none;
+ width: 100%;
+ }
+
+ footer {
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ -o-border-radius: 0;
+ -ms-border-radius: 0;
+ -khtml-border-radius: 0;
+ border-radius: 0;
+ padding: 20px;
+ width: auto;
+ }
+ footer p {
+ float: none;
+ margin: 0;
+ }
+ footer p + p {
+ float: none;
+ }
+}
+@media print, screen and (max-width:580px) {
+ header ul {
+ display: none;
+ }
+
+ header p.view {
+ display: block;
+ }
+
+ header p {
+ width: 100%;
+ }
+}
+@media print {
+ header p.view a small:before {
+ content: 'at http://github.com/';
+ }
+}
diff --git a/testReader.xcodeproj/project.pbxproj b/testReader.xcodeproj/project.pbxproj
deleted file mode 100644
index a7d92ee..0000000
--- a/testReader.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,387 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 77;
- objects = {
-
-/* Begin PBXBuildFile section */
- 39DBA78A2D80A8EA001F1C5B /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = 39DBA7892D80A8EA001F1C5B /* SwiftSoup */; };
- 39DBA78D2D80A917001F1C5B /* ZipArchive in Frameworks */ = {isa = PBXBuildFile; productRef = 39DBA78C2D80A917001F1C5B /* ZipArchive */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
- 39DBA7702D80A8B5001F1C5B /* testReader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = testReader.app; sourceTree = BUILT_PRODUCTS_DIR; };
-/* End PBXFileReference section */
-
-/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
- 39DBA7822D80A8B7001F1C5B /* Exceptions for "testReader" folder in "testReader" target */ = {
- isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
- membershipExceptions = (
- Info.plist,
- );
- target = 39DBA76F2D80A8B5001F1C5B /* testReader */;
- };
-/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
-
-/* Begin PBXFileSystemSynchronizedRootGroup section */
- 39DBA7722D80A8B5001F1C5B /* testReader */ = {
- isa = PBXFileSystemSynchronizedRootGroup;
- exceptions = (
- 39DBA7822D80A8B7001F1C5B /* Exceptions for "testReader" folder in "testReader" target */,
- );
- path = testReader;
- sourceTree = "";
- };
-/* End PBXFileSystemSynchronizedRootGroup section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 39DBA76D2D80A8B5001F1C5B /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 39DBA78A2D80A8EA001F1C5B /* SwiftSoup in Frameworks */,
- 39DBA78D2D80A917001F1C5B /* ZipArchive in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 39DBA7672D80A8B5001F1C5B = {
- isa = PBXGroup;
- children = (
- 39DBA7722D80A8B5001F1C5B /* testReader */,
- 39DBA7712D80A8B5001F1C5B /* Products */,
- );
- sourceTree = "";
- };
- 39DBA7712D80A8B5001F1C5B /* Products */ = {
- isa = PBXGroup;
- children = (
- 39DBA7702D80A8B5001F1C5B /* testReader.app */,
- );
- name = Products;
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 39DBA76F2D80A8B5001F1C5B /* testReader */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 39DBA7832D80A8B7001F1C5B /* Build configuration list for PBXNativeTarget "testReader" */;
- buildPhases = (
- 39DBA76C2D80A8B5001F1C5B /* Sources */,
- 39DBA76D2D80A8B5001F1C5B /* Frameworks */,
- 39DBA76E2D80A8B5001F1C5B /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- fileSystemSynchronizedGroups = (
- 39DBA7722D80A8B5001F1C5B /* testReader */,
- );
- name = testReader;
- packageProductDependencies = (
- 39DBA7892D80A8EA001F1C5B /* SwiftSoup */,
- 39DBA78C2D80A917001F1C5B /* ZipArchive */,
- );
- productName = testReader;
- productReference = 39DBA7702D80A8B5001F1C5B /* testReader.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 39DBA7682D80A8B5001F1C5B /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = 1;
- LastSwiftUpdateCheck = 1620;
- LastUpgradeCheck = 1620;
- TargetAttributes = {
- 39DBA76F2D80A8B5001F1C5B = {
- CreatedOnToolsVersion = 16.2;
- };
- };
- };
- buildConfigurationList = 39DBA76B2D80A8B5001F1C5B /* Build configuration list for PBXProject "testReader" */;
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 39DBA7672D80A8B5001F1C5B;
- minimizedProjectReferenceProxies = 1;
- packageReferences = (
- 39DBA7882D80A8EA001F1C5B /* XCRemoteSwiftPackageReference "SwiftSoup" */,
- 39DBA78B2D80A917001F1C5B /* XCRemoteSwiftPackageReference "ZipArchive" */,
- );
- preferredProjectObjectVersion = 77;
- productRefGroup = 39DBA7712D80A8B5001F1C5B /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 39DBA76F2D80A8B5001F1C5B /* testReader */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 39DBA76E2D80A8B5001F1C5B /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 39DBA76C2D80A8B5001F1C5B /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 39DBA7842D80A8B7001F1C5B /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = 7CSFZ8JM6F;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_FILE = testReader/Info.plist;
- INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
- INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
- INFOPLIST_KEY_UIMainStoryboardFile = Main;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- IPHONEOS_DEPLOYMENT_TARGET = 16.6;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = design.supr.testReader;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Debug;
- };
- 39DBA7852D80A8B7001F1C5B /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = 7CSFZ8JM6F;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_FILE = testReader/Info.plist;
- INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
- INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
- INFOPLIST_KEY_UIMainStoryboardFile = Main;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
- IPHONEOS_DEPLOYMENT_TARGET = 16.6;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = design.supr.testReader;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Release;
- };
- 39DBA7862D80A8B7001F1C5B /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 18.2;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = iphoneos;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- };
- name = Debug;
- };
- 39DBA7872D80A8B7001F1C5B /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 18.2;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = NO;
- MTL_FAST_MATH = YES;
- SDKROOT = iphoneos;
- SWIFT_COMPILATION_MODE = wholemodule;
- VALIDATE_PRODUCT = YES;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 39DBA76B2D80A8B5001F1C5B /* Build configuration list for PBXProject "testReader" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 39DBA7862D80A8B7001F1C5B /* Debug */,
- 39DBA7872D80A8B7001F1C5B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 39DBA7832D80A8B7001F1C5B /* Build configuration list for PBXNativeTarget "testReader" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 39DBA7842D80A8B7001F1C5B /* Debug */,
- 39DBA7852D80A8B7001F1C5B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
-
-/* Begin XCRemoteSwiftPackageReference section */
- 39DBA7882D80A8EA001F1C5B /* XCRemoteSwiftPackageReference "SwiftSoup" */ = {
- isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/scinfu/SwiftSoup.git";
- requirement = {
- kind = upToNextMajorVersion;
- minimumVersion = 2.8.5;
- };
- };
- 39DBA78B2D80A917001F1C5B /* XCRemoteSwiftPackageReference "ZipArchive" */ = {
- isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/ZipArchive/ZipArchive.git";
- requirement = {
- kind = upToNextMajorVersion;
- minimumVersion = 2.6.0;
- };
- };
-/* End XCRemoteSwiftPackageReference section */
-
-/* Begin XCSwiftPackageProductDependency section */
- 39DBA7892D80A8EA001F1C5B /* SwiftSoup */ = {
- isa = XCSwiftPackageProductDependency;
- package = 39DBA7882D80A8EA001F1C5B /* XCRemoteSwiftPackageReference "SwiftSoup" */;
- productName = SwiftSoup;
- };
- 39DBA78C2D80A917001F1C5B /* ZipArchive */ = {
- isa = XCSwiftPackageProductDependency;
- package = 39DBA78B2D80A917001F1C5B /* XCRemoteSwiftPackageReference "ZipArchive" */;
- productName = ZipArchive;
- };
-/* End XCSwiftPackageProductDependency section */
- };
- rootObject = 39DBA7682D80A8B5001F1C5B /* Project object */;
-}
diff --git a/testReader.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/testReader.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 919434a..0000000
--- a/testReader.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
diff --git a/testReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/testReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
deleted file mode 100644
index fd25e78..0000000
--- a/testReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "originHash" : "19367b3643418ff79e73fbdbe1b64178c4ecc49c15528ac32025d89f06a0b532",
- "pins" : [
- {
- "identity" : "swiftsoup",
- "kind" : "remoteSourceControl",
- "location" : "https://github.com/scinfu/SwiftSoup.git",
- "state" : {
- "revision" : "64e4daa41b0f22affa94a6063d509c137c26909c",
- "version" : "2.8.5"
- }
- },
- {
- "identity" : "ziparchive",
- "kind" : "remoteSourceControl",
- "location" : "https://github.com/ZipArchive/ZipArchive.git",
- "state" : {
- "revision" : "df35718ea19a94e015b91dc4881dee028ce4cdba",
- "version" : "2.6.0"
- }
- }
- ],
- "version" : 3
-}
diff --git a/testReader.xcodeproj/project.xcworkspace/xcuserdata/shrutesh.xcuserdatad/UserInterfaceState.xcuserstate b/testReader.xcodeproj/project.xcworkspace/xcuserdata/shrutesh.xcuserdatad/UserInterfaceState.xcuserstate
deleted file mode 100644
index 206cd80..0000000
Binary files a/testReader.xcodeproj/project.xcworkspace/xcuserdata/shrutesh.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ
diff --git a/testReader.xcodeproj/xcuserdata/shrutesh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/testReader.xcodeproj/xcuserdata/shrutesh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
deleted file mode 100644
index dba7422..0000000
--- a/testReader.xcodeproj/xcuserdata/shrutesh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/testReader.xcodeproj/xcuserdata/shrutesh.xcuserdatad/xcschemes/xcschememanagement.plist b/testReader.xcodeproj/xcuserdata/shrutesh.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index fb61db6..0000000
--- a/testReader.xcodeproj/xcuserdata/shrutesh.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- SchemeUserState
-
- testReader.xcscheme_^#shared#^_
-
- orderHint
- 0
-
-
-
-
diff --git a/testReader/.DS_Store b/testReader/.DS_Store
deleted file mode 100644
index 76b65ac..0000000
Binary files a/testReader/.DS_Store and /dev/null differ
diff --git a/testReader/AppDelegate.swift b/testReader/AppDelegate.swift
deleted file mode 100644
index cd84948..0000000
--- a/testReader/AppDelegate.swift
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// AppDelegate.swift
-// testReader
-//
-// Created by shrutesh sharma on 11/03/25.
-//
-
-import UIKit
-
-@main
-class AppDelegate: UIResponder, UIApplicationDelegate {
- var window: UIWindow?
-
- func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
- window = UIWindow(frame: UIScreen.main.bounds)
- let navController = UINavigationController(rootViewController: LibraryViewController())
- window?.rootViewController = navController
- window?.makeKeyAndVisible()
- return true
- }
-}
-
diff --git a/testReader/Assets.xcassets/.DS_Store b/testReader/Assets.xcassets/.DS_Store
deleted file mode 100644
index e55472c..0000000
Binary files a/testReader/Assets.xcassets/.DS_Store and /dev/null differ
diff --git a/testReader/Assets.xcassets/AccentColor.colorset/Contents.json b/testReader/Assets.xcassets/AccentColor.colorset/Contents.json
deleted file mode 100644
index eb87897..0000000
--- a/testReader/Assets.xcassets/AccentColor.colorset/Contents.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "colors" : [
- {
- "idiom" : "universal"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/testReader/Assets.xcassets/AppIcon.appiconset/Contents.json b/testReader/Assets.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644
index 2305880..0000000
--- a/testReader/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- },
- {
- "appearances" : [
- {
- "appearance" : "luminosity",
- "value" : "dark"
- }
- ],
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- },
- {
- "appearances" : [
- {
- "appearance" : "luminosity",
- "value" : "tinted"
- }
- ],
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/testReader/Assets.xcassets/Contents.json b/testReader/Assets.xcassets/Contents.json
deleted file mode 100644
index 73c0059..0000000
--- a/testReader/Assets.xcassets/Contents.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
diff --git a/testReader/Base.lproj/LaunchScreen.storyboard b/testReader/Base.lproj/LaunchScreen.storyboard
deleted file mode 100644
index 865e932..0000000
--- a/testReader/Base.lproj/LaunchScreen.storyboard
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testReader/Base.lproj/Main.storyboard b/testReader/Base.lproj/Main.storyboard
deleted file mode 100644
index 25a7638..0000000
--- a/testReader/Base.lproj/Main.storyboard
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/testReader/EPUBMetadata.swift b/testReader/EPUBMetadata.swift
deleted file mode 100644
index b29addd..0000000
--- a/testReader/EPUBMetadata.swift
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// EPUBMetadata.swift
-// testReader
-//
-// Created by shrutesh sharma on 11/03/25.
-//
-
-
-import Foundation
-
-struct EPUBMetadata {
- let title: String
- let author: String
-}
-
-struct EPUBSpineItem {
- let id: String
- let href: String
-}
-
-struct EPUBTOCItem {
- let label: String
- let href: String
-}
-
-struct Bookmark: Codable {
- let spineIndex: Int
- let pageNumber: Int
- let date: Date
-
- // Computed property for display in bookmarks list
- var displayText: String {
- let formatter = DateFormatter()
- formatter.dateStyle = .short
- formatter.timeStyle = .short
- return "Page \(pageNumber + 1) - \(formatter.string(from: date))"
- }
-}
-
-struct Highlight: Codable {
- let spineIndex: Int
- let pageNumber: Int
- let text: String
- let range: NSRange
- let color: String
- let date: Date
- let textContext: String // Store surrounding text for better matching
- let relativePosition: Double // Position as percentage of spine content
-
- init(spineIndex: Int, pageNumber: Int, text: String, range: NSRange, color: String, textContext: String = "", relativePosition: Double = 0.0) {
- self.spineIndex = spineIndex
- self.pageNumber = pageNumber
- self.text = text
- self.range = range
- self.color = color
- self.date = Date()
- self.textContext = textContext
- self.relativePosition = relativePosition
- }
-
- // Computed property for display in highlights list
- var displayText: String {
- return "\(text)"
- }
-
- // Custom encoding for NSRange since it's not Codable by default
- enum CodingKeys: String, CodingKey {
- case spineIndex, pageNumber, text, range, color, date, textContext, relativePosition
- }
-
- func encode(to encoder: Encoder) throws {
- var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encode(spineIndex, forKey: .spineIndex)
- try container.encode(pageNumber, forKey: .pageNumber)
- try container.encode(text, forKey: .text)
- try container.encode(color, forKey: .color)
- try container.encode(date, forKey: .date)
- try container.encode(textContext, forKey: .textContext)
- try container.encode(relativePosition, forKey: .relativePosition)
-
- // Encode NSRange as location and length
- let rangeDict = ["location": range.location, "length": range.length]
- try container.encode(rangeDict, forKey: .range)
- }
-
- init(from decoder: Decoder) throws {
- let container = try decoder.container(keyedBy: CodingKeys.self)
- spineIndex = try container.decode(Int.self, forKey: .spineIndex)
- pageNumber = try container.decode(Int.self, forKey: .pageNumber)
- text = try container.decode(String.self, forKey: .text)
- color = try container.decode(String.self, forKey: .color)
- date = try container.decode(Date.self, forKey: .date)
- textContext = try container.decodeIfPresent(String.self, forKey: .textContext) ?? ""
- relativePosition = try container.decodeIfPresent(Double.self, forKey: .relativePosition) ?? 0.0
-
- // Decode NSRange from location and length
- let rangeDict = try container.decode([String: Int].self, forKey: .range)
- let location = rangeDict["location"] ?? 0
- let length = rangeDict["length"] ?? 0
- range = NSRange(location: location, length: length)
- }
-}
diff --git a/testReader/EPUBParser.swift b/testReader/EPUBParser.swift
deleted file mode 100644
index 6c569f8..0000000
--- a/testReader/EPUBParser.swift
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// EPUBParser.swift
-// testReader
-//
-// Created by shrutesh sharma on 11/03/25.
-//
-
-
-import Foundation
-import ZipArchive
-import SwiftSoup
-
-class EPUBParser {
- static func parseEPUB(at url: URL) -> (metadata: EPUBMetadata, spine: [EPUBSpineItem], toc: [EPUBTOCItem], baseURL: URL)? {
- let tempDir = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
- do {
- try SSZipArchive.unzipFile(atPath: url.path, toDestination: tempDir.path)
- let containerURL = tempDir.appendingPathComponent("META-INF/container.xml")
- guard let opfPath = parseContainerXML(at: containerURL) else { return nil }
- let opfURL = tempDir.appendingPathComponent(opfPath)
- guard let (metadata, spine, tocPath) = parseOPFFile(at: opfURL, baseURL: tempDir) else { return nil }
- let toc = parseTOCFile(at: tempDir.appendingPathComponent("/OPS"), baseURL: tempDir)
- return (metadata, spine, toc, tempDir)
- } catch {
- print("Error parsing EPUB: \(error)")
- return nil
- }
- }
-
- private static func parseContainerXML(at url: URL) -> String? {
- guard let xmlString = try? String(contentsOf: url),
- let doc = try? SwiftSoup.parse(xmlString) else { return nil }
- do {
- let rootFile = try doc.select("rootfile").first()
- return try rootFile?.attr("full-path")
- } catch {
- print("Error parsing container.xml: \(error)")
- return nil
- }
- }
-
- private static func parseOPFFile(at url: URL, baseURL: URL) -> (EPUBMetadata, [EPUBSpineItem], String)? {
- guard let xmlString = try? String(contentsOf: url),
- let doc = try? SwiftSoup.parse(xmlString) else { return nil }
-
- do {
- // Extract metadata by directly targeting tag names
- let metadataElement = try doc.select("metadata").first()
- let title = try metadataElement?.getElementsByTag("dc:title").first()?.text() ?? "Unknown Title"
- let author = try metadataElement?.getElementsByTag("dc:creator").first()?.text() ?? "Unknown Author"
- let metadata = EPUBMetadata(title: title, author: author)
-
- // Extract spine items
- var spineItems: [EPUBSpineItem] = []
- let manifestItems = try doc.select("manifest item")
- let spineRefs = try doc.select("spine itemref")
-
- for ref in spineRefs {
- let idref = try ref.attr("idref")
- var matchingItem: Element? = nil
- for item in manifestItems {
- if (try? item.attr("id")) == idref {
- matchingItem = item
- break
- }
- }
- if let item = matchingItem {
- let href = try item.attr("href")
- spineItems.append(EPUBSpineItem(id: idref, href: href))
- }
- }
-
- // Extract TOC path
- let tocID = try doc.select("spine").attr("toc")
- var tocItem: Element? = nil
- for item in manifestItems {
- if (try? item.attr("id")) == tocID {
- tocItem = item
- break
- }
- }
- let tocPath = try tocItem?.attr("href") ?? ""
-
- return (metadata, spineItems, tocPath)
- } catch {
- print("Error parsing .opf file: \(error)")
- return nil
- }
- }
-
- private static func parseTOCFile(at url: URL, baseURL: URL) -> [EPUBTOCItem] {
- guard let xmlString = try? String(contentsOf: url.appending(path: "toc.xhtml")),
- let doc = try? SwiftSoup.parse(xmlString) else { return [] }
- do {
- let navPoints = try doc.select("nav")
- var tocItems: [EPUBTOCItem] = []
- for nav in navPoints {
- let label = try nav.select("navLabel text").first()?.text() ?? ""
- let href = try nav.select("content").attr("src")
- tocItems.append(EPUBTOCItem(label: label, href: href))
- }
- return tocItems
- } catch {
- print("Error parsing TOC: \(error)")
- return []
- }
- }
-}
diff --git a/testReader/Info.plist b/testReader/Info.plist
deleted file mode 100644
index 97ff79d..0000000
--- a/testReader/Info.plist
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- UIApplicationSceneManifest
-
- UIApplicationSupportsMultipleScenes
-
-
-
-
diff --git a/testReader/LibraryViewController.swift b/testReader/LibraryViewController.swift
deleted file mode 100644
index 112b946..0000000
--- a/testReader/LibraryViewController.swift
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// LibraryViewController.swift
-// testReader
-//
-// Created by shrutesh sharma on 11/03/25.
-//
-
-
-import UIKit
-
-class LibraryViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
- private let tableView = UITableView()
- private var epubFiles: [URL] = []
-
- override func viewDidLoad() {
- super.viewDidLoad()
- title = "EPUB Library"
- view.backgroundColor = .white
- setupNavigationBar()
- setupTableView()
- loadEpubFiles()
- }
-
- private func setupNavigationBar() {
- navigationItem.rightBarButtonItem = UIBarButtonItem(
- title: "Settings",
- style: .plain,
- target: self,
- action: #selector(openSettings)
- )
- }
-
- @objc private func openSettings() {
- let settingsVC = SettingsViewController()
- navigationController?.pushViewController(settingsVC, animated: true)
- }
-
- private func setupTableView() {
- view.addSubview(tableView)
- tableView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
- ])
- tableView.dataSource = self
- tableView.delegate = self
- tableView.register(UITableViewCell.self, forCellReuseIdentifier: "EpubCell")
- }
-
- private func loadEpubFiles() {
- let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
- if let files = try? FileManager.default.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil) {
- epubFiles = files.filter { $0.pathExtension.lowercased() == "epub" }
- tableView.reloadData()
- }
- }
-
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return epubFiles.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = tableView.dequeueReusableCell(withIdentifier: "EpubCell", for: indexPath)
- cell.textLabel?.text = epubFiles[indexPath.row].lastPathComponent
- return cell
- }
-
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let readerVC = ReaderViewController(epubURL: epubFiles[indexPath.row])
- navigationController?.pushViewController(readerVC, animated: true)
- tableView.deselectRow(at: indexPath, animated: true)
- }
-}
diff --git a/testReader/PageContentViewController.swift b/testReader/PageContentViewController.swift
deleted file mode 100644
index 29a19ca..0000000
--- a/testReader/PageContentViewController.swift
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-// PageContentViewController.swift
-// testReader
-//
-// Created by shrutesh sharma on 28/05/25.
-//
-
-import UIKit
-import WebKit
-
-class PageContentViewController: UIViewController {
- let webView: WKWebView
- let pageIndex: Int
- var targetPageIndex: Int = 0
- weak var delegate: ReaderViewController?
-
- init(webView: WKWebView, pageIndex: Int, delegate: ReaderViewController?) {
- self.webView = webView
- self.pageIndex = pageIndex
- self.targetPageIndex = pageIndex
- self.delegate = delegate
- super.init(nibName: nil, bundle: nil)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.addSubview(webView)
- webView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
- webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- webView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
- ])
-
- // Enable the menu controller
- becomeFirstResponder()
- }
-
- override var canBecomeFirstResponder: Bool {
- return true
- }
-
- override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
- if action == #selector(highlightSelectedText) || action == #selector(bookmarkFromMenu) {
- return true
- }
- return super.canPerformAction(action, withSender: sender)
- }
-
- @objc func highlightSelectedText() {
- // Forward the action to the delegate (ReaderViewController)
- delegate?.highlightSelectedText()
- }
-
- @objc func bookmarkFromMenu() {
- // Forward the action to the delegate (ReaderViewController)
- delegate?.bookmarkFromMenu()
- }
-
- override func viewWillAppear(_ animated: Bool) {
- super.viewWillAppear(animated)
- // Just set the page index when view appears - no translation needed
- if webView.alpha > 0 {
- delegate?.scrollToPage(in: webView, pageIndex: targetPageIndex)
- }
- }
-}
diff --git a/testReader/ReaderViewController.swift b/testReader/ReaderViewController.swift
deleted file mode 100644
index a9d2aba..0000000
--- a/testReader/ReaderViewController.swift
+++ /dev/null
@@ -1,977 +0,0 @@
-//
-// ReaderViewController.swift
-// testReader
-//
-// Created by shrutesh sharma on 11/03/25.
-//
-
-import UIKit
-import WebKit
-import SwiftSoup
-
-class ReaderViewController: UIViewController, WKNavigationDelegate, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UITableViewDataSource, UITableViewDelegate {
- private var pageViewController: UIPageViewController!
- private let epubURL: URL
- private var spineItems: [EPUBSpineItem] = []
- private var currentSpineIndex = 0
- private var currentPage = 0
- private var totalPages = 0
- private var totalPagesPerSpine: [Int] = [] // Track pages per chapter
- private var baseURL: URL?
- private var isPageCurlEnabled = UserDefaults.standard.bool(forKey: "isPageCurlEnabled")
- private let pageLabel = UILabel()
- private var bookmarks: [Bookmark] = []
- private var highlights: [Highlight] = []
- private let tocTableView = UITableView()
- private let highlightsTableView = UITableView()
- private var tocItems: [EPUBTOCItem] = []
- private let bookmarksTableView = UITableView()
-
- init(epubURL: URL) {
- self.epubURL = epubURL
- super.init(nibName: nil, bundle: nil)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = .white
- setupNavigationBar()
- setupPageLabel()
-
- // Load data first before parsing EPUB
- loadHighlights()
- loadBookmarks()
-
- parseAndLoadEPUB()
- setupPageViewController()
- setupMenuController()
- }
-
- override func viewDidAppear(_ animated: Bool) {
- super.viewDidAppear(animated)
- setupTOCView()
- setupHighlightsView()
- setupBookmarksView()
- // Data already loaded in viewDidLoad, just reload table views
- highlightsTableView.reloadData()
- bookmarksTableView.reloadData()
- }
-
- override func viewWillAppear(_ animated: Bool) {
- super.viewWillAppear(animated)
-
- // Check if page curl setting changed
- let newPageCurlSetting = UserDefaults.standard.bool(forKey: "isPageCurlEnabled")
- if newPageCurlSetting != isPageCurlEnabled {
- isPageCurlEnabled = newPageCurlSetting
- // Recreate page view controller with new style
- recreatePageViewController()
- }
- }
-
- func setupMenuController() {
- // Add custom menu items for highlighting and bookmarking
- let highlightMenuItem = UIMenuItem(title: "Highlight", action: #selector(highlightSelectedText))
- let bookmarkMenuItem = UIMenuItem(title: "Bookmark", action: #selector(bookmarkFromMenu))
- UIMenuController.shared.menuItems = [highlightMenuItem, bookmarkMenuItem]
- }
-
- @objc func highlightSelectedText() {
- guard let currentPageVC = pageViewController.viewControllers?.first as? PageContentViewController else {
- return
- }
-
- // Get the highlight color from settings
- let highlightColor = UserDefaults.standard.string(forKey: "highlightColor") ?? "yellow"
-
- let webView = currentPageVC.webView
- let highlightJS = """
- (function() {
- var selection = window.getSelection();
- if (selection.rangeCount > 0) {
- var range = selection.getRangeAt(0);
- var span = document.createElement('span');
- span.className = 'highlight';
- span.style.backgroundColor = '\(highlightColor)';
- span.style.color = 'black';
-
- var selectedText = selection.toString();
-
- // Get context around the selection for better matching
- var textContent = document.body.textContent || document.body.innerText;
- var selectedIndex = textContent.indexOf(selectedText);
- var contextStart = Math.max(0, selectedIndex - 50);
- var contextEnd = Math.min(textContent.length, selectedIndex + selectedText.length + 50);
- var textContext = textContent.substring(contextStart, contextEnd);
-
- // Calculate relative position in the document
- var relativePosition = selectedIndex / textContent.length;
-
- try {
- range.surroundContents(span);
- selection.removeAllRanges();
-
- // Return the highlighted data to Swift
- return {
- text: selectedText,
- context: textContext,
- position: relativePosition
- };
- } catch(e) {
- var contents = range.extractContents();
- span.appendChild(contents);
- range.insertNode(span);
- selection.removeAllRanges();
-
- // Return the highlighted data to Swift
- return {
- text: selectedText,
- context: textContext,
- position: relativePosition
- };
- }
- }
- return null;
- })();
- """
-
- webView.evaluateJavaScript(highlightJS) { result, error in
- if let result = result as? [String: Any],
- let text = result["text"] as? String,
- let context = result["context"] as? String,
- let position = result["position"] as? Double,
- !text.isEmpty {
-
- let highlight = Highlight(
- spineIndex: self.currentSpineIndex,
- pageNumber: self.currentPage,
- text: text,
- range: NSRange(location: 0, length: text.count),
- color: highlightColor,
- textContext: context,
- relativePosition: position
- )
-
- self.highlights.append(highlight)
- self.saveHighlights()
- print("Highlight saved: \(text) with color: \(highlightColor)")
- }
- }
- }
-
- private func recreatePageViewController() {
- // Remove old page view controller
- pageViewController.willMove(toParent: nil)
- pageViewController.view.removeFromSuperview()
- pageViewController.removeFromParent()
-
- // Create new one with updated settings
- setupPageViewController()
- }
-
- private func setupPageViewController() {
- let style: UIPageViewController.TransitionStyle = isPageCurlEnabled ? .pageCurl : .scroll
- pageViewController = UIPageViewController(transitionStyle: style, navigationOrientation: .horizontal, options: nil)
- pageViewController.dataSource = self
- pageViewController.delegate = self
- addChild(pageViewController)
- view.addSubview(pageViewController.view)
- pageViewController.view.frame = view.bounds
- pageViewController.view.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- pageViewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- pageViewController.view.bottomAnchor.constraint(equalTo: pageLabel.topAnchor, constant: -10),
- pageViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- pageViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor)
- ])
- // Load the initial page
- if let initialPage = createPageViewController(for: currentPage) {
- pageViewController.setViewControllers([initialPage], direction: .forward, animated: false)
- }
- }
-
- private func setupTOCView() {
- tocTableView.isHidden = true
- tocTableView.dataSource = self
- tocTableView.delegate = self
- tocTableView.register(UITableViewCell.self, forCellReuseIdentifier: "TOCCell")
- view.addSubview(tocTableView)
- tocTableView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- tocTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- tocTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- tocTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- tocTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
- ])
- }
-
- private func setupHighlightsView() {
- highlightsTableView.isHidden = true
- highlightsTableView.dataSource = self
- highlightsTableView.delegate = self
- highlightsTableView.register(UITableViewCell.self, forCellReuseIdentifier: "HighlightCell")
- view.addSubview(highlightsTableView)
- highlightsTableView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- highlightsTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- highlightsTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- highlightsTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- highlightsTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
- ])
- }
-
- private func setupBookmarksView() {
- bookmarksTableView.isHidden = true
- bookmarksTableView.dataSource = self
- bookmarksTableView.delegate = self
- bookmarksTableView.register(UITableViewCell.self, forCellReuseIdentifier: "BookmarkCell")
- view.addSubview(bookmarksTableView)
- bookmarksTableView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- bookmarksTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- bookmarksTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- bookmarksTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- bookmarksTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
- ])
- }
-
- private func setupPageLabel() {
- view.addSubview(pageLabel)
- pageLabel.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- pageLabel.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10),
- pageLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor)
- ])
- pageLabel.textAlignment = .center
- }
-
- private func setupNavigationBar() {
- navigationItem.rightBarButtonItems = [
- UIBarButtonItem(title: "Highlights", style: .plain, target: self, action: #selector(toggleHighlights)),
- UIBarButtonItem(title: "Bookmarks", style: .plain, target: self, action: #selector(toggleBookmarks)),
- UIBarButtonItem(title: "TOC", style: .plain, target: self, action: #selector(toggleTOC))
- ]
- }
-
-
- @objc func bookmarkFromMenu() {
- addBookmark()
- }
-
- // Add bookmark
- @objc func addBookmark() {
- let bookmark = Bookmark(spineIndex: currentSpineIndex, pageNumber: currentPage, date: Date())
- bookmarks.append(bookmark)
- saveBookmarks()
- print("Bookmark added: \(bookmark)")
-
- // Show confirmation
- let alert = UIAlertController(title: "Bookmark Added", message: "Page bookmarked successfully", preferredStyle: .alert)
- alert.addAction(UIAlertAction(title: "OK", style: .default))
- present(alert, animated: true)
- }
-
- // Save bookmarks to UserDefaults
- private func saveBookmarks() {
- let encoder = JSONEncoder()
- if let encoded = try? encoder.encode(bookmarks) {
- UserDefaults.standard.set(encoded, forKey: "savedBookmarks")
- print("Bookmarks saved: \(bookmarks.count) total")
- }
- }
-
- // Load bookmarks from UserDefaults
- private func loadBookmarks() {
- if let savedBookmarks = UserDefaults.standard.object(forKey: "savedBookmarks") as? Data {
- let decoder = JSONDecoder()
- if let loadedBookmarks = try? decoder.decode([Bookmark].self, from: savedBookmarks) {
- bookmarks = loadedBookmarks
- print("Bookmarks loaded: \(bookmarks.count) total")
- }
- }
- }
-
- // Load highlights from UserDefaults
- private func loadHighlights() {
- if let savedHighlights = UserDefaults.standard.object(forKey: "savedHighlights") as? Data {
- let decoder = JSONDecoder()
- if let loadedHighlights = try? decoder.decode([Highlight].self, from: savedHighlights) {
- highlights = loadedHighlights
- print("Highlights loaded: \(highlights.count) total")
- }
- }
- }
-
- // Save highlights to UserDefaults
- private func saveHighlights() {
- let encoder = JSONEncoder()
- if let encoded = try? encoder.encode(highlights) {
- UserDefaults.standard.set(encoded, forKey: "savedHighlights")
- print("Highlights saved: \(highlights.count) total")
- }
- }
-
- // Apply saved highlights to a WebView
- private func applySavedHighlights(to webView: WKWebView) {
- let currentHighlights = highlights.filter { $0.spineIndex == currentSpineIndex }
-
- for (index, highlight) in currentHighlights.enumerated() {
- let highlightJS = """
- (function() {
- var textContent = document.body.textContent || document.body.innerText;
- var searchText = '\(highlight.text.replacingOccurrences(of: "'", with: "\\'"))';
- var context = '\(highlight.textContext.replacingOccurrences(of: "'", with: "\\'"))';
-
- // Try to find the text using context first
- var foundIndex = -1;
- if (context.length > 0) {
- var contextIndex = textContent.indexOf(context);
- if (contextIndex !== -1) {
- var relativeIndexInContext = context.indexOf(searchText);
- if (relativeIndexInContext !== -1) {
- foundIndex = contextIndex + relativeIndexInContext;
- }
- }
- } else {
- // Fallback: use relative position
- var estimatedIndex = Math.floor(textContent.length * \(highlight.relativePosition));
- var searchWindow = 200; // Search within 200 characters
- var startSearch = Math.max(0, estimatedIndex - searchWindow);
- var endSearch = Math.min(textContent.length, estimatedIndex + searchWindow);
- var searchArea = textContent.substring(startSearch, endSearch);
- var localIndex = searchArea.indexOf(searchText);
- if (localIndex !== -1) {
- foundIndex = startSearch + localIndex;
- }
- }
-
- // Final fallback: simple indexOf
- if (foundIndex === -1) {
- foundIndex = textContent.indexOf(searchText);
- }
-
- if (foundIndex !== -1) {
- // Find the text node and apply highlighting
- var walker = document.createTreeWalker(
- document.body,
- NodeFilter.SHOW_TEXT,
- null,
- false
- );
-
- var currentIndex = 0;
- var node;
- while (node = walker.nextNode()) {
- var nodeLength = node.textContent.length;
- if (currentIndex + nodeLength > foundIndex) {
- var localStart = foundIndex - currentIndex;
- var localEnd = localStart + searchText.length;
-
- if (localEnd <= nodeLength) {
- var range = document.createRange();
- range.setStart(node, localStart);
- range.setEnd(node, localEnd);
-
- var span = document.createElement('span');
- span.style.backgroundColor = '\(highlight.color)';
- span.style.color = 'black';
- span.className = 'saved-highlight-\(index)';
- span.setAttribute('data-highlight-id', '\(index)');
-
- try {
- range.surroundContents(span);
- return true;
- } catch(e) {
- var contents = range.extractContents();
- span.appendChild(contents);
- range.insertNode(span);
- return true;
- }
- }
- }
- currentIndex += nodeLength;
- }
- }
- return false;
- })();
- """
-
- webView.evaluateJavaScript(highlightJS) { success, error in
- if let error = error {
- print("Error applying saved highlight: \(error)")
- } else if let success = success as? Bool, success {
- print("Successfully applied highlight: \(highlight.text)")
- }
- }
- }
- }
-
- @objc private func toggleBookmarks() {
- bookmarksTableView.isHidden = !bookmarksTableView.isHidden
- tocTableView.isHidden = true
- highlightsTableView.isHidden = true
- bookmarksTableView.reloadData()
- }
-
- @objc private func toggleTOC() {
- tocTableView.isHidden = !tocTableView.isHidden
- highlightsTableView.isHidden = true
- bookmarksTableView.isHidden = true
-
- // Load TOC from HTML file if empty
- if tocItems.isEmpty {
- loadTOCFromHTML()
- }
-
- tocTableView.reloadData()
- print("TOC toggled, items count: \(tocItems.count)")
- }
-
- @objc private func toggleHighlights() {
- highlightsTableView.isHidden = !highlightsTableView.isHidden
- tocTableView.isHidden = true
- bookmarksTableView.isHidden = true
- highlightsTableView.reloadData()
- }
-
- private func parseAndLoadEPUB() {
- guard let (metadata, spine, toc, baseURL) = EPUBParser.parseEPUB(at: epubURL) else { return }
- title = metadata.title
- spineItems = spine
- tocItems = toc // Keep this for fallback
- self.baseURL = baseURL
- totalPagesPerSpine = Array(repeating: 1, count: spine.count)
-
- // Try to load TOC from HTML file
- loadTOCFromHTML()
- }
-
- private func loadTOCFromHTML() {
- guard let baseURL = baseURL else { return }
-
- let tocURL = baseURL.appendingPathComponent("OPS/toc.xhtml")
-
- do {
- let tocHTML = try String(contentsOf: tocURL)
- let doc = try SwiftSoup.parse(tocHTML)
-
- // Parse the TOC HTML - typically contains nav or ol/li structure
- var newTocItems: [EPUBTOCItem] = []
-
- // Try to find navigation elements (EPUB3 style)
- if let nav = try doc.select("nav").first() {
- let links = try nav.select("a")
- for link in links {
- let href = try link.attr("href")
- let label = try link.text()
- if !href.isEmpty && !label.isEmpty {
- newTocItems.append(EPUBTOCItem(label: label, href: href))
- }
- }
- } else {
- // Fallback: look for any links in the document
- let links = try doc.select("a")
- for link in links {
- let href = try link.attr("href")
- let label = try link.text()
- if !href.isEmpty && !label.isEmpty {
- newTocItems.append(EPUBTOCItem(label: label, href: href))
- }
- }
- }
-
- if !newTocItems.isEmpty {
- tocItems = newTocItems
- print("Loaded \(tocItems.count) TOC items from TOC.html")
- } else {
- print("No TOC items found in TOC.html, using existing TOC")
- }
-
- } catch {
- print("Error loading TOC.html: \(error)")
- // Keep existing tocItems as fallback
- }
- }
-
- private func createPageViewController(for pageIndex: Int) -> PageContentViewController? {
- guard let baseURL = baseURL, currentSpineIndex < spineItems.count else { return nil }
-
- // Create fresh WKWebViewConfiguration for each page
- let config = WKWebViewConfiguration()
- let webView = WKWebView(frame: .zero, configuration: config)
-
- webView.scrollView.isScrollEnabled = false
- webView.navigationDelegate = self
- webView.alpha = 0 // Hide initially to prevent flickering
- let htmlURL = baseURL.appendingPathComponent("OPS/\(spineItems[currentSpineIndex].href)")
- webView.loadFileURL(htmlURL, allowingReadAccessTo: baseURL)
-
- let pageVC = PageContentViewController(webView: webView, pageIndex: pageIndex, delegate: self)
- pageVC.targetPageIndex = pageIndex
- return pageVC
- }
-
- func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
- applySettings(to: webView)
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
- self.calculateTotalPages(for: webView)
- // Find the PageContentViewController that owns this webView and scroll to its target page
- if let pageVC = self.findPageViewController(for: webView) {
- self.scrollToPage(in: webView, pageIndex: pageVC.targetPageIndex) {
- // Apply saved highlights after page is positioned and content is loaded
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
- self.applySavedHighlights(to: webView)
- // Show the web view after everything is ready
- webView.alpha = 1
- }
- }
- } else {
- // If not found, still apply highlights and show the web view
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
- self.applySavedHighlights(to: webView)
- webView.alpha = 1
- }
- }
- }
- }
-
- private func findPageViewController(for webView: WKWebView) -> PageContentViewController? {
- // Check current page view controller
- if let currentVC = pageViewController.viewControllers?.first as? PageContentViewController,
- currentVC.webView == webView {
- return currentVC
- }
- return nil
- }
-
- private func calculateTotalPages(for webView: WKWebView) {
- webView.evaluateJavaScript("window.getTotalPages()") { (totalPages, error) in
- if let pages = totalPages as? Int, pages > 0 {
- self.totalPagesPerSpine[self.currentSpineIndex] = pages
- self.totalPages = pages
- self.currentPage = min(self.currentPage, self.totalPages - 1)
- self.updatePageLabel()
- self.scrollToPage(in: webView, pageIndex: self.currentPage)
- } else {
- // Fallback: use a default single page if calculation fails
- print("Page calculation failed - using default single page")
- print("Total pages result: \(totalPages ?? "nil")")
- self.totalPagesPerSpine[self.currentSpineIndex] = 1
- self.totalPages = 1
- self.currentPage = 0
- self.updatePageLabel()
- }
- }
- }
-
- private func applySettings(to webView: WKWebView) {
- let backgroundColor = UserDefaults.standard.string(forKey: "backgroundColor") ?? "#FFFFFF"
- let fontFamily = UserDefaults.standard.string(forKey: "fontFamily") ?? "Georgia"
- let fontSize = UserDefaults.standard.integer(forKey: "fontSize") > 0 ? UserDefaults.standard.integer(forKey: "fontSize") : 16
- let isDarkMode = UserDefaults.standard.bool(forKey: "isDarkMode")
-
- let viewHeight = view.safeAreaLayoutGuide.layoutFrame.height - pageLabel.frame.height - 20
- let viewWidth = view.frame.width - 40
-
- let css = """
- * {
- -webkit-touch-callout: default;
- box-sizing: border-box;
- }
- html {
- margin: 0;
- padding: 0;
- height: 100vh;
- overflow: hidden;
- background-color: \(backgroundColor);
- }
- body {
- margin: 0;
- padding: 20px;
- font-family: '\(fontFamily)', serif;
- font-size: \(fontSize)px;
- color: \(isDarkMode ? "#FFFFFF" : "#000000");
- line-height: 1.6;
-
- /* Enable text selection */
- -webkit-user-select: text;
- -moz-user-select: text;
- -ms-user-select: text;
- user-select: text;
-
- /* Column-based pagination */
- column-width: \(viewWidth)px;
- column-height: \(viewHeight - 40)px;
- column-gap: 20px;
- column-fill: auto;
-
- /* Fixed height for consistent pagination */
- height: \(viewHeight - 40)px;
- width: auto;
- overflow: hidden;
-
- /* Prevent awkward breaks */
- orphans: 2;
- widows: 2;
- }
- p {
- margin-bottom: 1em;
- break-inside: avoid-column;
- -webkit-user-select: text;
- user-select: text;
- }
- h1, h2, h3, h4, h5, h6 {
- margin-top: 1.5em;
- margin-bottom: 0.5em;
- break-after: avoid-column;
- break-inside: avoid-column;
- -webkit-user-select: text;
- user-select: text;
- }
- img {
- max-width: 100%;
- height: auto;
- break-inside: avoid-column;
- }
- blockquote, pre {
- break-inside: avoid-column;
- -webkit-user-select: text;
- user-select: text;
- }
-
- /* Highlight styles */
- .highlight {
- background-color: yellow;
- color: black;
- }
- """
-
- let js = """
- var meta = document.createElement('meta');
- meta.name = "viewport";
- meta.content = "width=device-width, initial-scale=1.0, user-scalable=no";
- document.head.appendChild(meta);
-
- var style = document.createElement('style');
- style.type = "text/css";
- style.textContent = `\(css)`;
- document.head.appendChild(style);
-
- // Page configuration
- var pageConfig = {
- columnWidth: \(viewWidth),
- columnGap: 20,
- viewportWidth: \(viewWidth),
- targetPageIndex: 0
- };
-
- // Disable body scrolling but allow text selection
- document.body.style.overflowX = 'hidden';
- document.body.style.overflowY = 'hidden';
- window.addEventListener('scroll', function(e) { e.preventDefault(); });
- window.addEventListener('wheel', function(e) { e.preventDefault(); });
-
- // Existing page functions...
- window.getTotalPages = function() {
- var computedStyle = window.getComputedStyle(document.body);
- var columnWidth = parseFloat(computedStyle.columnWidth) || pageConfig.columnWidth;
- var columnGap = parseFloat(computedStyle.columnGap) || pageConfig.columnGap;
-
- var totalWidth = document.body.scrollWidth;
- var singleColumnWidth = columnWidth + columnGap;
- var totalColumns = Math.ceil(totalWidth / singleColumnWidth);
-
- console.log('Total width: ' + totalWidth + ', Single column: ' + singleColumnWidth + ', Columns: ' + totalColumns);
- return Math.max(1, totalColumns);
- };
-
- window.setPageIndex = function(pageIndex) {
- pageConfig.targetPageIndex = pageIndex;
-
- var columnWidth = pageConfig.columnWidth;
- var columnGap = pageConfig.columnGap;
- var singleColumnWidth = columnWidth + columnGap;
-
- var leftPosition = pageIndex * singleColumnWidth;
-
- var clipPath = 'inset(0 0 0 ' + leftPosition + 'px)';
- document.body.style.clipPath = clipPath;
- document.body.style.webkitClipPath = clipPath;
- document.body.style.marginLeft = '-' + leftPosition + 'px';
-
- return {
- totalPages: window.getTotalPages(),
- currentPage: pageIndex
- };
- };
-
- window.getCurrentPage = function() {
- return pageConfig.targetPageIndex;
- };
-
- window.refreshLayout = function() {
- document.body.style.display = 'none';
- document.body.offsetHeight;
- document.body.style.display = '';
- return window.getTotalPages();
- };
- """
-
- webView.evaluateJavaScript(js) { _, error in
- if let error = error {
- print("Error injecting settings: \(error)")
- }
- }
- }
-
- func scrollToPage(in webView: WKWebView, pageIndex: Int, completion: (() -> Void)? = nil) {
- webView.evaluateJavaScript("window.setPageIndex(\(pageIndex))") { result, error in
- if let error = error {
- print("Error setting page index: \(error)")
- }
- completion?()
- }
- }
-
- private func updatePageLabel() {
- let globalPageNumber = getCurrentGlobalPageNumber()
- let totalGlobalPages = getTotalGlobalPages()
- pageLabel.text = "Page \(globalPageNumber) of \(totalGlobalPages)"
- }
-
- private func getCurrentGlobalPageNumber() -> Int {
- var globalPage = 1
- for i in 0.. Int {
- return totalPagesPerSpine.reduce(0, +)
- }
-
- // MARK: - UIPageViewController DataSource
- func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
- guard let current = viewController as? PageContentViewController else { return nil }
-
- if current.pageIndex > 0 {
- // Previous page in same chapter
- let previousPage = current.pageIndex - 1
- currentPage = previousPage
- return createPageViewController(for: previousPage)
- } else if currentSpineIndex > 0 {
- // Move to previous chapter, last page
- currentSpineIndex -= 1
- let lastPage = max(0, totalPagesPerSpine[currentSpineIndex] - 1)
- currentPage = lastPage
- return createPageViewController(for: lastPage)
- }
- return nil
- }
-
- func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
- guard let current = viewController as? PageContentViewController else { return nil }
-
- if current.pageIndex < totalPagesPerSpine[currentSpineIndex] - 1 {
- // Next page in same chapter
- let nextPage = current.pageIndex + 1
- currentPage = nextPage
- return createPageViewController(for: nextPage)
- } else if currentSpineIndex < spineItems.count - 1 {
- // Move to next chapter, first page
- currentSpineIndex += 1
- currentPage = 0
- return createPageViewController(for: 0)
- }
- return nil
- }
-
- func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
- if completed, let current = pageViewController.viewControllers?.first as? PageContentViewController {
- currentPage = current.pageIndex
- updatePageLabel()
- }
- }
-
- // MARK: - UITableViewDataSource
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- if tableView == tocTableView {
- print("TOC table view requesting \(tocItems.count) rows")
- return tocItems.count
- }
- if tableView == highlightsTableView { return highlights.count }
- if tableView == bookmarksTableView { return bookmarks.count }
- return 0
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- if tableView == tocTableView {
- let cell = tableView.dequeueReusableCell(withIdentifier: "TOCCell", for: indexPath)
- let tocItem = tocItems[indexPath.row]
- cell.textLabel?.text = tocItem.label
- cell.textLabel?.numberOfLines = 0
- cell.accessoryType = .disclosureIndicator
- print("TOC cell configured: \(tocItem.label)")
- return cell
- } else if tableView == highlightsTableView {
- let cell = tableView.dequeueReusableCell(withIdentifier: "HighlightCell", for: indexPath)
- let highlight = highlights[indexPath.row]
- cell.textLabel?.text = highlight.displayText
- cell.textLabel?.numberOfLines = 0
-
- // Set background color to match the highlight color
- switch highlight.color {
- case "yellow":
- cell.backgroundColor = UIColor.yellow.withAlphaComponent(0.3)
- case "green":
- cell.backgroundColor = UIColor.green.withAlphaComponent(0.3)
- case "pink":
- cell.backgroundColor = UIColor.systemPink.withAlphaComponent(0.3)
- default:
- cell.backgroundColor = UIColor.yellow.withAlphaComponent(0.3)
- }
- return cell
- } else {
- let cell = tableView.dequeueReusableCell(withIdentifier: "BookmarkCell", for: indexPath)
- let bookmark = bookmarks[indexPath.row]
- let formatter = DateFormatter()
- formatter.dateStyle = .short
- formatter.timeStyle = .short
- cell.textLabel?.text = "Page \(bookmark.pageNumber + 1) - \(formatter.string(from: bookmark.date))"
- cell.textLabel?.numberOfLines = 0
- return cell
- }
- }
-
- // MARK: - UITableViewDelegate
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- if tableView == tocTableView {
- let tocItem = tocItems[indexPath.row]
- print("TOC item selected: \(tocItem.label), href: \(tocItem.href)")
-
- // Clean the href - remove any leading "./" and handle fragments
- var cleanHref = tocItem.href
- if cleanHref.hasPrefix("./") {
- cleanHref = String(cleanHref.dropFirst(2))
- }
-
- // Split href and fragment if present
- let components = cleanHref.components(separatedBy: "#")
- let fileHref = components[0]
-
- // Find the spine index that matches the TOC href
- if let index = spineItems.firstIndex(where: { spine in
- let spineHref = spine.href.components(separatedBy: "#")[0]
- return spineHref == fileHref || spineHref.hasSuffix(fileHref) || fileHref.hasSuffix(spineHref)
- }) {
- currentSpineIndex = index
- currentPage = 0
- if let newPage = createPageViewController(for: currentPage) {
- pageViewController.setViewControllers([newPage], direction: .forward, animated: false)
- }
- updatePageLabel()
- toggleTOC()
- print("Navigated to spine index: \(index) for file: \(fileHref)")
- } else {
- print("Could not find matching spine for TOC href: \(fileHref)")
- print("Available spine hrefs: \(spineItems.map { $0.href })")
- }
- } else if tableView == highlightsTableView {
- let highlight = highlights[indexPath.row]
- currentSpineIndex = highlight.spineIndex
-
- // Navigate to the spine first
- if let newPage = createPageViewController(for: 0) {
- pageViewController.setViewControllers([newPage], direction: .forward, animated: false)
- }
-
- // Find the correct page after the content loads
- DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
- self.findAndNavigateToHighlight(highlight)
- }
-
- toggleHighlights()
- } else {
- currentSpineIndex = bookmarks[indexPath.row].spineIndex
- currentPage = bookmarks[indexPath.row].pageNumber
- if let newPage = createPageViewController(for: currentPage) {
- pageViewController.setViewControllers([newPage], direction: .forward, animated: false)
- }
- updatePageLabel()
- toggleBookmarks()
- }
- tableView.deselectRow(at: indexPath, animated: true)
- }
-
- private func findAndNavigateToHighlight(_ highlight: Highlight) {
- guard let currentPageVC = pageViewController.viewControllers?.first as? PageContentViewController else {
- return
- }
-
- let webView = currentPageVC.webView
- let findHighlightJS = """
- (function() {
- var textContent = document.body.textContent || document.body.innerText;
- var searchText = '\(highlight.text.replacingOccurrences(of: "'", with: "\\'"))';
- var context = '\(highlight.textContext.replacingOccurrences(of: "'", with: "\\'"))';
-
- // Find the text position
- var foundIndex = -1;
- if (context.length > 0) {
- var contextIndex = textContent.indexOf(context);
- if (contextIndex !== -1) {
- var relativeIndexInContext = context.indexOf(searchText);
- if (relativeIndexInContext !== -1) {
- foundIndex = contextIndex + relativeIndexInContext;
- }
- }
- }
-
- if (foundIndex === -1) {
- var estimatedIndex = Math.floor(textContent.length * \(highlight.relativePosition));
- var searchWindow = 200;
- var startSearch = Math.max(0, estimatedIndex - searchWindow);
- var endSearch = Math.min(textContent.length, estimatedIndex + searchWindow);
- var searchArea = textContent.substring(startSearch, endSearch);
- var localIndex = searchArea.indexOf(searchText);
- if (localIndex !== -1) {
- foundIndex = startSearch + localIndex;
- }
- }
-
- if (foundIndex === -1) {
- foundIndex = textContent.indexOf(searchText);
- }
-
- if (foundIndex !== -1) {
- // Calculate which page this text would be on
- var totalPages = window.getTotalPages();
- var textPerPage = textContent.length / totalPages;
- var estimatedPage = Math.floor(foundIndex / textPerPage);
- return Math.max(0, Math.min(estimatedPage, totalPages - 1));
- }
-
- return 0;
- })();
- """
-
- webView.evaluateJavaScript(findHighlightJS) { result, error in
- if let pageNumber = result as? Int {
- self.currentPage = pageNumber
- self.scrollToPage(in: webView, pageIndex: pageNumber) {
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
- self.updatePageLabel()
- }
- }
- }
- }
- }
-}
-
-
diff --git a/testReader/SettingsViewController.swift b/testReader/SettingsViewController.swift
deleted file mode 100644
index d4f6239..0000000
--- a/testReader/SettingsViewController.swift
+++ /dev/null
@@ -1,176 +0,0 @@
-//
-// SettingsViewController.swift
-// testReader
-//
-// Created by shrutesh sharma on 11/03/25.
-//
-
-import UIKit
-
-class SettingsViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
- private let darkModeSwitch = UISwitch()
- private let backgroundColorPicker = UIPickerView()
- private let fontFamilyPicker = UIPickerView()
- private let fontSizeSlider = UISlider()
- private let highlightColorPicker = UIPickerView()
- private let pageCurlSwitch = UISwitch()
-
- private let colors = ["#FFFFFF", "#F5F5DC", "#E0E0E0"]
- private let colorNames = ["White", "Beige", "Gray"]
- private let fonts = ["Georgia", "Times New Roman", "Helvetica"]
- private let highlightColors = ["yellow", "green", "pink"]
-
- override func viewDidLoad() {
- super.viewDidLoad()
- title = "Settings"
- view.backgroundColor = .white
- setupUI()
- loadCurrentSettings()
- }
-
- private func setupUI() {
- let darkModeLabel = UILabel()
- darkModeLabel.text = "Dark Mode"
- darkModeLabel.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(darkModeLabel)
- darkModeSwitch.translatesAutoresizingMaskIntoConstraints = false
- darkModeSwitch.addTarget(self, action: #selector(saveSettings), for: .valueChanged)
- view.addSubview(darkModeSwitch)
-
- let bgLabel = UILabel()
- bgLabel.text = "Background Color"
- bgLabel.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(bgLabel)
- backgroundColorPicker.translatesAutoresizingMaskIntoConstraints = false
- backgroundColorPicker.dataSource = self
- backgroundColorPicker.delegate = self
- view.addSubview(backgroundColorPicker)
-
- let fontLabel = UILabel()
- fontLabel.text = "Font Family"
- fontLabel.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(fontLabel)
- fontFamilyPicker.translatesAutoresizingMaskIntoConstraints = false
- fontFamilyPicker.dataSource = self
- fontFamilyPicker.delegate = self
- view.addSubview(fontFamilyPicker)
-
- let sizeLabel = UILabel()
- sizeLabel.text = "Font Size"
- sizeLabel.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(sizeLabel)
- fontSizeSlider.translatesAutoresizingMaskIntoConstraints = false
- fontSizeSlider.minimumValue = 12
- fontSizeSlider.maximumValue = 24
- fontSizeSlider.addTarget(self, action: #selector(saveSettings), for: .valueChanged)
- view.addSubview(fontSizeSlider)
-
- let highlightLabel = UILabel()
- highlightLabel.text = "Highlight Color"
- highlightLabel.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(highlightLabel)
- highlightColorPicker.translatesAutoresizingMaskIntoConstraints = false
- highlightColorPicker.dataSource = self
- highlightColorPicker.delegate = self
- view.addSubview(highlightColorPicker)
-
- let pageCurlLabel = UILabel()
- pageCurlLabel.text = "Page Curl Animation"
- pageCurlLabel.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(pageCurlLabel)
- pageCurlSwitch.translatesAutoresizingMaskIntoConstraints = false
- pageCurlSwitch.addTarget(self, action: #selector(saveSettings), for: .valueChanged)
- view.addSubview(pageCurlSwitch)
-
- NSLayoutConstraint.activate([
- darkModeLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
- darkModeLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
- darkModeSwitch.centerYAnchor.constraint(equalTo: darkModeLabel.centerYAnchor),
- darkModeSwitch.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
-
- bgLabel.topAnchor.constraint(equalTo: darkModeLabel.bottomAnchor, constant: 20),
- bgLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
- backgroundColorPicker.topAnchor.constraint(equalTo: bgLabel.bottomAnchor, constant: 10),
- backgroundColorPicker.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- backgroundColorPicker.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- backgroundColorPicker.heightAnchor.constraint(equalToConstant: 100),
-
- fontLabel.topAnchor.constraint(equalTo: backgroundColorPicker.bottomAnchor, constant: 20),
- fontLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
- fontFamilyPicker.topAnchor.constraint(equalTo: fontLabel.bottomAnchor, constant: 10),
- fontFamilyPicker.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- fontFamilyPicker.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- fontFamilyPicker.heightAnchor.constraint(equalToConstant: 100),
-
- sizeLabel.topAnchor.constraint(equalTo: fontFamilyPicker.bottomAnchor, constant: 20),
- sizeLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
- fontSizeSlider.centerYAnchor.constraint(equalTo: sizeLabel.centerYAnchor),
- fontSizeSlider.leadingAnchor.constraint(equalTo: sizeLabel.trailingAnchor, constant: 20),
- fontSizeSlider.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
-
- highlightLabel.topAnchor.constraint(equalTo: sizeLabel.bottomAnchor, constant: 20),
- highlightLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
- highlightColorPicker.topAnchor.constraint(equalTo: highlightLabel.bottomAnchor, constant: 10),
- highlightColorPicker.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- highlightColorPicker.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- highlightColorPicker.heightAnchor.constraint(equalToConstant: 100),
-
- pageCurlLabel.topAnchor.constraint(equalTo: highlightColorPicker.bottomAnchor, constant: 20),
- pageCurlLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
- pageCurlSwitch.centerYAnchor.constraint(equalTo: pageCurlLabel.centerYAnchor),
- pageCurlSwitch.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
- ])
- }
-
- private func loadCurrentSettings() {
- darkModeSwitch.isOn = UserDefaults.standard.bool(forKey: "isDarkMode")
- if let bgColor = UserDefaults.standard.string(forKey: "backgroundColor"),
- let index = colors.firstIndex(of: bgColor) {
- backgroundColorPicker.selectRow(index, inComponent: 0, animated: false)
- }
- if let font = UserDefaults.standard.string(forKey: "fontFamily"),
- let index = fonts.firstIndex(of: font) {
- fontFamilyPicker.selectRow(index, inComponent: 0, animated: false)
- }
- fontSizeSlider.value = Float(UserDefaults.standard.integer(forKey: "fontSize") > 0 ? UserDefaults.standard.integer(forKey: "fontSize") : 16)
- if let highlightColor = UserDefaults.standard.string(forKey: "highlightColor"),
- let index = highlightColors.firstIndex(of: highlightColor) {
- highlightColorPicker.selectRow(index, inComponent: 0, animated: false)
- }
- pageCurlSwitch.isOn = UserDefaults.standard.bool(forKey: "isPageCurlEnabled")
- }
-
- @objc private func saveSettings() {
- UserDefaults.standard.set(darkModeSwitch.isOn, forKey: "isDarkMode")
- let bgIndex = backgroundColorPicker.selectedRow(inComponent: 0)
- UserDefaults.standard.set(colors[bgIndex], forKey: "backgroundColor")
- let fontIndex = fontFamilyPicker.selectedRow(inComponent: 0)
- UserDefaults.standard.set(fonts[fontIndex], forKey: "fontFamily")
- UserDefaults.standard.set(Int(fontSizeSlider.value), forKey: "fontSize")
- let highlightIndex = highlightColorPicker.selectedRow(inComponent: 0)
- UserDefaults.standard.set(highlightColors[highlightIndex], forKey: "highlightColor")
- UserDefaults.standard.set(pageCurlSwitch.isOn, forKey: "isPageCurlEnabled")
- }
-
- func numberOfComponents(in pickerView: UIPickerView) -> Int {
- return 1
- }
-
- func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
- if pickerView == backgroundColorPicker { return colors.count }
- if pickerView == fontFamilyPicker { return fonts.count }
- if pickerView == highlightColorPicker { return highlightColors.count }
- return 0
- }
-
- func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
- if pickerView == backgroundColorPicker { return colorNames[row] }
- if pickerView == fontFamilyPicker { return fonts[row] }
- if pickerView == highlightColorPicker { return highlightColors[row] }
- return nil
- }
-
- func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
- saveSettings()
- }
-}
diff --git a/testReader/ViewController.swift b/testReader/ViewController.swift
deleted file mode 100644
index 4e896fe..0000000
--- a/testReader/ViewController.swift
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// ViewController.swift
-// testReader
-//
-// Created by shrutesh sharma on 11/03/25.
-//
-
-import UIKit
-
-class ViewController: UIViewController {
-
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do any additional setup after loading the view.
- }
-
-
-}
-