Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions entry/src/main/ets/components/IconPackManager.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import { common } from '@kit.AbilityKit';
import { AegisIconPack, IconPackRegistry } from '../utils/IconPackUtils';
import { DefaultToastDuration } from '../pages/Base';
import { parseInstalledIconPacks, refreshInstalledIconPacks } from '../entryability/EntryAbility';

@Component
export struct IconPackManager {
@StorageLink('selectedIconPackKey') selectedIconPackKey: string = IconPackRegistry.getDefaultPackKey();
@StorageLink('installedIconPacksJson') installedIconPacksJson: string = '[]';
@State expanded: boolean = false;

aboutToAppear(): void {
this.reloadPacks();
}

private getInstalledPacks(): AegisIconPack[] {
return parseInstalledIconPacks(this.installedIconPacksJson);
}

private async reloadPacks(): Promise<void> {
const context = getContext(this) as common.UIAbilityContext;
const packs = await refreshInstalledIconPacks(context);
if (this.selectedIconPackKey !== IconPackRegistry.getDefaultPackKey()
&& !packs.some((pack) => pack.getKey() === this.selectedIconPackKey && !pack.invalid)) {
this.selectedIconPackKey = IconPackRegistry.getDefaultPackKey();
}
}

private showToast(message: ResourceStr | string): void {
this.getUIContext().getPromptAction().showToast({
duration: DefaultToastDuration,
message
});
}

private getInstalledCount(): number {
return this.getInstalledPacks().filter((pack) => !pack.invalid).length;
}

private getPackName(pack: AegisIconPack): ResourceStr | string {
if (pack.invalid) {
return $r('app.string.icon_pack_invalid_name_format', pack.name);
}
return pack.name;
}

private getPackSubtitle(pack: AegisIconPack): ResourceStr | string {
if (pack.invalid) {
return $r('app.string.icon_pack_invalid_desc');
}
return $r('app.string.icon_pack_meta_format', pack.icons.length, `${pack.version}`);
}

private async onImportPressed(): Promise<void> {
const context = getContext(this) as common.UIAbilityContext;
try {
const paths = await IconPackRegistry.pickZipFiles(context);
if (paths.length === 0) {
return;
}
for (const path of paths) {
await IconPackRegistry.importFromZip(context, path);
}
await this.reloadPacks();
this.showToast($r('app.string.icon_pack_import_success'));
} catch (error) {
this.showToast($r('app.string.icon_pack_import_failed_format',
IconPackRegistry.formatImportError(error as Object)));
}
}

private async onRemovePressed(pack: AegisIconPack): Promise<void> {
try {
await IconPackRegistry.removePack(pack);
if (this.selectedIconPackKey === pack.getKey()) {
this.selectedIconPackKey = IconPackRegistry.getDefaultPackKey();
}
await this.reloadPacks();
this.showToast($r('app.string.icon_pack_remove_success'));
} catch (error) {
this.showToast($r('app.string.icon_pack_remove_failed_format',
IconPackRegistry.formatImportError(error as Object)));
}
}

@Builder
private packRow(value: string, name: ResourceStr | string, subtitle: ResourceStr | string, selected: boolean,
enabled: boolean, onSelect: () => void, onRemove?: () => void) {
Row() {
Radio({ value, group: 'icon-pack-group' })
.checked(selected)
.enabled(enabled)
.onChange((checked) => {
if (checked && enabled) {
onSelect();
}
})

Column() {
Text(name)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Start)
Text(subtitle)
.fontSize(12)
.textAlign(TextAlign.Start)
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)

if (onRemove) {
Button($r('app.string.icon_pack_remove'))
.type(ButtonType.Capsule)
.buttonStyle(ButtonStyleMode.TEXTUAL)
.onClick(() => onRemove())
}
}
.width('100%')
.padding(12)
.borderRadius(12)
.backgroundColor($r("app.color.icon_pack_row_background"))
}

build() {
Column() {
Row() {
Text($r('app.string.icon_pack_title'))
.width('85%')
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Start)
Button(this.expanded ? $r('app.string.icon_pack_hide') : $r('app.string.icon_pack_manage'))
.type(ButtonType.Capsule)
.buttonStyle(ButtonStyleMode.TEXTUAL)
.onClick(() => {
this.expanded = !this.expanded;
})
}
.width('100%')
.alignItems(VerticalAlign.Center)

Row() {
Text($r('app.string.icon_pack_desc'))
.padding({ left: 10 })
.fontSize(12)
}
.width('100%')

if (this.expanded) {
Column({ space: 8 }) {
this.packRow(
IconPackRegistry.getDefaultPackKey(),
$r('app.string.icon_pack_builtin'),
$r('app.string.icon_pack_builtin_desc'),
this.selectedIconPackKey === IconPackRegistry.getDefaultPackKey(),
true,
() => {
this.selectedIconPackKey = IconPackRegistry.getDefaultPackKey();
}
)

ForEach(this.getInstalledPacks(), (pack: AegisIconPack) => {
this.packRow(
pack.getKey(),
this.getPackName(pack),
this.getPackSubtitle(pack),
this.selectedIconPackKey === pack.getKey(),
!pack.invalid,
() => {
this.selectedIconPackKey = pack.getKey();
},
() => this.onRemovePressed(pack)
)
}, (pack: AegisIconPack) => pack.getKey())

Row({ space: 12 }) {
Button($r('app.string.icon_pack_import'))
.type(ButtonType.Capsule)
.onClick(() => this.onImportPressed())
Text($r('app.string.icon_pack_installed_count_format', this.getInstalledCount()))
.fontSize(12)
.fontColor('#666666')
}
.margin({ top: 4 })
}
.width('100%')
.margin({ top: 12, left: 30, right: 20 })
}
}
.width('100%')
.padding({ top: 8, bottom: 8 })
}
}
86 changes: 86 additions & 0 deletions entry/src/main/ets/components/TokenIcon.ets
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { fileIo as fs } from '@kit.CoreFileKit';
import { AegisIconPack, IconPackRegistry } from '../utils/IconPackUtils';
import { parseInstalledIconPacks } from '../entryability/EntryAbility';

@Component
export struct TokenIcon {
@Prop issuer: string = '';
@Prop iconPath: string = '';
@StorageLink('selectedIconPackKey') selectedIconPackKey: string = IconPackRegistry.getDefaultPackKey();
@StorageLink('installedIconPacksJson') installedIconPacksJson: string = '[]';

private getInstalledPacks(): AegisIconPack[] {
return parseInstalledIconPacks(this.installedIconPacksJson);
}

private resolveIconPath(): string {
if (this.iconPath && this.isValidPath(this.iconPath)) {
return this.iconPath;
}
return IconPackRegistry.getIconPathByIssuer(this.issuer, this.selectedIconPackKey, this.getInstalledPacks());
}

private isValidPath(path: string): boolean {
if (path.startsWith('rawfile://')) {
return true;
}
if (path.startsWith('file://')) {
return fs.accessSync(path.slice(7));
}
return fs.accessSync(path);
}

private getImageSource(): ResourceStr | string | undefined {
const path = this.resolveIconPath();
if (!path) {
return undefined;
}
if (path.startsWith('rawfile://')) {
return $rawfile(path.slice(10));
}
return path;
}

private hasImageSource(): boolean {
return this.getImageSource() !== undefined;
}

private stringToColor(input: string): string {
let hash = 0;
for (let index = 0; index < input.length; index++) {
hash = input.charCodeAt(index) + ((hash << 5) - hash);
}

let color = '#';
for (let index = 0; index < 3; index++) {
const value = (hash >> (index * 8)) & 0xff;
const hex = `00${value.toString(16)}`;
color += hex.substring(hex.length - 2);
}
return color;
}

build() {
Stack() {
if (this.hasImageSource()) {
Image(this.getImageSource())
.width(40)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

svg 的大小不一,这里统一宽高,图标看起来也会大小不一

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

大佬,关于这个我想请教一下。就是我考虑把这些内置图标换掉,用aegis-icon的图标,大小应该会比较统一,但是感觉可能会有一些版权方面的问题,而且现在添加的也未必没有这方面的问题。要不还是就保留你之前的那些图标,我的那些都删掉吧,保留图标包的功能,把这方面的版权问题规避掉,都由用户来添加。

.height(40)
.objectFit(ImageFit.Contain)
.draggable(false)
} else {
Text(this.issuer.length > 0 ? this.issuer.charAt(0).toUpperCase() : '?')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
}
}
.width(50)
.height(50)
.padding(5)
.margin(10)
.backgroundColor(this.hasImageSource() ? $r('app.color.vendor_background_color') :
this.stringToColor(this.issuer || 'k'))
.borderRadius(20)
}
}
Loading