SettingsPage 重构 - IDE Agent 开发指令

任务目标

SettingsPage.ets 的设置项重新归类为三个分组,并同步修改 SiteSettingsPageUASettingsPage 的相关逻辑。


一、SettingsPage.ets 修改

文件路径:products/default/src/main/ets/pages/SettingsPage.ets

新增状态变量

@State searchSuggestionsEnabled: boolean = true;  // 搜索推荐开关
@State jsEnabled: boolean = true;                  // JavaScript 开关
@State imagesEnabled: boolean = true;             // 显示图片开关
@State dataSaverEnabled: boolean = false;         // 节省流量开关
@State textZoom: number = 100;                  // 文字缩放百分比

build() 结构(按此顺序重写 List 内容)

List() {
  // === 搜索设置 ===
  SectionHeader('搜索设置')
  SettingItem('搜索引擎', this.searchEngine, () => this.showSearchEngineDialog())
  ToggleItem('搜索推荐', '显示搜索建议', this.searchSuggestionsEnabled, (v) => {
    this.searchSuggestionsEnabled = v;
    // 保存到 Preferences,BrowserPage 地址栏读取此值控制搜索建议显示
  })

  // === 网站设置 ===
  SectionHeader('网站设置')
  SettingItem('网站设置', '管理网站特定设置', () => {
    router.pushUrl({ url: 'pages/SiteSettingsPage' });
  })
  ToggleItem('广告拦截', '拦截网页广告', this.adBlockEnabled, (v) => { ... })
  ToggleItem('允许 Cookie', '允许网站保存 Cookie', this.cookiesEnabled, (v) => { ... })
  ToggleItem('智能防跟踪', '阻止跨站跟踪', this.itpEnabled, (v) => { ... })
  SettingItem('浏览器 UA 标识', this.getUAName(), () => {
    router.pushUrl({ url: 'pages/UASettingsPage' });
  })

  // === 高级设置 ===
  SectionHeader('高级设置')
  SettingItem('用户代理', this.getUAName(), () => {
    router.pushUrl({ url: 'pages/UASettingsPage' });
  })
  SettingItem('脚本管理', '待开发', () => {
    console.log('Script manager not implemented yet');
  })
  ToggleItem('JavaScript', '', this.jsEnabled, (v) => {
    this.jsEnabled = v;
    // 保存到 SettingsManager.updateSettings({ javascriptEnabled: v })
  })
  ToggleItem('显示图片', '', this.imagesEnabled, (v) => {
    this.imagesEnabled = v;
    // 保存到 SettingsManager.updateSettings({ imageEnabled: v })
  })
  ToggleItem('节省流量', '', this.dataSaverEnabled, (v) => {
    this.dataSaverEnabled = v;
    // 保存到 SettingsManager.updateSettings({ dataSaverEnabled: v })
  })
  // 文字缩放(步进控制器,不是 Toggle)
  this.TextZoomItem()

  // === 数据管理(保持不变)===
  SectionHeader('数据管理')
  ActionItem('清除浏览历史', '清除访问记录', () => { ... })
  ActionItem('清除缓存', '清除网页缓存', () => { ... })
  ActionItem('清除 Cookie', '清除所有 Cookie', () => { ... })
  ActionItem('清除所有数据', '清除浏览历史、缓存和 Cookie', () => { ... })

  // === 关于(保持不变)===
  SectionHeader('关于')
  InfoItem('版本', '1.0.0')
  ActionItem('恢复默认设置', '', () => { ... })
}

新增 Builder:TextZoomItem

@Builder
TextZoomItem() {
  Row() {
    Text('文字缩放')
      .fontSize(16)
      .fontColor('#333333')
      .layoutWeight(1)

    Text(this.textZoom + '%')
      .fontSize(14)
      .fontColor('#1976D2')
      .margin({ right: 8 })

    Row() {
      Button('-')
        .width(32).height(32).fontSize(16)
        .enabled(this.textZoom > 50)
        .onClick(() => {
          if (this.textZoom > 50) {
            this.textZoom -= 10;
            SettingsManager.updateSettings({ textZoom: this.textZoom });
          }
        })
      Text(this.textZoom.toString())
        .width(40).textAlign(TextAlign.Center).fontSize(14)
      Button('+')
        .width(32).height(32).fontSize(16)
        .enabled(this.textZoom < 200)
        .onClick(() => {
          if (this.textZoom < 200) {
            this.textZoom += 10;
            SettingsManager.updateSettings({ textZoom: this.textZoom });
          }
        })
    }
  }
  .width('100%')
  .padding({ left: 16, right: 16, top: 12, bottom: 12 })
  .backgroundColor('#FFFFFF')
  .border({ width: { bottom: 1 }, color: '#F0F0F0' })
}

移除的设置项

  • 主页 设置项(当前为 TODO,无实际功能,暂时移除)
  • 用户代理 原来在「常规设置」分组里,已移入「高级设置」

getUAName() 辅助方法

private getUAName(): string {
  const presetName = UserAgentManager.getInstance().getCurrentPresetName();
  return presetName === 'Custom' ? '自定义' : presetName;
}

aboutToAppear 初始化

aboutToAppear 中从 SettingsManager 加载新增状态变量的初始值:

async aboutToAppear(): Promise<void> {
  const settings = SettingsManager.getSettings();
  this.searchSuggestionsEnabled = true;  // 默认开启,后续可持久化
  this.jsEnabled = settings.javascriptEnabled ?? true;
  this.imagesEnabled = settings.imageEnabled ?? true;
  this.dataSaverEnabled = settings.dataSaverEnabled ?? false;
  this.textZoom = settings.textZoom ?? 100;
}

二、SiteSettingsPage.ets 修改

文件路径:products/default/src/main/ets/pages/SiteSettingsPage.ets

在「全局设置」区域,「广告拦截」Toggle 下方新增「浏览器 UA 标识」设置项

build() 的「全局设置」Column 里,this.SettingToggle('广告拦截', ...) 之后加:

Divider().margin({ left: 16 })

// 浏览器 UA 标识
Row() {
  Text('浏览器 UA 标识')
    .fontSize(16)
    .fontColor('#333333')
    .layoutWeight(1)

  Text(this.globalSettings.defaultUserAgent || '默认(使用系统 UA)')
    .fontSize(14)
    .fontColor('#1976D2')
    .margin({ right: 8 })

  SymbolGlyph($r('sys.symbol.chevron_right'))
    .fontSize(16)
    .fontColor(['#CCCCCC'])
}
.width('100%')
.padding({ left: 16, right: 16, top: 12, bottom: 12 })
.backgroundColor('#FFFFFF')
.onClick(() => {
  this.showUASelectorForGlobal();
})

新增方法:showUASelectorForGlobal()

showUASelectorForGlobal(): void {
  const uaOptions = this.userAgentManager.getPresets();
  this.uaList = ['默认(使用系统 UA)', ...uaOptions.map((item: UserAgentPreset) => item.name)];
  
  const current = this.globalSettings.defaultUserAgent || '';
  this.selectedUAIndex = current ? this.uaList.indexOf(current) : 0;
  this.showUASelectorDialog = true;
}

修改 selectUA() 方法,支持全局设置

在现有的 selectUA(index) 里,增加判断:如果来源是全局设置,则保存到 globalSettings.defaultUserAgent

selectUA(index: number): void {
  const uaOptions = this.userAgentManager.getPresets();
  if (index === 0) {
    this.editingSettings.userAgent = '';
    this.globalSettings.defaultUserAgent = '';  // 新增:清除全局 UA
  } else {
    const selectedName = uaOptions[index - 1].name;  // -1 因为 uaList[0] 是"默认"
    this.editingSettings.userAgent = selectedName;
    this.globalSettings.defaultUserAgent = selectedName;  // 新增:保存全局 UA
  }
  this.showUASelectorDialog = false;
  this.saveGlobalSettings();  // 新增:持久化
}

注意:uaListshowUASelectorForGlobal() 里会被重新赋值,包含"默认"选项。selectUA 需要兼容两种场景(站点编辑器和全局设置)。建议在 showUASelector() 里也同步更新 uaList 格式,或在 selectUA 里根据 this.showSiteEditor 判断是存到 editingSettings 还是 globalSettings


三、UASettingsPage.ets 修改

文件路径:products/default/src/main/ets/pages/UASettingsPage.ets

aboutToAppear 修改:同步读取 SiteSettingsManager 的全局 UA

aboutToAppear(): void {
  this.presets = this.userAgentManager.getPresets();
  
  // 从 SiteSettingsManager 读取全局 UA 预设名(权威来源)
  const siteSettingsMgr = SiteSettingsManager.getInstance();
  const globalSettings = siteSettingsMgr.getGlobalSettings();
  this.selectedPreset = globalSettings.defaultUserAgent || 'Android';
  
  this.customUA = this.userAgentManager.getCustomUA();
  this.showCustomInput = this.selectedPreset === 'Custom';
}

applySettings() 修改:同时写入 SiteSettingsManager

private applySettings(): void {
  if (this.selectedPreset === 'Custom') {
    this.userAgentManager.setCustomUA(this.customUA);
    this.userAgentManager.setPresetUA('Custom');
    // 同步到 SiteSettingsManager 全局设置
    SiteSettingsManager.getInstance().setGlobalSetting('defaultUserAgent', 'Custom');
  } else {
    this.userAgentManager.setPresetUA(this.selectedPreset);
    // 同步到 SiteSettingsManager 全局设置
    SiteSettingsManager.getInstance().setGlobalSetting('defaultUserAgent', this.selectedPreset);
  }
  this.showToast('用户代理已更新,请刷新页面生效');
}

注意:SiteSettingsManager 需要新增 setGlobalSetting(key, value) 方法,用于只更新单个字段而不覆盖整个 GlobalSettings 对象。如果该方法不存在,需要在 SiteSettingsManager.ets 中新增:

async setGlobalSetting(key: string, value: string): Promise<void> {
  const settings = await this.getGlobalSettings();
  (settings as any)[key] = value;
  await this.saveGlobalSettings(settings);
}

四、SettingsManager.ets 修改

文件路径:products/default/src/main/ets/managers/SettingsManager.ets

BrowserSettings 接口新增字段

export interface BrowserSettings {
  // ...现有字段...
  searchSuggestionsEnabled: boolean;  // 新增:搜索推荐开关
}

createDefaultSettings() 新增默认值

function createDefaultSettings(): BrowserSettings {
  return {
    // ...现有字段...
    searchSuggestionsEnabled: true,  // 默认开启搜索推荐
  };
}

updateSettings() 新增处理

updateSettings() 方法的 if 链中新增:

if (updates.searchSuggestionsEnabled !== undefined) {
  this.settings.searchSuggestionsEnabled = updates.searchSuggestionsEnabled;
}

新增 getter/setter

isSearchSuggestionsEnabled(): boolean {
  return this.settings.searchSuggestionsEnabled;
}

async setSearchSuggestionsEnabled(enabled: boolean): Promise<void> {
  await this.updateSettings({ searchSuggestionsEnabled: enabled });
}

五、SiteSettingsManager.ets 修改

文件路径:products/default/src/main/ets/utils/SiteSettingsManager.ets

注意:GlobalSettings 接口已有 defaultUserAgent: string 字段,无需新增。

需要新增的方法

// 保存全局设置(支持部分更新)
async saveGlobalSettingsPartial(partial: Partial<GlobalSettings>): Promise<void> {
  const current = await this.getGlobalSettings();
  const updated = { ...current, ...partial };
  await this.saveGlobalSettings(updated);
}

// 获取单例(如果还没有 getInstance 的话,确认现有代码)

六、验收标准

  1. SettingsPage 设置项按「搜索设置 / 网站设置 / 高级设置 / 数据管理 / 关于」五组显示,顺序严格按本文档「一」中的结构
  2. 点击「搜索引擎」弹出选择菜单(百度/Google/Bing/搜狗),选择后 SettingsManager.getSearchEngine() 返回值正确
  3. 「搜索推荐」开关状态持久化到 SettingsManagerBrowserPage 地址栏搜索建议随之显示/隐藏
  4. 「网站设置」分组内的广告拦截/Cookie/ITP 开关功能正常
  5. SiteSettingsPage 全局设置中可设置「浏览器 UA 标识」,保存到 Preferences
  6. UASettingsPage 的 UA 选择结果与 SiteSettingsManager.getGlobalSettings().defaultUserAgent 同步
  7. 「脚本管理」入口可点击,不崩溃,控制台输出 Script manager not implemented yet
  8. 清除数据、恢复默认设置功能不受影响
  9. 「高级设置」内的 JavaScript/显示图片/节省流量/文字缩放 开关/步进器功能正常,状态持久化

七、不需要改动的部分

  • SiteSettingsPage 的站点特定设置编辑器(SiteEditorSheet)不需要改动
  • AdBlockManager.ets 不需要改动
  • BrowserPage.ets 本次不修改(搜索推荐联动在后续 PR 处理)
  • 路由配置(main_pages.json 等)不需要改动