aboutsummaryrefslogtreecommitdiffstats
path: root/android/app/src/main/res/values
diff options
context:
space:
mode:
authorAdam Soltys <adam@coinos.io>2026-10-17 05:04:35 -0700
committerAdam Soltys <adam@coinos.io>2026-10-17 05:04:35 -0700
commite529ab104a19ceb71f1981016fb3a857a79d3caa (patch)
tree75ca0f7646fe7894a0bb547c58d7669001c65f58 /android/app/src/main/res/values
parent1b5c254ec50176f20dceef6f015d1a2731a4904e (diff)
downloadcoinosv3-e529ab104a19ceb71f1981016fb3a857a79d3caa.tar.gz
coinosv3-e529ab104a19ceb71f1981016fb3a857a79d3caa.zip
The video pager's counter counts every post it has found, not just the clips already warmed up: a refresh no longer shows "1 / 2" over a grid of a dozen.
The posts were all there (the grid showed them); the carousel holds a post back until its clip is ready to play — its first frame on the slide and its opening cached — and only the next couple are warmed at a time, so after a refresh the total started at 1 or 2 and crept up as clips warmed (Adam, 2026-10-17: "On refresh the total video count seems to reset to 1 and slowly more load despite showing posters for several more being available"). Now the total, and the place in it, count the waiting posts too; only posts kept out for their shape are left out. A swipe still passes over a post not yet ready. tools/pager-ready-gate-test.js: the counter reads 3 / 4 both before and after the waiting post joins. pager-swipe-fly, profile-pager, thread-pager and pager-seek-hide pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
Diffstat (limited to 'android/app/src/main/res/values')
0 files changed, 0 insertions, 0 deletions
'n79' href='#n79'>79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
import cookie from 'cookie';
import { browser } from '$app/environment';
import { toast } from '@zerodevx/svelte-toast';

export function scroll(section) {
	section.scrollIntoView({ behavior: 'smooth' });
}

const base = browser ? '' : import.meta.env.VITE_COINOS_URL;

export const get = (url, headers = {}) =>
	fetch(base + url, { headers })
		.then((r) => r.text())
		.then((body) => {
			try {
				return JSON.parse(body);
			} catch (e) {
				throw new Error(body);
			}
		});

export const post = (url, body, headers) => {
	headers = { ...headers, 'content-type': 'application/json', accept: 'application/json' };
	return fetch(base + url, { method: 'POST', body: JSON.stringify(body), headers })
		.then((r) => r.text())
		.then((body) => {
			try {
				body = JSON.parse(body);
			} catch (e) {
				throw new Error(body);
			}

			if (body instanceof Error) throw body;
			if (body.name === 'Error') throw new Error(body.message);

			return body;
		});
};

export const put = (url, body, headers) => {
	headers = { ...headers, 'content-type': 'application/json' };
	return fetch(base + url, {
		method: 'PUT',
		body: JSON.stringify(body),
		headers
	}).then(async (r) => {
		if (!r.ok) throw new Error('put failed');
	});
};

export const copy = (text) => {
	navigator.clipboard.writeText(text);
	success('Copied!');
};

export function reverseFormat(val, locale) {
	let parts = new Intl.NumberFormat(locale).formatToParts(1111.1);
	let group = parts.find((part) => part.type === 'group').value;
	let decimal = parts.find((part) => part.type === 'decimal').value;
	let reversedVal = val.replace(new RegExp('\\' + group, 'g'), '');
	reversedVal = reversedVal.replace(new RegExp('\\' + decimal, 'g'), '.');
	return Number.isNaN(reversedVal) ? 0 : +reversedVal;
}

export let protectedRoutes = [
	/receive/,
	/customers/,
	/dashboard/,
	/settings/,
	/transactions/,
	/support/
];

export const success = (m) => {
	toast.pop();
	toast.push(m, {
		theme: {
			'--toastBarBackground': '#F5F7FA'
		}
	});
};

export const warning = (m) => {
	toast.pop();
	toast.push(m, {
		theme: {
			'--toastBarBackground': '#FFCE22'
		}
	});
};
export const failure = (m) => {
	toast.pop();
	toast.push(m, {
		theme: {
			'--toastBarBackground': '#E93535'
		}
	});
};
export const info = (m) => {
	toast.pop();
	toast.push(m, {
		theme: {
			'--toastBarBackground': '#1C69FF'
		}
	});
};

export const login = async (user, setHeaders) => {
	let maxAge = 30 * 24 * 60 * 60;
	let { token } = await post('/login', user);

	let expires = new Date();
	expires.setSeconds(expires.getSeconds() + maxAge);

	setHeaders({
		'set-cookie': cookie.serialize('token', token, {
			httpOnly: true,
			maxAge,
			sameSite: 'lax',
			path: '/',
			expires
		})
	});
};

export const auth = (req) => {
	let { token } = cookie.parse(req.headers.get('cookie') || '');
	return { authorization: `Bearer ${token}` };
};

export const f = (s, currency) =>
	new Intl.NumberFormat('en-US', {
		style: 'currency',
		currency
	})
		.format(s)
		.replace('CA', '');

export const s = (s) => new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(s);