Merge pull request #2244 from omnivore-app/feat/ios-deep-links

Support read, search, and saved-search deep link formats
This commit is contained in:
Jackson Harper 2023-05-25 11:09:13 +08:00 committed by GitHub
commit 93f1fd8c83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 154 additions and 18 deletions

View file

@ -179,11 +179,20 @@ struct AnimatingCellHeight: AnimatableModifier {
}
}
.onOpenURL { url in
withoutAnimation {
viewModel.linkRequest = nil
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
if let linkRequestID = DeepLink.make(from: url)?.linkRequestID {
viewModel.linkRequest = LinkRequest(id: UUID(), serverID: linkRequestID)
viewModel.linkRequest = nil
if let deepLink = DeepLink.make(from: url) {
switch deepLink {
case let .search(query):
viewModel.searchTerm = query
case let .savedSearch(named):
if let filter = LinkedItemFilter(rawValue: named) {
viewModel.appliedFilter = filter.rawValue
}
case let .webAppLinkRequest(requestID):
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
withoutAnimation {
viewModel.linkRequest = LinkRequest(id: UUID(), serverID: requestID)
}
}
}
}

View file

@ -66,6 +66,13 @@ public extension LinkedItem {
var unwrappedSavedAt: Date { savedAt ?? Date() }
var unwrappedCreatedAt: Date { createdAt ?? Date() }
var deepLink: URL? {
if let id = id {
return URL(string: "omnivore://read/\(id)")
}
return nil
}
var hasLabels: Bool {
(labels?.count ?? 0) > 0
}

View file

@ -11,6 +11,8 @@ public struct LinkRequest: Identifiable, Hashable {
}
public enum DeepLink {
case search(query: String)
case savedSearch(named: String)
case webAppLinkRequest(requestID: String)
}
@ -32,7 +34,13 @@ public extension DeepLink {
private static func deepLinkFromOmnivoreScheme(url: URL) -> DeepLink? {
switch url.host {
case "shareExtensionRequestID":
case "search":
let query = url.path.replacingOccurrences(of: "/", with: "")
return .search(query: query)
case "saved-search":
let named = url.path.replacingOccurrences(of: "/", with: "")
return .savedSearch(named: named)
case "read", "shareExtensionRequestID":
let requestID = url.path.replacingOccurrences(of: "/", with: "")
return .webAppLinkRequest(requestID: requestID)
default:

View file

@ -2,6 +2,17 @@ import Models
import SwiftUI
import Utils
public extension View {
func draggableItem(item: LinkedItem) -> some View {
if #available(iOS 16.0, *), let url = item.deepLink {
return AnyView(self.draggable(url) {
Label(item.unwrappedTitle, systemImage: "link")
})
}
return AnyView(self)
}
}
public struct LibraryItemCard: View {
let viewer: Viewer?
let tapHandler: () -> Void
@ -27,6 +38,7 @@ public struct LibraryItemCard: View {
}
}
.padding(.bottom, 8)
.draggableItem(item: item)
}
var isFullyRead: Bool {

View file

@ -2,8 +2,8 @@
"manifest_version": 2,
"name": "Omnivore",
"short_name": "Omnivore",
"version": "0.1.24",
"description": "Save articles to your Omnivore library",
"version": "2.0.2",
"description": "Save PDFs and Articles to your Omnivore library",
"author": "Omnivore Media, Inc",
"default_locale": "en",
"developer": {
@ -44,6 +44,10 @@
"id": "save-extension@omnivore.app"
}
},
"options_ui": {
"page": "/views/options.html",
"open_in_tab": true
},
"content_scripts": [
{
"matches": [
@ -51,10 +55,10 @@
"http://*/**"
],
"js": [
"/scripts/constants.js",
"/scripts/common.js",
"/scripts/content/toast.js",
"/scripts/content/page-info.js",
"/scripts/content/prepare-content.js",
"/scripts/content/toast.js",
"/scripts/content/content-listener-script.js"
]
},
@ -89,6 +93,6 @@
}
},
"web_accessible_resources": [
"views/cta-popup.html"
"views/toast.html"
]
}

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
"use strict";!function(){const e=window.matchMedia("(prefers-color-scheme: dark)");e&&(e.onchange=function(e){browserApi.runtime.sendMessage({action:ACTIONS.RefreshDarkMode,payload:{value:e.matches}})}),browserApi.runtime.onMessage.addListener((({action:e,payload:n},o,t)=>{if(e===ACTIONS.GetContent)return prepareContent().then((e=>{t({type:e.type,doc:e.content||"",uploadContentObjUrl:e.uploadContentObjUrl,pageInfo:getPageInfo()})})),!0;if(e===ACTIONS.Ping)t({pong:!0});else if(e===ACTIONS.ShowMessage)showMessage(n);else if(e===ACTIONS.GetPageInfo){const e=getPageInfo();t(e)}else e===ACTIONS.AddIframeContent||console.warn("Unknown message has been taken")}))}();
"use strict";!function(){const e=window.matchMedia("(prefers-color-scheme: dark)");e&&(e.onchange=function(e){browserApi.runtime.sendMessage({action:ACTIONS.RefreshDarkMode,payload:{value:e.matches}})}),browserApi.runtime.onMessage.addListener((({action:e,payload:n},o,a)=>{if(e===ACTIONS.GetContent)return prepareContent().then((e=>{a({type:e.type,doc:e.content||"",uploadContentObjUrl:e.uploadContentObjUrl,pageInfo:getPageInfo()})})),!0;console.log("handling ",e,n),e===ACTIONS.Ping?a({pong:!0}):e===ACTIONS.ShowToolbar?showToolbar(n):e===ACTIONS.UpdateStatus?updateStatus(n):e===ACTIONS.LabelCacheUpdated?updateLabelsFromCache(n):e===ACTIONS.AddIframeContent||console.warn("Unknown message has been taken")}))}();

View file

@ -1 +1 @@
"use strict";window.getPageInfo=function(){return{title:function(){const n=document.querySelector(SELECTORS.TITLE);return n&&n.content||document.title||""}(),canonicalUrl:function(){const n=window.location.href,t=document.querySelector(SELECTORS.CANONICAL_URL),e=t&&t.href;return e?new URL(e,n).href:n}(),contentType:document.contentType}};
"use strict";window.getPageInfo=function(){return{title:function(){const n=document.querySelector(SELECTORS.TITLE),t=n&&n.content;return document.title||t||""}(),canonicalUrl:function(){const n=window.location.href,t=document.querySelector(SELECTORS.CANONICAL_URL),e=t&&t.href;return e?new URL(e,n).href:n}(),contentType:document.contentType}};

View file

@ -1 +1 @@
"use strict";!function(){const e={};function t(t){const n=t.tagName.toLowerCase();if("iframe"===n){const n=e[t.src];if(!n)return;const o=document.createElement("div");o.className="omnivore-instagram-embed",o.innerHTML=n;const r=t.parentNode;if(!r)return;return void r.replaceChild(o,t)}if("img"===n||"image"===n){if(-1===window.getComputedStyle(t).getPropertyValue("filter").indexOf("blur("))return;return void t.remove()}const o=window.getComputedStyle(t),r=o.getPropertyValue("background-image");if(r&&"none"!==r)return;const i=o.getPropertyValue("filter");if(i&&-1!==i.indexOf("blur("))return void t.remove();if(t.src)return;if(t.innerHTML.length>24)return;const a=/url\("(.+?)"\)/gi,c=a.exec(r);a.lastIndex=0;const l=c&&c[1];if(!l)return;const s=document.createElement("img");s.src=l;const p=t.parentNode;p&&p.replaceChild(s,t)}function n(){const e=document.createElement("div");e.style.position="absolute",e.style.left="-2000px",e.style.zIndex="-2000",e.innerHTML=document.body.innerHTML,document.documentElement.appendChild(e),Array.from(e.getElementsByTagName("*")).forEach(t);const n=`<html><head>${document.head.innerHTML}</head><body>${e.innerHTML}</body></html>`;return e.remove(),n}function o(){const e=document.querySelectorAll(".webext-omnivore-backdrop");for(let t=0;t<e.length;t++)e[t].style.setProperty("opacity","0","important");setTimeout((()=>{for(let t=0;t<e.length;t++)e[t].remove()}),500)}browserApi.runtime.onMessage.addListener((({action:t,payload:n},o,r)=>{if(t!==ACTIONS.AddIframeContent)return;const{url:i,content:a}=n;e[i]=a,r({})})),window.prepareContent=async function(){return await async function(){const e=".pdf"===window.location.pathname.slice(-4).toLowerCase(),t=-1!==["application/acrobat","application/pdf","application/x-pdf","applications/vnd.pdf","text/pdf","text/x-pdf"].indexOf(document.contentType);if(!e&&!t)return Promise.resolve(null);const n=document.querySelector("embed");return n&&"application/pdf"!==n.type?Promise.resolve(null):ENV_DOES_NOT_SUPPORT_BLOB_URL_ACCESS&&n.src?Promise.resolve({type:"url",uploadContentObjUrl:n.src}):new Promise(((e,t)=>{const n=new XMLHttpRequest;n.open("GET","",!0),n.responseType="blob",n.onload=function(n){200===this.status?e({type:"pdf",uploadContentObjUrl:URL.createObjectURL(this.response)}):t(n)},n.send()}))}()||(await async function(){const e=document.scrollingElement||document.body,t=e.scrollTop,n=e.scrollHeight;o();const r=function(){const e=document.createElement("div");return e.className="webext-omnivore-backdrop",e.style.cssText="all: initial !important;\n position: fixed !important;\n top: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n left: 0 !important;\n z-index: 99999 !important;\n background: #fff !important;\n opacity: 0.8 !important;\n transition: opacity 0.3s !important;\n -webkit-backdrop-filter: blur(4px) !important;\n backdrop-filter: blur(4px) !important;\n ",e}();for(document.body.appendChild(r);e.scrollTop<=n-500;){const t=e.scrollTop;if(e.scrollTop+=500,await new Promise((e=>{setTimeout(e,10)})),e.scrollTop===t)break}e.scrollTop=t,await new Promise((e=>{setTimeout(e,10)}))}(),o(),{type:"html",content:n()})}}();
"use strict";!function(){const e={};function t(t){const n=t.tagName.toLowerCase();if("iframe"===n){const n=e[t.src];if(!n)return;const o=document.createElement("div");o.className="omnivore-instagram-embed",o.innerHTML=n;const r=t.parentNode;if(!r)return;return void r.replaceChild(o,t)}if("img"===n||"image"===n){if(-1===window.getComputedStyle(t).getPropertyValue("filter").indexOf("blur("))return;return void t.remove()}const o=window.getComputedStyle(t),r=o.getPropertyValue("background-image");if(r&&"none"!==r)return;const i=o.getPropertyValue("filter");if(i&&-1!==i.indexOf("blur("))return void t.remove();if(t.src)return;if(t.innerHTML.length>24)return;const c=/url\("(.+?)"\)/gi,a=c.exec(r);c.lastIndex=0;const l=a&&a[1];if(!l)return;const s=document.createElement("img");s.src=l;const d=t.parentNode;d&&d.replaceChild(s,t)}function n(){const e=document.createElement("div");e.style.position="absolute",e.style.left="-2000px",e.style.zIndex="-2000",e.innerHTML=document.body.innerHTML,document.documentElement.appendChild(e),Array.from(e.getElementsByTagName("*")).forEach(t);try{if("undefined"!=typeof create_time&&create_time){const t=new Date(1e3*create_time),n=document.createElement("div");n.className="omnivore-published-date",n.innerHTML=t.toLocaleString(),e.appendChild(n)}}catch(e){console.log("Error while trying to add published date to WeChat post",e)}const n=`<html><head>${document.head.innerHTML}</head><body>${e.innerHTML}</body></html>`;return e.remove(),n}function o(){const e=document.querySelectorAll(".webext-omnivore-backdrop");for(let t=0;t<e.length;t++)e[t].style.setProperty("opacity","0","important");setTimeout((()=>{for(let t=0;t<e.length;t++)e[t].remove()}),500)}browserApi.runtime.onMessage.addListener((({action:t,payload:n},o,r)=>{if(t!==ACTIONS.AddIframeContent)return;const{url:i,content:c}=n;e[i]=c,r({})})),window.prepareContent=async function(){const e=await async function(){const e=".pdf"===window.location.pathname.slice(-4).toLowerCase(),t=-1!==["application/acrobat","application/pdf","application/x-pdf","applications/vnd.pdf","text/pdf","text/x-pdf"].indexOf(document.contentType);if(!e&&!t)return Promise.resolve(null);const n=document.querySelector("embed");return n&&"application/pdf"!==n.type?Promise.resolve(null):ENV_DOES_NOT_SUPPORT_BLOB_URL_ACCESS&&n.src?Promise.resolve({type:"url",uploadContentObjUrl:n.src}):new Promise(((e,t)=>{const n=new XMLHttpRequest;n.open("GET","",!0),n.responseType="blob",n.onload=function(n){200===this.status?e({type:"pdf",uploadContentObjUrl:URL.createObjectURL(this.response)}):t(n)},n.send()}))}();if(e)return e;const t=window.location.href;try{if(handleBackendUrl(t))return{type:"url"}}catch{console.log("error checking url")}return await async function(e){const t=document.scrollingElement||document.body,n=t.scrollTop,r=t.scrollHeight;o();const i=function(){const e=document.createElement("div");return e.className="webext-omnivore-backdrop",e.style.cssText="all: initial !important;\n position: fixed !important;\n top: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n left: 0 !important;\n z-index: 99999 !important;\n background: #fff !important;\n opacity: 0.8 !important;\n transition: opacity 0.3s !important;\n -webkit-backdrop-filter: blur(4px) !important;\n backdrop-filter: blur(4px) !important;\n ",e}();for(document.body.appendChild(i);t.scrollTop<=r-500&&window.location.href===e;){const e=t.scrollTop;if(t.scrollTop+=500,await new Promise((e=>{setTimeout(e,10)})),t.scrollTop===e)break}t.scrollTop=n,await new Promise((e=>{setTimeout(e,10)}))}(t),o(),{type:"html",content:n()}}}();

File diff suppressed because one or more lines are too long

View file

@ -6,7 +6,8 @@
<title>Omnivore background</title>
<script src="/scripts/constants.js"></script>
<script src="/scripts/api.js"></script>
<script src="/scripts/common.js"></script>
<script src="/scripts/background.js"></script>
</head>

View file

@ -7,7 +7,102 @@
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="/styles/cta-popup.css">
<style>
@font-face {
font-style: normal;
font-weight: 400;
font-family: Inter;
src:
local(""),
url("/fonts/inter-v3-latin-400.woff2") format("woff2");
}
@font-face {
font-style: normal;
font-weight: 600;
font-family: Inter;
src:
local(""),
url("/fonts/inter-v3-latin-600.woff2") format("woff2");
}
@font-face {
font-style: normal;
font-weight: 700;
font-family: Inter;
src:
local(""),
url("/fonts/inter-v3-latin-700.woff2") format("woff2");
}
html,
body {
width: 100%;
height: 100%;
}
body {
margin: 0;
}
.cta-container {
position: relative;
overflow: hidden;
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 24px 12px;
background: linear-gradient(150deg, #fff 55%, #ffde8c 55%);
background-color: #fff;
color: #3d3d3d;
font-family: Inter, sans-serif;
text-align: center;
}
.cta-container__wrapper {
position: relative;
z-index: 1;
}
.cta-container__title {
padding: 0 24px 24px;
font-weight: 600;
font-size: 16px;
}
.cta-container__icon {
vertical-align: unset;
margin-bottom: -4px;
fill: none;
}
.cta-container__link {
display: flex;
align-items: center;
justify-content: center;
width: 184px;
height: 34px;
margin: 36px auto 14px;
border-radius: 40px;
background-color: #fff;
color: inherit;
font-weight: 700;
font-size: 12px;
text-decoration: none;
cursor: pointer;
}
.cta-container__text {
margin: 0;
font-size: 12px;
}
.cta-container__textlink {
color: inherit;
font-weight: 700;
}
</style>
</head>
<body>
<div class="cta-container">