diff --git a/web/src/components/form/FontAwesome.svelte b/web/src/components/form/FontAwesome.svelte
index 4074407..c18ff55 100644
--- a/web/src/components/form/FontAwesome.svelte
+++ b/web/src/components/form/FontAwesome.svelte
@@ -78,7 +78,8 @@
//Misc
ratingStar: solidIcons.faStar,
- saveListing: solidIcons.faBookmark
+ saveListing: solidIcons.faBookmark,
+ noTrackers: solidIcons.faShieldCheck,
};
export let iconName: string;
diff --git a/web/src/components/things/AndroidDetailedInfo.astro b/web/src/components/things/AndroidDetailedInfo.astro
new file mode 100644
index 0000000..7bef98e
--- /dev/null
+++ b/web/src/components/things/AndroidDetailedInfo.astro
@@ -0,0 +1,164 @@
+---
+
+import type { AndroidInfo } from '@utils/fetch-android-info';
+import { formatDate, timeAgo } from '@utils/dates-n-stuff';
+import FontAwesome from "@components/form/FontAwesome.svelte"
+
+
+interface Props {
+ androidData: AndroidInfo;
+};
+
+const { androidData } = Astro.props;
+
+function permissionToReadable(permission: string): string {
+ return (permission
+ .split('.')
+ .pop() || '')
+ .replace(/_/g, ' ')
+ .toLowerCase()
+ .split(' ')
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ')
+}
+
+
+---
+
+
+
+
Update Info
+
+ -
+ App
+
+
+ {androidData.app_name}
+
+
+ -
+ Creation Date
+ {formatDate(androidData.created)}
+
+ -
+ Last Updated
+ {formatDate(androidData.updated)}
+
+ -
+ Current Version
+ {androidData.version_name}
+
+ {androidData.creator && (
+ -
+ Creator
+ {androidData.creator}
+
+ )}
+ {androidData.downloads && (
+ -
+ Downloads
+ {androidData.downloads}
+
+ )}
+
+
+
Trackers
+ {androidData.trackers.length === 0 && (
+
+
+ No trackers found
+
+ )}
+
+ {androidData.trackers.map((track) => (
+ - {track.name}
+ ))}
+
+
+
+
+
Permissions
+ {androidData.permissions.length === 0 && (
+
+
+ No permissions required
+
+ )}
+
+ {androidData.permissions.map((perm) => (
+ - {permissionToReadable(perm)}
+ ))}
+
+
+
+
+
+
diff --git a/web/src/components/things/SaveListing.svelte b/web/src/components/things/SaveListing.svelte
index 9df2493..1f04e02 100644
--- a/web/src/components/things/SaveListing.svelte
+++ b/web/src/components/things/SaveListing.svelte
@@ -33,17 +33,32 @@
}
+
+{#if showLabel && isSaved }
+
+ You can view all saved items in your
Inventory
+
+{/if}
+
+
diff --git a/web/src/pages/[...listing].astro b/web/src/pages/[...listing].astro
index b44913e..c64f471 100644
--- a/web/src/pages/[...listing].astro
+++ b/web/src/pages/[...listing].astro
@@ -8,6 +8,7 @@ import PrivacyPolicyDetails from '@components/things/PrivacyPolicyDetails.astro'
import WebsiteDetailedInfo from '@components/things/WebsiteDetailedInfo.astro';
import DockerDetailedInfo from '@components/things/DockerDetailedInfo.astro';
import IosAppDetailedInfo from '@components/things/IosAppDetailedInfo.astro';
+import AndroidAppDetailedInfo from '@components/things/AndroidDetailedInfo.astro';
import DiscordDetailedInfo from '@components/things/DiscordDetailedInfo.astro';
import RedditDetailedInfo from '@components/things/RedditDetailedInfo.astro';
import SocialShare from '@components/form/Social.astro';
@@ -19,6 +20,7 @@ import { fetchTosdrPrivacy } from '@utils/fetch-privacy-policy';
import { fetchWebsiteInfo } from '@utils/fetch-website-info';
import { fetchDockerData } from '@utils/fetch-docker-instructions';
import { fetchIosInfo } from '@utils/fetch-ios-info';
+import { fetchAndroidInfo } from '@utils/fetch-android-info';
import { fetchDiscordInfo } from '@utils/fetch-discord-info';
import { fetchRedditInfo } from '@utils/fetch-reddit-info';
import { parseMarkdown, formatLink } from '@utils/parse-markdown';
@@ -42,6 +44,7 @@ const {
discordInvite,
subreddit,
iosApp,
+ androidApp,
icon,
followWith,
securityAudited,
@@ -138,13 +141,13 @@ const makePaginationLinks = () => {
const { previous, next } = makePaginationLinks();
-
const ignoredSites = ['github.gom', 'wikipedia.'];
// Fetch detailed data about the services GitHub repo, privacy policy and website
const githubData = github ? await fetchGitHubStats(github) : null;
const privacyData = tosdrId ? await fetchTosdrPrivacy(tosdrId) : null;
const iosData = iosApp ? await fetchIosInfo(iosApp) : null;
+const androidData = androidApp ? await fetchAndroidInfo(androidApp) : null;
const discordData = discordInvite ? await fetchDiscordInfo(discordInvite) : null;
const redditData = subreddit ? await fetchRedditInfo(subreddit) : null;
const dockerData = await fetchDockerData(name);
@@ -232,12 +235,12 @@ const getApiEndpoint = () => {
{formatLink(iosApp)}
)}
-
+ )}
{ discordInvite && (
Discord Invite:
@@ -306,6 +309,12 @@ const getApiEndpoint = () => {
)}
+ { androidData && (
+
+ )}
{ iosData && (
{name} iOS App
diff --git a/web/src/utils/fetch-android-info.ts b/web/src/utils/fetch-android-info.ts
new file mode 100644
index 0000000..ebf682f
--- /dev/null
+++ b/web/src/utils/fetch-android-info.ts
@@ -0,0 +1,46 @@
+
+const doubleCheckPackageName = (packageStr: string) => {
+ return packageStr.includes('id=') ? packageStr.split('id=')[1] : packageStr;
+}
+
+export const fetchAndroidInfo = async (androidPackage: string): Promise => {
+ const endpoint = `https://android-app-privacy.as93.net/${doubleCheckPackageName(androidPackage)}`;
+ try {
+ return await fetch(endpoint).then((res) => res.json());
+ } catch (error) {
+ console.error('Error fetching android data:', error);
+ return null;
+ }
+};
+
+interface Tracker {
+ id: number;
+ name: string;
+ description: string;
+ creation_date: string;
+ code_signature: string;
+ network_signature: string;
+ website: string;
+ categories: string[];
+ documentation: string[];
+}
+
+export interface AndroidInfo {
+ handle: string;
+ app_name: string;
+ uaid: string;
+ version_name: string;
+ version_code: string;
+ source: string;
+ icon_hash: string;
+ apk_hash: string;
+ created: string;
+ updated: string;
+ report: number;
+ creator: string;
+ downloads: string;
+ trackers: Tracker[];
+ permissions: string[];
+}
+
+