Skip to content

Commit 33ac7df

Browse files
feat: implement getOwned plugins
1 parent 232b9da commit 33ac7df

File tree

4 files changed

+196
-344
lines changed

4 files changed

+196
-344
lines changed

src/lib/installPlugin.js

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,23 @@ export default async function installPlugin(
8282
},
8383
);
8484
} else {
85-
// cordova http plugin for others
86-
plugin = await new Promise((resolve, reject) => {
87-
cordova.plugin.http.sendRequest(
85+
const tempPath = cordova.file.cacheDirectory + "plugin_download.zip";
86+
87+
await new Promise((resolve, reject) => {
88+
cordova.exec(resolve, reject, "Authenticator", "downloadPlugin", [
8889
pluginUrl,
89-
{
90-
method: "GET",
91-
responseType: "arraybuffer",
92-
},
93-
(response) => {
94-
resolve(response.data);
95-
loaderDialog.setMessage(`${strings.loading} 100%`);
96-
},
97-
(error) => {
98-
reject(error);
99-
},
100-
);
90+
tempPath,
91+
]);
10192
});
93+
94+
plugin = await fsOperation(tempPath).readFile(
95+
undefined,
96+
(loaded, total) => {
97+
loaderDialog.setMessage(
98+
`${strings.loading} ${((loaded / total) * 100).toFixed(2)}%`,
99+
);
100+
},
101+
);
102102
}
103103

104104
if (plugin) {

src/pages/plugins/plugins.js

Lines changed: 121 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -416,95 +416,82 @@ export default function PluginsInclude(updates) {
416416
}
417417
}
418418

419-
async function retrieveFilteredPlugins(filterState) {
419+
//fetch plugins with the auth token
420+
function fetchPlugins(url) {
421+
return new Promise((resolve, reject) => {
422+
cordova.exec(
423+
(items) => resolve(items),
424+
(err) => reject(new Error(err)),
425+
"Authenticator",
426+
"fetchPlugins",
427+
[url]
428+
);
429+
});
430+
}
431+
432+
async function retrieveFilteredPlugins(filterState) {
420433
if (!filterState) return { items: [], hasMore: false };
421434

422435
if (filterState.type === "orderBy") {
423-
const page = filterState.nextPage || 1;
424-
try {
425-
let response;
426-
if (filterState.value === "top_rated") {
427-
response = await fetch(
428-
withSupportedEditor(
429-
`${constants.API_BASE}/plugins?explore=random&page=${page}&limit=${LIMIT}`,
430-
),
431-
);
432-
} else {
433-
response = await fetch(
434-
withSupportedEditor(
435-
`${constants.API_BASE}/plugin?orderBy=${filterState.value}&page=${page}&limit=${LIMIT}`,
436-
),
437-
);
438-
}
439-
const items = await response.json();
440-
if (!Array.isArray(items)) {
441-
return { items: [], hasMore: false };
436+
const page = filterState.nextPage || 1;
437+
try {
438+
let url;
439+
if (filterState.value === "top_rated") {
440+
url = withSupportedEditor(`${constants.API_BASE}/plugins?explore=random&page=${page}&limit=${LIMIT}`);
441+
} else {
442+
url = withSupportedEditor(`${constants.API_BASE}/plugin?orderBy=${filterState.value}&page=${page}&limit=${LIMIT}`);
443+
}
444+
445+
const items = await fetchPlugins(url);
446+
filterState.nextPage = page + 1;
447+
return { items, hasMore: items.length === LIMIT };
448+
} catch (error) {
449+
console.error("Failed to fetch ordered plugins:", error);
450+
return { items: [], hasMore: false };
442451
}
443-
filterState.nextPage = page + 1;
444-
const hasMoreResults = items.length === LIMIT;
445-
return { items, hasMore: hasMoreResults };
446-
} catch (error) {
447-
console.error("Failed to fetch ordered plugins:", error);
448-
return { items: [], hasMore: false };
449-
}
450452
}
451453

452-
if (!Array.isArray(filterState.buffer)) {
453-
filterState.buffer = [];
454-
}
455-
if (filterState.hasMoreSource === undefined) {
456-
filterState.hasMoreSource = true;
457-
}
458-
if (!filterState.nextPage) {
459-
filterState.nextPage = 1;
460-
}
454+
if (!Array.isArray(filterState.buffer)) filterState.buffer = [];
455+
if (filterState.hasMoreSource === undefined) filterState.hasMoreSource = true;
456+
if (!filterState.nextPage) filterState.nextPage = 1;
461457

462458
const items = [];
463459

464460
while (items.length < LIMIT) {
465-
if (filterState.buffer.length) {
466-
items.push(filterState.buffer.shift());
467-
continue;
468-
}
461+
if (filterState.buffer.length) {
462+
items.push(filterState.buffer.shift());
463+
continue;
464+
}
469465

470-
if (filterState.hasMoreSource === false) break;
466+
if (filterState.hasMoreSource === false) break;
471467

472-
try {
473-
const page = filterState.nextPage;
474-
const response = await fetch(
475-
withSupportedEditor(`${constants.API_BASE}/plugins?page=${page}&limit=${LIMIT}`),
476-
);
477-
const data = await response.json();
478-
filterState.nextPage = page + 1;
468+
try {
469+
const url = withSupportedEditor(`${constants.API_BASE}/plugins?page=${filterState.nextPage}&limit=${LIMIT}`);
470+
const data = await fetchPlugins(url); // <-- java call
471+
filterState.nextPage++;
479472

480-
if (!Array.isArray(data) || !data.length) {
481-
filterState.hasMoreSource = false;
482-
break;
483-
}
473+
if (!Array.isArray(data) || !data.length) {
474+
filterState.hasMoreSource = false;
475+
break;
476+
}
484477

485-
if (data.length < LIMIT) {
486-
filterState.hasMoreSource = false;
487-
}
478+
if (data.length < LIMIT) filterState.hasMoreSource = false;
488479

489-
const matched = data.filter((plugin) => matchesFilter(plugin, filterState));
490-
filterState.buffer.push(...matched);
491-
} catch (error) {
492-
console.error("Failed to fetch filtered plugins:", error);
493-
filterState.hasMoreSource = false;
494-
break;
495-
}
480+
filterState.buffer.push(...data.filter(plugin => matchesFilter(plugin, filterState)));
481+
} catch (error) {
482+
console.error("Failed to fetch filtered plugins:", error);
483+
filterState.hasMoreSource = false;
484+
break;
485+
}
496486
}
497487

498488
while (items.length < LIMIT && filterState.buffer.length) {
499-
items.push(filterState.buffer.shift());
489+
items.push(filterState.buffer.shift());
500490
}
501491

502-
const hasMoreResults =
503-
(filterState.hasMoreSource !== false && filterState.nextPage) ||
504-
filterState.buffer.length > 0;
505-
492+
const hasMoreResults = (filterState.hasMoreSource !== false && filterState.nextPage) || filterState.buffer.length > 0;
506493
return { items, hasMore: Boolean(hasMoreResults) };
507-
}
494+
}
508495

509496
function matchesFilter(plugin, filterState) {
510497
if (!plugin) return false;
@@ -559,6 +546,7 @@ export default function PluginsInclude(updates) {
559546
return [];
560547
}
561548

549+
//auth token is not needed here as this endpoint only returns public plugins and the server handles the filtering based on supported editor
562550
async function getAllPlugins() {
563551
if (currentFilter) return;
564552
if (isLoading || !hasMore) return;
@@ -632,26 +620,76 @@ export default function PluginsInclude(updates) {
632620
$list.installed.setAttribute("empty-msg", strings["no plugins found"]);
633621
}
634622

635-
async function getOwned() {
636-
$list.owned.setAttribute("empty-msg", strings["loading..."]);
637-
const purchases = await helpers.promisify(iap.getPurchases);
638-
const disabledMap = settings.value.pluginsDisabled || {};
623+
async function getOwned() {
624+
$list.owned.setAttribute("empty-msg", strings["loading..."]);
625+
626+
const purchases = await helpers.promisify(iap.getPurchases);
627+
const disabledMap = settings.value.pluginsDisabled || {};
628+
629+
// Prevent duplicates
630+
const addedIds = new Set();
639631

640-
purchases.forEach(async ({ productIds }) => {
632+
// Play Store / IAP purchases
633+
await Promise.all(
634+
purchases.map(async ({ productIds }) => {
641635
const [sku] = productIds;
642-
const url = Url.join(constants.API_BASE, "plugin/owned", sku);
643-
const plugin = await fsOperation(url).readFile("json");
644-
const isInstalled = plugins.installed.find(({ id }) => id === plugin.id);
645-
plugin.installed = !!isInstalled;
646636

647-
if (plugin.installed) {
648-
plugin.enabled = disabledMap[plugin.id] !== true;
649-
plugin.onToggleEnabled = onToggleEnabled;
637+
try {
638+
const url = Url.join(constants.API_BASE, "plugin/owned", sku);
639+
const plugin = await fsOperation(url).readFile("json");
640+
641+
if (!plugin || addedIds.has(plugin.id)) return;
642+
643+
const isInstalled = plugins.installed.find(
644+
({ id }) => id === plugin.id
645+
);
646+
647+
plugin.installed = !!isInstalled;
648+
649+
if (plugin.installed) {
650+
plugin.enabled = disabledMap[plugin.id] !== true;
651+
plugin.onToggleEnabled = onToggleEnabled;
652+
}
653+
654+
addedIds.add(plugin.id);
655+
plugins.owned.push(plugin);
656+
$list.owned.append(<Item {...plugin} updates={updates} />);
657+
} catch (err) {
658+
console.error("Failed to load owned IAP plugin:", err);
650659
}
660+
})
661+
);
662+
663+
// Razorpay / external purchases
664+
try {
665+
const url = withSupportedEditor(
666+
`${constants.API_BASE}/plugins?owned=true`
667+
);
668+
669+
const ownedPlugins = await fetchPlugins(url);
670+
671+
ownedPlugins.forEach((plugin) => {
672+
if (!plugin || addedIds.has(plugin.id)) return;
673+
674+
const isInstalled = plugins.installed.find(
675+
({ id }) => id === plugin.id
676+
);
677+
678+
plugin.installed = !!isInstalled;
679+
680+
if (plugin.installed) {
681+
plugin.enabled = disabledMap[plugin.id] !== true;
682+
plugin.onToggleEnabled = onToggleEnabled;
683+
}
684+
685+
addedIds.add(plugin.id);
686+
plugins.owned.push(plugin);
687+
$list.owned.append(<Item {...plugin} updates={updates} />);
688+
});
689+
} catch (err) {
690+
console.error("Failed to fetch owned plugins:", err);
691+
}
651692

652-
plugins.owned.push(plugin);
653-
$list.owned.append(<Item {...plugin} updates={updates} />);
654-
});
655693
$list.owned.setAttribute("empty-msg", strings["no plugins found"]);
656694
}
657695

src/plugins/auth/src/android/Authenticator.java

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,32 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
4242
prefManager.setString(KEY_TOKEN, token);
4343
callbackContext.success();
4444
return true;
45-
case "getAllPlugins":
45+
case "downloadPlugin":
4646
cordova.getThreadPool().execute(() -> {
47-
try {
48-
PluginRetriever.getAllPlugins(args.getInt(0), callbackContext);
49-
} catch (Exception e) {
50-
Log.e(TAG, "getAllPlugins error: " + e.getMessage(), e);
51-
callbackContext.error("Error: " + e.getMessage());
52-
}
53-
});
47+
try {
48+
PluginRetriever.downloadPlugin(
49+
prefManager.getString(KEY_TOKEN, null),
50+
args.getString(0),
51+
args.getString(1),
52+
callbackContext
53+
);
54+
} catch (Exception e) {
55+
Log.e(TAG, "downloadPlugin error: " + e.getMessage(), e);
56+
callbackContext.error("Error: " + e.getMessage());
57+
}
58+
});
5459
return true;
55-
case "retrieveFilteredPlugins":
56-
try {
57-
JSONObject filterState = args.length() > 0 ? args.getJSONObject(0) : null;
58-
final JSONObject finalFilterState = filterState;
59-
cordova.getThreadPool().execute(() -> {
60-
try {
61-
PluginRetriever.retrieveFilteredPlugins(prefManager.getString(KEY_TOKEN, null), finalFilterState, callbackContext);
62-
} catch (Exception e) {
63-
Log.e(TAG, "retrieveFilteredPlugins error: " + e.getMessage(), e);
64-
callbackContext.error("Error: " + e.getMessage());
65-
}
66-
});
67-
} catch (JSONException e) {
68-
callbackContext.error("Invalid filter JSON: " + e.getMessage());
69-
}
60+
case "fetchPlugins":
61+
cordova.getThreadPool().execute(() -> {
62+
try {
63+
String url = args.getString(0);
64+
JSONArray items = PluginRetriever.fetchJsonArray(url, prefManager.getString(KEY_TOKEN, null));
65+
callbackContext.success(items != null ? items : new JSONArray());
66+
} catch (Exception e) {
67+
Log.e(TAG, "fetchPlugins error: " + e.getMessage(), e);
68+
callbackContext.error("Error: " + e.getMessage());
69+
}
70+
});
7071
return true;
7172
default:
7273
Log.w(TAG, "Attempted to call unknown action: " + action);

0 commit comments

Comments
 (0)