Skip to content

Commit e98e125

Browse files
fix: conflicts
2 parents 753f03e + ae03b2b commit e98e125

97 files changed

Lines changed: 16610 additions & 575 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/node_modules
1+
node_modules
22
/build.json
33
/www/build
44
/plugins
@@ -13,3 +13,4 @@ pnpm-lock.yaml
1313
.idea
1414
ace-builds
1515
fdroid.bool
16+
tsconfig.tsbuildinfo

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
"intoview",
174174
"Invisibles",
175175
"irid",
176+
"isfiles",
176177
"jbuilder",
177178
"JEXL",
178179
"jsbeautify",
@@ -249,6 +250,7 @@
249250
"onscrollleft",
250251
"onscrolltop",
251252
"onsearch",
253+
"onwillconnect",
252254
"onwilldisconnect",
253255
"onwriteend",
254256
"opencl",
@@ -370,6 +372,8 @@
370372
"watchmanconfig",
371373
"webp",
372374
"wercker",
375+
"willconnect",
376+
"willdisconnect",
373377
"Wollok",
374378
"wpgm",
375379
"wpml",

config.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version='1.0' encoding='utf-8'?>
2-
<widget id="com.foxdebug.acode" android-versionCode="970" version="1.12.0"
2+
<widget id="com.foxdebug.acode" android-versionCode="971" version="1.12.1"
33
xmlns="http://www.w3.org/ns/widgets"
44
xmlns:android="http://schemas.android.com/apk/res/android"
55
xmlns:cdv="http://cordova.apache.org/ns/1.0">
@@ -86,4 +86,4 @@
8686
<hook type="after_prepare" src="hooks/post-process.js" />
8787
</platform>
8888
<preference name="AndroidBlacklistSecureSocketProtocols" value="SSLv3,TLSv1" />
89-
</widget>
89+
</widget>

package-lock.json

Lines changed: 111 additions & 214 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@
3737
"cordova-plugin-browser": {},
3838
"cordova-plugin-sftp": {},
3939
"com.foxdebug.acode.rk.exec.terminal": {},
40-
"com.foxdebug.acode.rk.customtabs": {},
4140
"com.foxdebug.acode.rk.plugin.plugincontext": {},
4241
"cordova-plugin-system": {},
4342
"com.foxdebug.acode.rk.auth": {},
4443
"com.foxdebug.acode.rk.exec.proot": {},
45-
"cordova-plugin-iap": {}
44+
"cordova-plugin-iap": {},
45+
"com.foxdebug.acode.rk.customtabs": {}
4646
},
4747
"platforms": [
4848
"android"

src/components/sidebar/index.js

Lines changed: 109 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import "./style.scss";
2+
import fsOperation from "fileSystem";
23
import toast from "components/toast";
4+
import confirm from "dialogs/confirm";
5+
import loader from "dialogs/loader";
36
import Ref from "html-tag-js/ref";
47
import actionStack from "lib/actionStack";
58
import auth, { loginEvents } from "lib/auth";
69
import config from "lib/config";
10+
import helpers from "utils/helpers";
11+
import Url from "utils/Url";
712

813
/**
914
* @typedef {object} SideBar
@@ -98,56 +103,66 @@ function create($container, $toggler) {
98103
show();
99104
}
100105

101-
loginEvents.on(() => {
102-
updateSidebarAvatar();
103-
});
106+
loginEvents.addListener(updateSidebarAvatar);
104107

105108
async function handleUserIconClick(e) {
106109
try {
107-
const user = await auth.getLoggedInUser();
110+
loader.create(strings["login"], strings["loading..."]);
111+
let user = await auth.getLoggedInUser();
108112

109113
if (!user) {
110-
CustomTabs.open(
111-
`${config.BASE_URL}/login?redirect=app`,
112-
{ showTitle: true },
113-
() => {},
114-
() => {},
114+
const confirmation = await confirm(
115+
strings.confirm,
116+
strings["confirm-login"],
115117
);
116-
} else {
117-
const menu = userContextMenu.el;
118-
const isActive = menu.classList.toggle("active");
119-
120-
if (isActive) {
121-
const menuName = userContextMenu.el.querySelector(".user-menu-name");
122-
const menuEmail =
123-
userContextMenu.el.querySelector(".user-menu-email");
124-
125-
if (menuName) {
126-
menuName.content = (
127-
<div style={{ display: "flex" }}>
128-
{Boolean(user.verified) && (
129-
<span className="icon verified"></span>
130-
)}
131-
{user.name}
132-
{Boolean(user.acode_pro) && <span className="badge">Pro</span>}
133-
</div>
134-
);
135-
}
136118

137-
if (menuEmail) {
138-
menuEmail.textContent = user.email || "";
139-
}
119+
if (!confirmation) {
120+
return;
121+
}
140122

141-
setTimeout(() => {
142-
document.addEventListener("click", handleClickOutside);
143-
}, 10);
144-
} else {
145-
document.removeEventListener("click", handleClickOutside);
123+
loader.show();
124+
125+
await auth.login();
126+
user = await auth.getLoggedInUser();
127+
if (!user) {
128+
return;
146129
}
147130
}
131+
132+
const menu = userContextMenu.el;
133+
const isActive = menu.classList.toggle("active");
134+
135+
if (isActive) {
136+
const menuName = userContextMenu.el.querySelector(".user-menu-name");
137+
const menuEmail = userContextMenu.el.querySelector(".user-menu-email");
138+
139+
if (menuName) {
140+
menuName.content = (
141+
<div style={{ display: "flex" }}>
142+
{user.name}
143+
{Boolean(user.verified) && (
144+
<span className="icon verified badge"></span>
145+
)}
146+
{Boolean(user.acode_pro) && <span className="badge">Pro</span>}
147+
</div>
148+
);
149+
}
150+
151+
if (menuEmail) {
152+
menuEmail.textContent = user.email || "";
153+
}
154+
155+
setTimeout(() => {
156+
document.addEventListener("click", handleClickOutside);
157+
}, 10);
158+
} else {
159+
document.removeEventListener("click", handleClickOutside);
160+
}
148161
} catch (error) {
149162
console.error("Error checking login status:", error);
150163
toast("Error checking login status", 3000);
164+
} finally {
165+
loader.destroy();
151166
}
152167
}
153168

@@ -163,47 +178,84 @@ function create($container, $toggler) {
163178
}
164179

165180
async function handleLogout() {
181+
loader.create(strings["logout"], strings["loading..."]);
182+
loader.show();
166183
try {
184+
const user = await auth.getLoggedInUser();
167185
const success = await auth.logout();
168186
if (success) {
169187
userContextMenu.el.classList.remove("active");
170188
document.removeEventListener("click", handleClickOutside);
171-
toast("Logged out successfully");
172189
updateSidebarAvatar();
190+
toast("Logged out successfully");
191+
192+
try {
193+
const avatarFile = await getUserAvatar(user, false);
194+
if (avatarFile) {
195+
await fsOperation(avatarFile).delete();
196+
}
197+
} catch {}
173198
} else {
174199
toast("Failed to logout");
175200
}
176201
} catch (error) {
177202
console.error("Error during logout:", error);
203+
} finally {
204+
loader.destroy();
178205
}
179206
}
180207

181208
async function updateSidebarAvatar() {
182-
const existingIcon = userAvatar.el.querySelector(".icon");
183-
const existingAvatar = userAvatar.el.querySelector(".avatar");
209+
const defaultAvatar = <span className="icon account_circle" />;
210+
const user = await auth.getLoggedInUser();
184211

185-
if (existingIcon) {
186-
existingIcon.remove();
212+
userAvatar.content = defaultAvatar;
213+
214+
if (!user) {
215+
return;
187216
}
188-
if (existingAvatar) {
189-
existingAvatar.remove();
217+
218+
defaultAvatar.classList.add("loading");
219+
220+
const img = <img alt="User avatar" className="avatar" />;
221+
const avatarFile = await getUserAvatar(user);
222+
223+
img.src = avatarFile
224+
? await helpers.toInternalUri(avatarFile)
225+
: generateInitialsAvatar(user.name);
226+
img.onload = () => defaultAvatar.replaceWith(img);
227+
}
228+
229+
async function getUserAvatar(user, download = true) {
230+
let avatarUrl = user.avatar_url;
231+
232+
if (!avatarUrl) {
233+
if (!user.github) {
234+
return null;
235+
}
236+
avatarUrl = `https://avatars.githubusercontent.com/${user.github}`;
190237
}
191238

192-
const user = await auth.getLoggedInUser();
239+
const hash = avatarUrl.hashCode();
240+
const cacheFileName = `user_avatar_${hash}`;
241+
const cacheFile = Url.join(CACHE_STORAGE, cacheFileName);
193242

194-
if (user) {
195-
const avatarUrl = user.github
196-
? `https://avatars.githubusercontent.com/${user.github}`
197-
: generateInitialsAvatar(user.name);
198-
const avatarImg = document.createElement("img");
199-
avatarImg.className = "avatar";
200-
avatarImg.src = avatarUrl;
201-
userAvatar.append(avatarImg);
202-
} else {
203-
const defaultIcon = document.createElement("span");
204-
defaultIcon.className = "icon account_circle";
205-
userAvatar.append(defaultIcon);
243+
if (!(await fsOperation(cacheFile).exists())) {
244+
if (!download) {
245+
return null;
246+
}
247+
248+
const blob = await helpers.promisify(
249+
cordova.plugin.http.sendRequest,
250+
avatarUrl,
251+
{
252+
responseType: "blob",
253+
},
254+
);
255+
await fsOperation(CACHE_STORAGE).createFile(cacheFileName, blob.data);
206256
}
257+
258+
return cacheFile;
207259
}
208260

209261
function generateInitialsAvatar(name) {

src/components/sidebar/style.scss

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ body.no-animation {
114114
height: 40px;
115115
width: 40px;
116116
color: currentColor;
117-
font-size: 1.4em;
117+
font-size: 2.8em;
118118
border-radius: 10px;
119119
opacity: 0.6;
120120
transition: all 0.2s ease;
@@ -376,7 +376,13 @@ body.no-animation {
376376
border-radius: 4px;
377377
font-size: 12px;
378378
font-weight: 500;
379-
margin-left: 8px;
379+
margin-left: 4px;
380+
381+
&.verified {
382+
color: var(--active-color);
383+
background-color: transparent;
384+
padding: 0;
385+
}
380386
}
381387
}
382388

@@ -404,4 +410,4 @@ body.no-animation {
404410
background-color: var(--border-color);
405411
margin: 4px 0;
406412
}
407-
}
413+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import actionStack from "lib/actionStack";
44
import restoreTheme from "lib/restoreTheme";
55

66
/**
7-
* Confirm dialog box
7+
* Dialog box
88
* @param {string} titleText Title text
99
* @param {string} html HTML string
1010
* @param {string} [hideButtonText] Text for hide button
1111
* @param {string} [cancelButtonText] Text for cancel button
1212
* @returns {PromiseLike}
1313
*/
14-
function box(titleText, html, hideButtonText, cancelButtonText) {
14+
function dialog(titleText, html, hideButtonText, cancelButtonText) {
1515
let waitFor = 0,
1616
strOK = hideButtonText || strings.ok,
1717
_onclick = () => {},
@@ -197,4 +197,4 @@ function box(titleText, html, hideButtonText, cancelButtonText) {
197197
return promiseLike;
198198
}
199199

200-
export default box;
200+
export default dialog;

src/dialogs/rateBox.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import config from "lib/config";
22
import template from "views/rating.hbs";
3-
import box from "./box";
3+
import dialog from "./dialog";
44

55
function rateBox() {
6-
const $box = box("Did you like the app?", template, strings.cancel).onclick(
7-
onInteract,
8-
);
6+
const $box = dialog(
7+
"Did you like the app?",
8+
template,
9+
strings.cancel,
10+
).onclick(onInteract);
911

1012
function onInteract(e) {
1113
/**

src/dialogs/style.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@
103103
z-index: 111;
104104
background-color: rgb(0, 0, 0);
105105
opacity: 0.4;
106+
107+
~.mask {
108+
opacity: 0;
109+
}
106110
}
107111

108112
&.hide {

0 commit comments

Comments
 (0)