diff --git a/assets/init.js b/assets/init.js index a9ad57c..7e067cf 100644 --- a/assets/init.js +++ b/assets/init.js @@ -1322,13 +1322,15 @@ let UI = { * Show an input dialog * @param title {string} * @param validator {(string) => string | null | undefined} - A function that validates the input. If the function returns a string, the dialog will show the error message. + * @param image {string?} - Available since 1.4.6. An optional image to show in the dialog. You can use this to show a captcha. * @returns {Promise} - The input value. If the dialog is canceled, return null. */ - showInputDialog: (title, validator) => { + showInputDialog: (title, validator, image) => { return sendMessage({ method: 'UI', function: 'showInputDialog', title: title, + image: image, validator: validator }) }, diff --git a/assets/opencc.txt b/assets/opencc.txt new file mode 100644 index 0000000..e4fc467 --- /dev/null +++ b/assets/opencc.txt @@ -0,0 +1,3982 @@ +# OpenCC Simplified Chinese to Traditional Chinese conversion table +# Original source: https://github.com/BYVoid/OpenCC +㐷傌 +㐹㑶 +㐽偑 +㑇㑳 +㑈倲 +㑔㑯 +㑩儸 +㓆𠗣 +㓥劏 +㓰劃 +㔉劚 +㖊噚 +㖞喎 +㘎㘚 +㚯㜄 +㛀媰 +㛟𡞵 +㛠𡢃 +㛣㜏 +㛤孋 +㛿𡠹 +㟆㠏 +㟜𡾱 +㟥嵾 +㡎幓 +㤘㥮 +㤽懤 +㥪慺 +㧏掆 +㧐㩳 +㧑撝 +㧟擓 +㧰擽 +㨫㩜 +㭎棡 +㭏椲 +㭣𣙎 +㭤樢 +㭴樫 +㱩殰 +㱮殨 +㲿瀇 +㳔濧 +㳕灡 +㳠澾 +㳡濄 +㳢𣾷 +㳽瀰 +㴋潚 +㶉鸂 +㶶燶 +㶽煱 +㺍獱 +㻅璯 +㻏𤫩 +㻘𤪺 +䀥䁻 +䁖瞜 +䂵碽 +䃅磾 +䅉稏 +䅟穇 +䅪𥢢 +䇲筴 +䉤籔 +䌶䊷 +䌷紬 +䌸縳 +䌹絅 +䌺䋙 +䌻䋚 +䌼綐 +䌽綵 +䌾䋻 +䌿䋹 +䍀繿 +䍁繸 +䍠䍦 +䎬䎱 +䏝膞 +䑽𦪙 +䓓薵 +䓕薳 +䓖藭 +䓨罃 +䗖螮 +䘛𧝞 +䘞𧜗 +䙊𧜵 +䙌䙡 +䙓襬 +䜣訢 +䜤鿁 +䜥𧩙 +䜧䜀 +䜩讌 +䝙貙 +䞌𧵳 +䞍䝼 +䞎𧶧 +䞐賰 +䟢躎 +䢀𨊰 +䢁𨊸 +䢂𨋢 +䥺釾 +䥽鏺 +䥾䥱 +䥿𨯅 +䦀𨦫 +䦁𨧜 +䦂䥇 +䦃鐯 +䦅鐥 +䦆钁 +䦶䦛 +䦷䦟 +䩄靦 +䭪𩞯 +䯃𩣑 +䯄騧 +䯅䯀 +䲝䱽 +䲞𩶘 +䲟鮣 +䲠鰆 +䲡鰌 +䲢鰧 +䲣䱷 +䴓鳾 +䴔鵁 +䴕鴷 +䴖鶄 +䴗鶪 +䴘鷉 +䴙鸊 +䶮龑 +万萬 +与與 +丑醜 +专專 +业業 +丛叢 +东東 +丝絲 +丢丟 +两兩 +严嚴 +丧喪 +个個 +丰豐 +临臨 +为爲 +丽麗 +举舉 +么麼 +义義 +乌烏 +乐樂 +乔喬 +习習 +乡鄉 +书書 +买買 +乱亂 +了了 +争爭 +于於 +亏虧 +云雲 +亘亙 +亚亞 +产產 +亩畝 +亲親 +亵褻 +亸嚲 +亿億 +仅僅 +仆僕 +仇仇 +从從 +仑侖 +仓倉 +仪儀 +们們 +价價 +仿仿 +众衆 +优優 +伙夥 +会會 +伛傴 +伞傘 +伟偉 +传傳 +伡俥 +伣俔 +伤傷 +伥倀 +伦倫 +伧傖 +伪僞 +伫佇 +体體 +余餘 +佛佛 +佣傭 +佥僉 +侠俠 +侣侶 +侥僥 +侦偵 +侧側 +侨僑 +侩儈 +侪儕 +侬儂 +侭儘 +俊俊 +俣俁 +俦儔 +俨儼 +俩倆 +俪儷 +俫倈 +俭儉 +修修 +借借 +债債 +倾傾 +偬傯 +偻僂 +偾僨 +偿償 +傤儎 +傥儻 +傧儐 +储儲 +傩儺 +僵僵 +儿兒 +克克 +兑兌 +兖兗 +党黨 +兰蘭 +关關 +兴興 +兹茲 +养養 +兽獸 +冁囅 +内內 +冈岡 +册冊 +写寫 +军軍 +农農 +冬冬 +冯馮 +冲衝 +决決 +况況 +冻凍 +净淨 +凄悽 +准準 +凉涼 +凌凌 +减減 +凑湊 +凛凜 +几幾 +凤鳳 +凫鳧 +凭憑 +凯凱 +凶兇 +出出 +击擊 +凿鑿 +刍芻 +划劃 +刘劉 +则則 +刚剛 +创創 +删刪 +别別 +刬剗 +刭剄 +刮刮 +制制 +刹剎 +刽劊 +刾㓨 +刿劌 +剀剴 +剂劑 +剐剮 +剑劍 +剥剝 +剧劇 +劝勸 +办辦 +务務 +劢勱 +动動 +励勵 +劲勁 +劳勞 +势勢 +勋勳 +勚勩 +匀勻 +匦匭 +匮匱 +区區 +医醫 +千千 +升升 +华華 +协協 +单單 +卖賣 +卜卜 +占佔 +卢盧 +卤滷 +卧臥 +卫衛 +却卻 +卷卷 +卺巹 +厂廠 +厅廳 +历歷 +厉厲 +压壓 +厌厭 +厍厙 +厐龎 +厕廁 +厘釐 +厢廂 +厣厴 +厦廈 +厨廚 +厩廄 +厮廝 +县縣 +叁叄 +参參 +叆靉 +叇靆 +双雙 +发發 +变變 +叙敘 +叠疊 +只只 +台臺 +叶葉 +号號 +叹嘆 +叽嘰 +吁籲 +吃喫 +合合 +吊吊 +同同 +后後 +向向 +吓嚇 +吕呂 +吗嗎 +吨噸 +听聽 +启啓 +吴吳 +呐吶 +呒嘸 +呓囈 +呕嘔 +呖嚦 +呗唄 +员員 +呙咼 +呛嗆 +呜嗚 +周周 +咏詠 +咙嚨 +咛嚀 +咝噝 +咤吒 +咨諮 +咸鹹 +咽咽 +哄哄 +响響 +哑啞 +哒噠 +哓嘵 +哔嗶 +哕噦 +哗譁 +哙噲 +哜嚌 +哝噥 +哟喲 +唇脣 +唛嘜 +唝嗊 +唠嘮 +唡啢 +唢嗩 +唤喚 +啧嘖 +啬嗇 +啭囀 +啮齧 +啯嘓 +啰囉 +啴嘽 +啸嘯 +喂喂 +喷噴 +喽嘍 +喾嚳 +嗫囁 +嗳噯 +嘘噓 +嘤嚶 +嘱囑 +噜嚕 +噪噪 +嚣囂 +回回 +团團 +园園 +困困 +囱囪 +围圍 +囵圇 +国國 +图圖 +圆圓 +圣聖 +圹壙 +场場 +坏壞 +块塊 +坚堅 +坛壇 +坜壢 +坝壩 +坞塢 +坟墳 +坠墜 +垄壟 +垅壠 +垆壚 +垒壘 +垦墾 +垩堊 +垫墊 +垭埡 +垯墶 +垱壋 +垲塏 +垴堖 +埘塒 +埙壎 +埚堝 +堑塹 +堕墮 +塆壪 +墙牆 +壮壯 +声聲 +壳殼 +壶壺 +壸壼 +处處 +备備 +复復 +够夠 +夫夫 +头頭 +夸誇 +夹夾 +夺奪 +奁奩 +奂奐 +奋奮 +奖獎 +奥奧 +奸奸 +妆妝 +妇婦 +妈媽 +妩嫵 +妪嫗 +妫嬀 +姗姍 +姜姜 +姹奼 +娄婁 +娅婭 +娆嬈 +娇嬌 +娈孌 +娘娘 +娱娛 +娲媧 +娴嫺 +婳嫿 +婴嬰 +婵嬋 +婶嬸 +媪媼 +媭嬃 +嫒嬡 +嫔嬪 +嫱嬙 +嬷嬤 +孙孫 +学學 +孪孿 +宁寧 +它它 +宝寶 +实實 +宠寵 +审審 +宪憲 +宫宮 +家家 +宽寬 +宾賓 +寝寢 +对對 +寻尋 +导導 +寿壽 +将將 +尔爾 +尘塵 +尝嘗 +尧堯 +尴尷 +尸屍 +尽盡 +局局 +层層 +屃屓 +屉屜 +届屆 +属屬 +屡屢 +屦屨 +屿嶼 +岁歲 +岂豈 +岖嶇 +岗崗 +岘峴 +岚嵐 +岛島 +岩巖 +岭嶺 +岳嶽 +岽崬 +岿巋 +峃嶨 +峄嶧 +峡峽 +峣嶢 +峤嶠 +峥崢 +峦巒 +峰峯 +崂嶗 +崃崍 +崄嶮 +崭嶄 +嵘嶸 +嵚嶔 +嵝嶁 +巅巔 +巨巨 +巩鞏 +巯巰 +币幣 +布布 +帅帥 +师師 +帏幃 +帐帳 +帘簾 +帜幟 +带帶 +帧幀 +席席 +帮幫 +帱幬 +帻幘 +帼幗 +幂冪 +干幹 +并並 +幸幸 +广廣 +庄莊 +庆慶 +床牀 +庐廬 +庑廡 +库庫 +应應 +庙廟 +庞龐 +废廢 +庵庵 +庼廎 +廪廩 +开開 +异異 +弃棄 +弑弒 +张張 +弥彌 +弦弦 +弪弳 +弯彎 +弹彈 +强強 +归歸 +当當 +录錄 +彟彠 +彦彥 +彨彲 +彩彩 +彻徹 +征徵 +径徑 +徕徠 +御御 +忆憶 +忏懺 +志志 +忧憂 +念念 +忾愾 +怀懷 +态態 +怂慫 +怃憮 +怄慪 +怅悵 +怆愴 +怜憐 +总總 +怼懟 +怿懌 +恋戀 +恒恆 +恤恤 +恳懇 +恶惡 +恸慟 +恹懨 +恺愷 +恻惻 +恼惱 +恽惲 +悦悅 +悫愨 +悬懸 +悭慳 +悮悞 +悯憫 +惊驚 +惧懼 +惨慘 +惩懲 +惫憊 +惬愜 +惭慚 +惮憚 +惯慣 +愈愈 +愠慍 +愤憤 +愦憒 +愿願 +慑懾 +慭憖 +懑懣 +懒懶 +懔懍 +戆戇 +戋戔 +戏戲 +戗戧 +战戰 +戚戚 +戬戩 +戯戱 +户戶 +才才 +扎扎 +扑撲 +托託 +扣扣 +执執 +扩擴 +扪捫 +扫掃 +扬揚 +扰擾 +折折 +抚撫 +抛拋 +抟摶 +抠摳 +抡掄 +抢搶 +护護 +报報 +抵抵 +担擔 +拐拐 +拟擬 +拢攏 +拣揀 +拥擁 +拦攔 +拧擰 +拨撥 +择擇 +挂掛 +挚摯 +挛攣 +挜掗 +挝撾 +挞撻 +挟挾 +挠撓 +挡擋 +挢撟 +挣掙 +挤擠 +挥揮 +挦撏 +挨挨 +挽挽 +捝挩 +捞撈 +损損 +捡撿 +换換 +捣搗 +据據 +掳擄 +掴摑 +掷擲 +掸撣 +掺摻 +掼摜 +揽攬 +揾搵 +揿撳 +搀攙 +搁擱 +搂摟 +搄揯 +搅攪 +搜搜 +携攜 +摄攝 +摅攄 +摆擺 +摇搖 +摈擯 +摊攤 +撄攖 +撑撐 +撵攆 +撷擷 +撸擼 +撺攛 +擜㩵 +擞擻 +攒攢 +敌敵 +敚敓 +敛斂 +敩斆 +数數 +斋齋 +斓斕 +斗鬥 +斩斬 +断斷 +旋旋 +无無 +旧舊 +时時 +旷曠 +旸暘 +昆昆 +昙曇 +昵暱 +昼晝 +昽曨 +显顯 +晋晉 +晒曬 +晓曉 +晔曄 +晕暈 +晖暉 +暂暫 +暅𣈶 +暗暗 +暧曖 +曲曲 +术術 +朱朱 +朴樸 +机機 +杀殺 +杂雜 +权權 +杆杆 +杠槓 +条條 +来來 +杨楊 +杩榪 +杯杯 +杰傑 +松松 +板板 +极極 +构構 +枞樅 +枢樞 +枣棗 +枥櫪 +枧梘 +枨棖 +枪槍 +枫楓 +枭梟 +柜櫃 +柠檸 +柽檉 +栀梔 +栅柵 +标標 +栈棧 +栉櫛 +栊櫳 +栋棟 +栌櫨 +栎櫟 +栏欄 +树樹 +栖棲 +栗栗 +样樣 +核核 +栾欒 +桠椏 +桡橈 +桢楨 +档檔 +桤榿 +桥橋 +桦樺 +桧檜 +桨槳 +桩樁 +桪樳 +梁梁 +梦夢 +梼檮 +梾棶 +梿槤 +检檢 +棁梲 +棂欞 +椁槨 +椝槼 +椟櫝 +椠槧 +椢槶 +椤欏 +椫樿 +椭橢 +椮槮 +楼樓 +榄欖 +榅榲 +榇櫬 +榈櫚 +榉櫸 +榝樧 +槚檟 +槛檻 +槟檳 +槠櫧 +横橫 +樯檣 +樱櫻 +橥櫫 +橱櫥 +橹櫓 +橼櫞 +檩檁 +欢歡 +欤歟 +欧歐 +欲欲 +歼殲 +殁歿 +殇殤 +残殘 +殒殞 +殓殮 +殚殫 +殡殯 +殴毆 +毁毀 +毂轂 +毕畢 +毙斃 +毡氈 +毵毿 +毶𣯶 +氇氌 +气氣 +氢氫 +氩氬 +氲氳 +汇匯 +汉漢 +汤湯 +汹洶 +沄澐 +沈沈 +沟溝 +没沒 +沣灃 +沤漚 +沥瀝 +沦淪 +沧滄 +沨渢 +沩潙 +沪滬 +沾沾 +泛泛 +泞濘 +注注 +泪淚 +泶澩 +泷瀧 +泸瀘 +泺濼 +泻瀉 +泼潑 +泽澤 +泾涇 +洁潔 +洒灑 +洼窪 +浃浹 +浅淺 +浆漿 +浇澆 +浈湞 +浉溮 +浊濁 +测測 +浍澮 +济濟 +浏瀏 +浐滻 +浑渾 +浒滸 +浓濃 +浔潯 +浕濜 +涂塗 +涌湧 +涚涗 +涛濤 +涝澇 +涞淶 +涟漣 +涠潿 +涡渦 +涢溳 +涣渙 +涤滌 +润潤 +涧澗 +涨漲 +涩澀 +淀澱 +渊淵 +渌淥 +渍漬 +渎瀆 +渐漸 +渑澠 +渔漁 +渖瀋 +渗滲 +温溫 +游遊 +湾灣 +湿溼 +溁濚 +溃潰 +溅濺 +溆漵 +溇漊 +滗潷 +滚滾 +滞滯 +滟灩 +滠灄 +满滿 +滢瀅 +滤濾 +滥濫 +滦灤 +滨濱 +滩灘 +滪澦 +漓漓 +潆瀠 +潇瀟 +潋瀲 +潍濰 +潜潛 +潴瀦 +澛瀂 +澜瀾 +濑瀨 +濒瀕 +灏灝 +灭滅 +灯燈 +灵靈 +灶竈 +灾災 +灿燦 +炀煬 +炉爐 +炖燉 +炜煒 +炝熗 +点點 +炼煉 +炽熾 +烁爍 +烂爛 +烃烴 +烛燭 +烟煙 +烦煩 +烧燒 +烨燁 +烩燴 +烫燙 +烬燼 +热熱 +焕煥 +焖燜 +焘燾 +煴熅 +熏燻 +爱愛 +爷爺 +牍牘 +牦犛 +牵牽 +牺犧 +犊犢 +状狀 +犷獷 +犸獁 +犹猶 +狈狽 +狝獮 +狞獰 +独獨 +狭狹 +狮獅 +狯獪 +狰猙 +狱獄 +狲猻 +猃獫 +猎獵 +猕獼 +猡玀 +猪豬 +猫貓 +猬蝟 +献獻 +獭獺 +玑璣 +玙璵 +玚瑒 +玛瑪 +玩玩 +玮瑋 +环環 +现現 +玱瑲 +玺璽 +珐琺 +珑瓏 +珰璫 +珲琿 +琎璡 +琏璉 +琐瑣 +琼瓊 +瑶瑤 +瑷璦 +瑸璸 +璇璇 +璎瓔 +瓒瓚 +瓮甕 +瓯甌 +电電 +画畫 +畅暢 +畴疇 +疖癤 +疗療 +疟瘧 +疠癘 +疡瘍 +疬癧 +疭瘲 +疮瘡 +疯瘋 +疱皰 +疴痾 +症症 +痈癰 +痉痙 +痒癢 +痖瘂 +痨癆 +痪瘓 +痫癇 +痴癡 +瘅癉 +瘆瘮 +瘗瘞 +瘘瘻 +瘪癟 +瘫癱 +瘾癮 +瘿癭 +癞癩 +癣癬 +癫癲 +皂皁 +皑皚 +皱皺 +皲皸 +盏盞 +盐鹽 +监監 +盖蓋 +盗盜 +盘盤 +眍瞘 +眦眥 +眬矓 +睁睜 +睐睞 +睑瞼 +瞆瞶 +瞒瞞 +瞩矚 +矩矩 +矫矯 +矶磯 +矾礬 +矿礦 +砀碭 +码碼 +砖磚 +砗硨 +砚硯 +砜碸 +砺礪 +砻礱 +砾礫 +础礎 +硁硜 +硕碩 +硖硤 +硗磽 +硙磑 +硚礄 +确確 +硵磠 +硷礆 +碍礙 +碛磧 +碜磣 +碱鹼 +礼禮 +祃禡 +祎禕 +祢禰 +祯禎 +祷禱 +祸禍 +禀稟 +禄祿 +禅禪 +离離 +私私 +秃禿 +秆稈 +秋秋 +种種 +秘祕 +积積 +称稱 +秽穢 +秾穠 +稆穭 +税稅 +稣穌 +稳穩 +穑穡 +穞穭 +穷窮 +窃竊 +窍竅 +窎窵 +窑窯 +窜竄 +窝窩 +窥窺 +窦竇 +窭窶 +竖豎 +竞競 +笃篤 +笋筍 +笔筆 +笕筧 +笺箋 +笼籠 +笾籩 +筑築 +筚篳 +筛篩 +筜簹 +筝箏 +筹籌 +筼篔 +签籤 +筿篠 +简簡 +箓籙 +箦簀 +箧篋 +箨籜 +箩籮 +箪簞 +箫簫 +篑簣 +篓簍 +篮籃 +篯籛 +篱籬 +簖籪 +籁籟 +籴糴 +类類 +籼秈 +粜糶 +粝糲 +粤粵 +粪糞 +粮糧 +粽糉 +糁糝 +糇餱 +糍餈 +系系 +紧緊 +絷縶 +緼縕 +縆緪 +纟糹 +纠糾 +纡紆 +红紅 +纣紂 +纤纖 +纥紇 +约約 +级級 +纨紈 +纩纊 +纪紀 +纫紉 +纬緯 +纭紜 +纮紘 +纯純 +纰紕 +纱紗 +纲綱 +纳納 +纴紝 +纵縱 +纶綸 +纷紛 +纸紙 +纹紋 +纺紡 +纻紵 +纼紖 +纽紐 +纾紓 +线線 +绀紺 +绁紲 +绂紱 +练練 +组組 +绅紳 +细細 +织織 +终終 +绉縐 +绊絆 +绋紼 +绌絀 +绍紹 +绎繹 +经經 +绐紿 +绑綁 +绒絨 +结結 +绔絝 +绕繞 +绖絰 +绗絎 +绘繪 +给給 +绚絢 +绛絳 +络絡 +绝絕 +绞絞 +统統 +绠綆 +绡綃 +绢絹 +绣繡 +绤綌 +绥綏 +绦絛 +继繼 +绨綈 +绩績 +绪緒 +绫綾 +绬緓 +续續 +绮綺 +绯緋 +绰綽 +绱鞝 +绲緄 +绳繩 +维維 +绵綿 +绶綬 +绷繃 +绸綢 +绹綯 +绺綹 +绻綣 +综綜 +绽綻 +绾綰 +绿綠 +缀綴 +缁緇 +缂緙 +缃緗 +缄緘 +缅緬 +缆纜 +缇緹 +缈緲 +缉緝 +缊縕 +缋繢 +缌緦 +缍綞 +缎緞 +缏緶 +缐線 +缑緱 +缒縋 +缓緩 +缔締 +缕縷 +编編 +缗緡 +缘緣 +缙縉 +缚縛 +缛縟 +缜縝 +缝縫 +缞縗 +缟縞 +缠纏 +缡縭 +缢縊 +缣縑 +缤繽 +缥縹 +缦縵 +缧縲 +缨纓 +缩縮 +缪繆 +缫繅 +缬纈 +缭繚 +缮繕 +缯繒 +缰繮 +缱繾 +缲繰 +缳繯 +缴繳 +缵纘 +罂罌 +网網 +罗羅 +罚罰 +罢罷 +罴羆 +羁羈 +羟羥 +羡羨 +群羣 +翘翹 +翙翽 +翚翬 +耢耮 +耧耬 +耸聳 +耻恥 +聂聶 +聋聾 +职職 +聍聹 +联聯 +聩聵 +聪聰 +肃肅 +肠腸 +肤膚 +肮骯 +肴餚 +肾腎 +肿腫 +胀脹 +胁脅 +胄胄 +胆膽 +背背 +胜勝 +胡胡 +胧朧 +胨腖 +胪臚 +胫脛 +胶膠 +脉脈 +脍膾 +脏髒 +脐臍 +脑腦 +脓膿 +脔臠 +脚腳 +脱脫 +脶腡 +脸臉 +腊臘 +腌醃 +腘膕 +腭齶 +腻膩 +腼靦 +腽膃 +腾騰 +膑臏 +膻羶 +臜臢 +致致 +舆輿 +舍舍 +舣艤 +舰艦 +舱艙 +舻艫 +艰艱 +艳豔 +艺藝 +节節 +芈羋 +芗薌 +芜蕪 +芦蘆 +芸芸 +苁蓯 +苇葦 +苈藶 +苋莧 +苌萇 +苍蒼 +苎苧 +苏蘇 +苔苔 +苧薴 +苹蘋 +范範 +茎莖 +茏蘢 +茑蔦 +茔塋 +茕煢 +茧繭 +荆荊 +荐薦 +荙薘 +荚莢 +荛蕘 +荜蓽 +荝萴 +荞蕎 +荟薈 +荠薺 +荡蕩 +荣榮 +荤葷 +荥滎 +荦犖 +荧熒 +荨蕁 +荩藎 +荪蓀 +荫蔭 +荬蕒 +荭葒 +荮葤 +药藥 +莅蒞 +莱萊 +莲蓮 +莳蒔 +莴萵 +莶薟 +获獲 +莸蕕 +莹瑩 +莺鶯 +莼蓴 +萚蘀 +萝蘿 +萤螢 +营營 +萦縈 +萧蕭 +萨薩 +葱蔥 +蒀蒕 +蒇蕆 +蒉蕢 +蒋蔣 +蒌蔞 +蒏醟 +蒙蒙 +蓝藍 +蓟薊 +蓠蘺 +蓣蕷 +蓥鎣 +蓦驀 +蔂虆 +蔑蔑 +蔷薔 +蔹蘞 +蔺藺 +蔼藹 +蕰薀 +蕲蘄 +蕴蘊 +薮藪 +藓蘚 +藴蘊 +蘖櫱 +虏虜 +虑慮 +虚虛 +虫蟲 +虬虯 +虮蟣 +虱蝨 +虽雖 +虾蝦 +虿蠆 +蚀蝕 +蚁蟻 +蚂螞 +蚃蠁 +蚕蠶 +蚝蠔 +蚬蜆 +蛊蠱 +蛎蠣 +蛏蟶 +蛮蠻 +蛰蟄 +蛱蛺 +蛲蟯 +蛳螄 +蛴蠐 +蜕蛻 +蜗蝸 +蜡蠟 +蝇蠅 +蝈蟈 +蝉蟬 +蝎蠍 +蝼螻 +蝾蠑 +螀螿 +螨蟎 +蟏蠨 +衅釁 +衔銜 +补補 +表表 +衬襯 +衮袞 +袄襖 +袅嫋 +袆褘 +袜襪 +袭襲 +袯襏 +装裝 +裆襠 +裈褌 +裢褳 +裣襝 +裤褲 +裥襉 +褛褸 +褴襤 +襕襴 +见見 +观觀 +觃覎 +规規 +觅覓 +视視 +觇覘 +览覽 +觉覺 +觊覬 +觋覡 +觌覿 +觍覥 +觎覦 +觏覯 +觐覲 +觑覷 +觞觴 +触觸 +觯觶 +訚誾 +詟讋 +誉譽 +誊謄 +讠訁 +计計 +订訂 +讣訃 +认認 +讥譏 +讦訐 +讧訌 +讨討 +让讓 +讪訕 +讫訖 +讬託 +训訓 +议議 +讯訊 +记記 +讱訒 +讲講 +讳諱 +讴謳 +讵詎 +讶訝 +讷訥 +许許 +讹訛 +论論 +讻訩 +讼訟 +讽諷 +设設 +访訪 +诀訣 +证證 +诂詁 +诃訶 +评評 +诅詛 +识識 +诇詗 +诈詐 +诉訴 +诊診 +诋詆 +诌謅 +词詞 +诎詘 +诏詔 +诐詖 +译譯 +诒詒 +诓誆 +诔誄 +试試 +诖詿 +诗詩 +诘詰 +诙詼 +诚誠 +诛誅 +诜詵 +话話 +诞誕 +诟詬 +诠詮 +诡詭 +询詢 +诣詣 +诤諍 +该該 +详詳 +诧詫 +诨諢 +诩詡 +诪譸 +诫誡 +诬誣 +语語 +诮誚 +误誤 +诰誥 +诱誘 +诲誨 +诳誑 +说說 +诵誦 +诶誒 +请請 +诸諸 +诹諏 +诺諾 +读讀 +诼諑 +诽誹 +课課 +诿諉 +谀諛 +谁誰 +谂諗 +调調 +谄諂 +谅諒 +谆諄 +谇誶 +谈談 +谉讅 +谊誼 +谋謀 +谌諶 +谍諜 +谎謊 +谏諫 +谐諧 +谑謔 +谒謁 +谓謂 +谔諤 +谕諭 +谖諼 +谗讒 +谘諮 +谙諳 +谚諺 +谛諦 +谜謎 +谝諞 +谞諝 +谟謨 +谠讜 +谡謖 +谢謝 +谣謠 +谤謗 +谥諡 +谦謙 +谧謐 +谨謹 +谩謾 +谪謫 +谫譾 +谬謬 +谭譚 +谮譖 +谯譙 +谰讕 +谱譜 +谲譎 +谳讞 +谴譴 +谵譫 +谶讖 +谷谷 +豮豶 +贝貝 +贞貞 +负負 +贠貟 +贡貢 +财財 +责責 +贤賢 +败敗 +账賬 +货貨 +质質 +贩販 +贪貪 +贫貧 +贬貶 +购購 +贮貯 +贯貫 +贰貳 +贱賤 +贲賁 +贳貰 +贴貼 +贵貴 +贶貺 +贷貸 +贸貿 +费費 +贺賀 +贻貽 +贼賊 +贽贄 +贾賈 +贿賄 +赀貲 +赁賃 +赂賂 +赃贓 +资資 +赅賅 +赆贐 +赇賕 +赈賑 +赉賚 +赊賒 +赋賦 +赌賭 +赍齎 +赎贖 +赏賞 +赐賜 +赑贔 +赒賙 +赓賡 +赔賠 +赕賧 +赖賴 +赗賵 +赘贅 +赙賻 +赚賺 +赛賽 +赜賾 +赝贗 +赞贊 +赟贇 +赠贈 +赡贍 +赢贏 +赣贛 +赪赬 +赵趙 +赶趕 +趋趨 +趱趲 +趸躉 +跃躍 +跄蹌 +跖蹠 +跞躒 +践踐 +跶躂 +跷蹺 +跸蹕 +跹躚 +跻躋 +踌躊 +踪蹤 +踬躓 +踯躑 +蹑躡 +蹒蹣 +蹰躕 +蹿躥 +躏躪 +躜躦 +躯軀 +輼轀 +车車 +轧軋 +轨軌 +轩軒 +轪軑 +轫軔 +转轉 +轭軛 +轮輪 +软軟 +轰轟 +轱軲 +轲軻 +轳轤 +轴軸 +轵軹 +轶軼 +轷軤 +轸軫 +轹轢 +轺軺 +轻輕 +轼軾 +载載 +轾輊 +轿轎 +辀輈 +辁輇 +辂輅 +较較 +辄輒 +辅輔 +辆輛 +辇輦 +辈輩 +辉輝 +辊輥 +辋輞 +辌輬 +辍輟 +辎輜 +辏輳 +辐輻 +辑輯 +辒轀 +输輸 +辔轡 +辕轅 +辖轄 +辗輾 +辘轆 +辙轍 +辚轔 +辞辭 +辟闢 +辩辯 +辫辮 +边邊 +辽遼 +达達 +迁遷 +过過 +迈邁 +运運 +还還 +这這 +进進 +远遠 +违違 +连連 +迟遲 +迩邇 +迳逕 +迹跡 +适適 +选選 +逊遜 +递遞 +逦邐 +逻邏 +遗遺 +遥遙 +邓鄧 +邝鄺 +邬鄔 +邮郵 +邹鄒 +邺鄴 +邻鄰 +郁鬱 +郏郟 +郐鄶 +郑鄭 +郓鄆 +郦酈 +郧鄖 +郸鄲 +酂酇 +酝醞 +酦醱 +酱醬 +酸酸 +酽釅 +酾釃 +酿釀 +醖醞 +采採 +释釋 +里裏 +鉴鑑 +銮鑾 +錾鏨 +钅釒 +钆釓 +钇釔 +针針 +钉釘 +钊釗 +钋釙 +钌釕 +钍釷 +钎釺 +钏釧 +钐釤 +钑鈒 +钒釩 +钓釣 +钔鍆 +钕釹 +钖鍚 +钗釵 +钘鈃 +钙鈣 +钚鈈 +钛鈦 +钜鉅 +钝鈍 +钞鈔 +钟鍾 +钠鈉 +钡鋇 +钢鋼 +钣鈑 +钤鈐 +钥鑰 +钦欽 +钧鈞 +钨鎢 +钩鉤 +钪鈧 +钫鈁 +钬鈥 +钭鈄 +钮鈕 +钯鈀 +钰鈺 +钱錢 +钲鉦 +钳鉗 +钴鈷 +钵鉢 +钶鈳 +钷鉕 +钸鈽 +钹鈸 +钺鉞 +钻鑽 +钼鉬 +钽鉭 +钾鉀 +钿鈿 +铀鈾 +铁鐵 +铂鉑 +铃鈴 +铄鑠 +铅鉛 +铆鉚 +铇鉋 +铈鈰 +铉鉉 +铊鉈 +铋鉍 +铌鈮 +铍鈹 +铎鐸 +铏鉶 +铐銬 +铑銠 +铒鉺 +铓鋩 +铔錏 +铕銪 +铖鋮 +铗鋏 +铘鋣 +铙鐃 +铚銍 +铛鐺 +铜銅 +铝鋁 +铞銱 +铟銦 +铠鎧 +铡鍘 +铢銖 +铣銑 +铤鋌 +铥銩 +铦銛 +铧鏵 +铨銓 +铩鎩 +铪鉿 +铫銚 +铬鉻 +铭銘 +铮錚 +铯銫 +铰鉸 +铱銥 +铲鏟 +铳銃 +铴鐋 +铵銨 +银銀 +铷銣 +铸鑄 +铹鐒 +铺鋪 +铻鋙 +铼錸 +铽鋱 +链鏈 +铿鏗 +销銷 +锁鎖 +锂鋰 +锃鋥 +锄鋤 +锅鍋 +锆鋯 +锇鋨 +锈鏽 +锉銼 +锊鋝 +锋鋒 +锌鋅 +锍鋶 +锎鐦 +锏鐧 +锐銳 +锑銻 +锒鋃 +锓鋟 +锔鋦 +锕錒 +锖錆 +锗鍺 +锘鍩 +错錯 +锚錨 +锛錛 +锜錡 +锝鍀 +锞錁 +锟錕 +锠錩 +锡錫 +锢錮 +锣鑼 +锤錘 +锥錐 +锦錦 +锧鑕 +锨鍁 +锩錈 +锪鍃 +锫錇 +锬錟 +锭錠 +键鍵 +锯鋸 +锰錳 +锱錙 +锲鍥 +锳鍈 +锴鍇 +锵鏘 +锶鍶 +锷鍔 +锸鍤 +锹鍬 +锺鍾 +锻鍛 +锼鎪 +锽鍠 +锾鍰 +锿鎄 +镀鍍 +镁鎂 +镂鏤 +镃鎡 +镄鐨 +镅鎇 +镆鏌 +镇鎮 +镈鎛 +镉鎘 +镊鑷 +镋钂 +镌鐫 +镍鎳 +镎鎿 +镏鎦 +镐鎬 +镑鎊 +镒鎰 +镓鎵 +镔鑌 +镕鎔 +镖鏢 +镗鏜 +镘鏝 +镙鏍 +镚鏰 +镛鏞 +镜鏡 +镝鏑 +镞鏃 +镟鏇 +镠鏐 +镡鐔 +镢钁 +镣鐐 +镤鏷 +镥鑥 +镦鐓 +镧鑭 +镨鐠 +镩鑹 +镪鏹 +镫鐙 +镬鑊 +镭鐳 +镮鐶 +镯鐲 +镰鐮 +镱鐿 +镲鑔 +镳鑣 +镴鑞 +镵鑱 +镶鑲 +长長 +门門 +闩閂 +闪閃 +闫閆 +闬閈 +闭閉 +问問 +闯闖 +闰閏 +闱闈 +闲閒 +闳閎 +间間 +闵閔 +闶閌 +闷悶 +闸閘 +闹鬧 +闺閨 +闻聞 +闼闥 +闽閩 +闾閭 +闿闓 +阀閥 +阁閣 +阂閡 +阃閫 +阄鬮 +阅閱 +阆閬 +阇闍 +阈閾 +阉閹 +阊閶 +阋鬩 +阌閿 +阍閽 +阎閻 +阏閼 +阐闡 +阑闌 +阒闃 +阓闠 +阔闊 +阕闋 +阖闔 +阗闐 +阘闒 +阙闕 +阚闞 +阛闤 +队隊 +阳陽 +阴陰 +阵陣 +阶階 +际際 +陆陸 +陇隴 +陈陳 +陉陘 +陕陝 +陦隯 +陧隉 +陨隕 +险險 +随隨 +隐隱 +隶隸 +隽雋 +难難 +雇僱 +雏雛 +雕雕 +雠讎 +雳靂 +雾霧 +霁霽 +霉黴 +霡霢 +霭靄 +靓靚 +靔靝 +静靜 +面面 +靥靨 +鞑韃 +鞒鞽 +鞯韉 +鞲韝 +韦韋 +韧韌 +韨韍 +韩韓 +韪韙 +韫韞 +韬韜 +韵韻 +页頁 +顶頂 +顷頃 +顸頇 +项項 +顺順 +须須 +顼頊 +顽頑 +顾顧 +顿頓 +颀頎 +颁頒 +颂頌 +颃頏 +预預 +颅顱 +领領 +颇頗 +颈頸 +颉頡 +颊頰 +颋頲 +颌頜 +颍潁 +颎熲 +颏頦 +颐頤 +频頻 +颒頮 +颓頹 +颔頷 +颕頴 +颖穎 +颗顆 +题題 +颙顒 +颚顎 +颛顓 +颜顏 +额額 +颞顳 +颟顢 +颠顛 +颡顙 +颢顥 +颣纇 +颤顫 +颥顬 +颦顰 +颧顴 +风風 +飏颺 +飐颭 +飑颮 +飒颯 +飓颶 +飔颸 +飕颼 +飖颻 +飗飀 +飘飄 +飙飆 +飚飈 +飞飛 +飨饗 +餍饜 +饣飠 +饤飣 +饥飢 +饦飥 +饧餳 +饨飩 +饩餼 +饪飪 +饫飫 +饬飭 +饭飯 +饮飲 +饯餞 +饰飾 +饱飽 +饲飼 +饳飿 +饴飴 +饵餌 +饶饒 +饷餉 +饸餄 +饹餎 +饺餃 +饻餏 +饼餅 +饽餑 +饾餖 +饿餓 +馀餘 +馁餒 +馂餕 +馃餜 +馄餛 +馅餡 +馆館 +馇餷 +馈饋 +馉餶 +馊餿 +馋饞 +馌饁 +馍饃 +馎餺 +馏餾 +馐饈 +馑饉 +馒饅 +馓饊 +馔饌 +馕饢 +马馬 +驭馭 +驮馱 +驯馴 +驰馳 +驱驅 +驲馹 +驳駁 +驴驢 +驵駔 +驶駛 +驷駟 +驸駙 +驹駒 +驺騶 +驻駐 +驼駝 +驽駑 +驾駕 +驿驛 +骀駘 +骁驍 +骂罵 +骃駰 +骄驕 +骅驊 +骆駱 +骇駭 +骈駢 +骉驫 +骊驪 +骋騁 +验驗 +骍騂 +骎駸 +骏駿 +骐騏 +骑騎 +骒騍 +骓騅 +骔騌 +骕驌 +骖驂 +骗騙 +骘騭 +骙騤 +骚騷 +骛騖 +骜驁 +骝騮 +骞騫 +骟騸 +骠驃 +骡騾 +骢驄 +骣驏 +骤驟 +骥驥 +骦驦 +骧驤 +髅髏 +髋髖 +髌髕 +鬓鬢 +鬶鬹 +魇魘 +魉魎 +鱼魚 +鱽魛 +鱾魢 +鱿魷 +鲀魨 +鲁魯 +鲂魴 +鲃䰾 +鲄魺 +鲅鮁 +鲆鮃 +鲇鮎 +鲈鱸 +鲉鮋 +鲊鮓 +鲋鮒 +鲌鮊 +鲍鮑 +鲎鱟 +鲏鮍 +鲐鮐 +鲑鮭 +鲒鮚 +鲓鮳 +鲔鮪 +鲕鮞 +鲖鮦 +鲗鰂 +鲘鮜 +鲙鱠 +鲚鱭 +鲛鮫 +鲜鮮 +鲝鮺 +鲞鯗 +鲟鱘 +鲠鯁 +鲡鱺 +鲢鰱 +鲣鰹 +鲤鯉 +鲥鰣 +鲦鰷 +鲧鯀 +鲨鯊 +鲩鯇 +鲪鮶 +鲫鯽 +鲬鯒 +鲭鯖 +鲮鯪 +鲯鯕 +鲰鯫 +鲱鯡 +鲲鯤 +鲳鯧 +鲴鯝 +鲵鯢 +鲶鯰 +鲷鯛 +鲸鯨 +鲹鰺 +鲺鯴 +鲻鯔 +鲼鱝 +鲽鰈 +鲾鰏 +鲿鱨 +鳀鯷 +鳁鰮 +鳂鰃 +鳃鰓 +鳄鱷 +鳅鰍 +鳆鰒 +鳇鰉 +鳈鰁 +鳉鱂 +鳊鯿 +鳋鰠 +鳌鰲 +鳍鰭 +鳎鰨 +鳏鰥 +鳐鰩 +鳑鰟 +鳒鰜 +鳓鰳 +鳔鰾 +鳕鱈 +鳖鱉 +鳗鰻 +鳘鰵 +鳙鱅 +鳚䲁 +鳛鰼 +鳜鱖 +鳝鱔 +鳞鱗 +鳟鱒 +鳠鱯 +鳡鱤 +鳢鱧 +鳣鱣 +鳤䲘 +鸟鳥 +鸠鳩 +鸡雞 +鸢鳶 +鸣鳴 +鸤鳲 +鸥鷗 +鸦鴉 +鸧鶬 +鸨鴇 +鸩鴆 +鸪鴣 +鸫鶇 +鸬鸕 +鸭鴨 +鸮鴞 +鸯鴦 +鸰鴒 +鸱鴟 +鸲鴝 +鸳鴛 +鸴鷽 +鸵鴕 +鸶鷥 +鸷鷙 +鸸鴯 +鸹鴰 +鸺鵂 +鸻鴴 +鸼鵃 +鸽鴿 +鸾鸞 +鸿鴻 +鹀鵐 +鹁鵓 +鹂鸝 +鹃鵑 +鹄鵠 +鹅鵝 +鹆鵒 +鹇鷳 +鹈鵜 +鹉鵡 +鹊鵲 +鹋鶓 +鹌鵪 +鹍鵾 +鹎鵯 +鹏鵬 +鹐鵮 +鹑鶉 +鹒鶊 +鹓鵷 +鹔鷫 +鹕鶘 +鹖鶡 +鹗鶚 +鹘鶻 +鹙鶖 +鹚鷀 +鹛鶥 +鹜鶩 +鹝鷊 +鹞鷂 +鹟鶲 +鹠鶹 +鹡鶺 +鹢鷁 +鹣鶼 +鹤鶴 +鹥鷖 +鹦鸚 +鹧鷓 +鹨鷚 +鹩鷯 +鹪鷦 +鹫鷲 +鹬鷸 +鹭鷺 +鹮䴉 +鹯鸇 +鹰鷹 +鹱鸌 +鹲鸏 +鹳鸛 +鹴鸘 +鹾鹺 +麦麥 +麸麩 +麹麴 +麺麪 +麽麼 +黄黃 +黉黌 +黡黶 +黩黷 +黪黲 +黾黽 +鼋黿 +鼌鼂 +鼍鼉 +鼹鼴 +齐齊 +齑齏 +齿齒 +龀齔 +龁齕 +龂齗 +龃齟 +龄齡 +龅齙 +龆齠 +龇齜 +龈齦 +龉齬 +龊齪 +龋齲 +龌齷 +龙龍 +龚龔 +龛龕 +龟龜 +鿎䃮 +鿏䥑 +鿒鿓 +鿔鎶 +𠀾𠁞 +𠆲儣 +𠆿𠌥 +𠇹俓 +𠉂㒓 +𠉗𠏢 +𠋆儭 +𠚳𠠎 +𠛅剾 +𠛆𠞆 +𠛾𪟖 +𠡠勑 +𠮶嗰 +𠯟哯 +𠯠噅 +𠰱㘉 +𠰷嚧 +𠱞囃 +𠲥𡅏 +𠴛𡃕 +𠴢𡄔 +𠵸𡄣 +𠵾㗲 +𡋀𡓾 +𡋗𡑭 +𡋤壗 +𡍣𡔖 +𡒄壈 +𡝠㜷 +𡞋㜗 +𡞱㜢 +𡠟孎 +𡥧孻 +𡭜𡮉 +𡭬𡮣 +𡳃𡳳 +𡳒𦘧 +𡶴嵼 +𡸃𡽗 +𡺃嶈 +𡺄嶘 +𢋈㢝 +𢗓㦛 +𢘙𢤱 +𢘝𢣚 +𢘞𢣭 +𢙏愻 +𢙐憹 +𢙑𢠼 +𢙒憢 +𢙓懀 +𢛯㦎 +𢠁懎 +𢢐𤢻 +𢧐戰 +𢫊𢷮 +𢫞𢶫 +𢫬摋 +𢬍擫 +𢬦𢹿 +𢭏擣 +𢽾斅 +𣃁斸 +𣆐曥 +𣈣𣋋 +𣍨𦢈 +𣍯腪 +𣍰脥 +𣎑臗 +𣏢槫 +𣐕桱 +𣐤欍 +𣑶𣠲 +𣒌楇 +𣓿橯 +𣔌樤 +𣗊樠 +𣗋欓 +𣗙㰙 +𣘐㯤 +𣘓𣞻 +𣘴檭 +𣘷𣝕 +𣚚欘 +𣞎𣠩 +𣨼殢 +𣭤𣯴 +𣯣𣯩 +𣱝氭 +𣲗湋 +𣲘潕 +𣳆㵗 +𣶩澅 +𣶫𣿉 +𣶭𪷓 +𣷷𤅶 +𣸣濆 +𣺼灙 +𣺽𤁣 +𣽷瀃 +𤆡熓 +𤆢㷍 +𤇃爄 +𤇄熌 +𤇭爖 +𤇹熚 +𤈶熉 +𤈷㷿 +𤊀𤒎 +𤊰𤓩 +𤋏熡 +𤎺𤓎 +𤎻𤑳 +𤙯𤛮 +𤝢𤢟 +𤞃獩 +𤞤玁 +𤠋㺏 +𤦀瓕 +𤩽瓛 +𤳄𤳸 +𤶊癐 +𤶧𤸫 +𤻊㿗 +𤽯㿧 +𤾀皟 +𤿲麬 +𥁢䀉 +𥅘𥌃 +𥅴䀹 +𥅿𥊝 +𥆧瞤 +𥇢䁪 +𥎝䂎 +𥐟礒 +𥐯𥖅 +𥐰𥕥 +𥐻碙 +𥞦𥞵 +𥧂𥨐 +𥩟竚 +𥩺𥪂 +𥫣籅 +𥬀䉙 +𥬞籋 +𥬠篘 +𥭉𥵊 +𥮋𥸠 +𥮜䉲 +𥮾篸 +𥱔𥵃 +𥹥𥼽 +𥺅䊭 +𥺇𥽖 +𦈈𥿊 +𦈉緷 +𦈋綇 +𦈌綀 +𦈎繟 +𦈏緍 +𦈐縺 +𦈑緸 +𦈒𦂅 +𦈓䋿 +𦈔縎 +𦈕緰 +𦈖䌈 +𦈗𦃄 +𦈘䌋 +𦈙䌰 +𦈚縬 +𦈛繓 +𦈜䌖 +𦈝繏 +𦈞䌟 +𦈟䌝 +𦈠䌥 +𦈡繻 +𦍠䍽 +𦛨朥 +𦝼膢 +𦟗𦣎 +𦨩𦪽 +𦰏蓧 +𦰴䕳 +𦶟爇 +𦶻𦾟 +𦻕蘟 +𧉐𧕟 +𧉞䗿 +𧌥𧎈 +𧏖蠙 +𧏗蠀 +𧑏蠾 +𧒭𧔥 +𧜭䙱 +𧝝襰 +𧝧𧟀 +𧮪詀 +𧳕𧳟 +𧹑䞈 +𧹒買 +𧹓𧶔 +𧹔賬 +𧹕䝻 +𧹖賟 +𧹗贃 +𧿈𨇁 +𨀁躘 +𨀱𨄣 +𨁴𨅍 +𨂺𨈊 +𨄄𨈌 +𨅛䠱 +𨅫𨇞 +𨅬躝 +𨉗軉 +𨐅軗 +𨐆𨊻 +𨐇𨏠 +𨐈輄 +𨐉𨎮 +𨐊𨏥 +𨑹䢨 +𨟳𨣞 +𨠨𨣧 +𨡙𨢿 +𨡺𨣈 +𨤰𨤻 +𨰾鎷 +𨰿釳 +𨱀𨥛 +𨱁鈠 +𨱂鈋 +𨱃鈲 +𨱄鈯 +𨱅鉁 +𨱆龯 +𨱇銶 +𨱈鋉 +𨱉鍄 +𨱊𨧱 +𨱋錂 +𨱌鏆 +𨱍鎯 +𨱎鍮 +𨱏鎝 +𨱐𨫒 +𨱑鐄 +𨱒鏉 +𨱓鐎 +𨱔鐏 +𨱕𨮂 +𨱖䥩 +𨷿䦳 +𨸀𨳕 +𨸁𨳑 +𨸂閍 +𨸃閐 +𨸄䦘 +𨸅𨴗 +𨸆𨵩 +𨸇𨵸 +𨸉𨶀 +𨸊𨶏 +𨸋𨶲 +𨸌𨶮 +𨸎𨷲 +𨸘𨽏 +𨸟䧢 +𩏼䪏 +𩏽𩏪 +𩏾𩎢 +𩏿䪘 +𩐀䪗 +𩓋顂 +𩖕𩓣 +𩖖顃 +𩖗䫴 +𩙥颰 +𩙦𩗀 +𩙧䬞 +𩙨𩘹 +𩙩𩘀 +𩙪颷 +𩙫颾 +𩙬𩘺 +𩙭𩘝 +𩙮䬘 +𩙯䬝 +𩙰𩙈 +𩟿𩚛 +𩠀𩚥 +𩠁𩚵 +𩠂𩛆 +𩠃𩛩 +𩠅𩟐 +𩠆𩜦 +𩠇䭀 +𩠈䭃 +𩠉𩜇 +𩠊𩜵 +𩠋𩝔 +𩠌餸 +𩠎𩞄 +𩠏𩞦 +𩠠𩠴 +𩡖𩡣 +𩧦𩡺 +𩧨駎 +𩧩𩤊 +𩧪䮾 +𩧫駚 +𩧬𩢡 +𩧭䭿 +𩧮𩢾 +𩧯驋 +𩧰䮝 +𩧱𩥉 +𩧲駧 +𩧳𩢸 +𩧴駩 +𩧵𩢴 +𩧶𩣏 +𩧸𩣫 +𩧺駶 +𩧻𩣵 +𩧼𩣺 +𩧿䮠 +𩨀騔 +𩨁䮞 +𩨂驄 +𩨃騝 +𩨄騪 +𩨅𩤸 +𩨆𩤙 +𩨇䮫 +𩨈騟 +𩨉𩤲 +𩨊騚 +𩨋𩥄 +𩨌𩥑 +𩨍𩥇 +𩨎龭 +𩨏䮳 +𩨐𩧆 +𩩈䯤 +𩬣𩭙 +𩬤𩰀 +𩭹鬖 +𩯒𩯳 +𩰰𩰹 +𩲒𩳤 +𩴌𩴵 +𩽹魥 +𩽺𩵩 +𩽻𩵹 +𩽼鯶 +𩽽𩶱 +𩽾鮟 +𩽿𩶰 +𩾁鯄 +𩾂䲖 +𩾃鮸 +𩾄𩷰 +𩾅𩸃 +𩾆𩸦 +𩾇鯱 +𩾈䱙 +𩾊䱬 +𩾋䱰 +𩾌鱇 +𩾎𩽇 +𪉂䲰 +𪉃鳼 +𪉄𩿪 +𪉅𪀦 +𪉆鴲 +𪉈鴜 +𪉉𪁈 +𪉊鷨 +𪉋𪀾 +𪉌𪁖 +𪉍鵚 +𪉎𪂆 +𪉏𪃏 +𪉐𪃍 +𪉑鷔 +𪉒𪄕 +𪉔𪄆 +𪉕𪇳 +𪎈䴬 +𪎉麲 +𪎊麨 +𪎋䴴 +𪎌麳 +𪑅䵳 +𪔭𪔵 +𪚏𪘀 +𪚐𪘯 +𪜎𠿕 +𪞝凙 +𪟎㔋 +𪟝勣 +𪠀𧷎 +𪠟㓄 +𪠡𠬙 +𪠳唓 +𪠵㖮 +𪠸嚛 +𪠺𠽃 +𪠽噹 +𪡀嘺 +𪡃嘪 +𪡋噞 +𪡏嗹 +𪡛㗿 +𪡞嘳 +𪡺𡃄 +𪢌㘓 +𪢐𡃤 +𪢒𡂡 +𪢕嚽 +𪢖𡅯 +𪢠囒 +𪢮圞 +𪢸墲 +𪣆埬 +𪣒堚 +𪣻塿 +𪤄𡓁 +𪤚壣 +𪥠𧹈 +𪥫孇 +𪥰嬣 +𪥿嬻 +𪧀孾 +𪧘寠 +𪨊㞞 +𪨗屩 +𪨧崙 +𪨩𡸗 +𪨶輋 +𪨷巗 +𪨹𡹬 +𪩇㟺 +𪩎巊 +𪩘巘 +𪩛𡿖 +𪩷幝 +𪩸幩 +𪪏廬 +𪪑㢗 +𪪞廧 +𪪴𢍰 +𪪼彃 +𪫌徿 +𪫡𢤩 +𪫷㦞 +𪫺憸 +𪬚𢣐 +𪬯𢤿 +𪭝𢯷 +𪭢摐 +𪭧擟 +𪭯𢶒 +𪭵掚 +𪭾撊 +𪮃㨻 +𪮋㩋 +𪮖撧 +𪮳𢺳 +𪮶攋 +𪯋㪎 +𪰶曊 +𪱥膹 +𪱷梖 +𪲎櫅 +𪲔欐 +𪲛檵 +𪲮櫠 +𪳍欇 +𪳗𣜬 +𪴙欑 +𪵑毊 +𪵣霼 +𪵱濿 +𪶄溡 +𪶒𤄷 +𪶮𣽏 +𪷍㵾 +𪷽灒 +𪸕熂 +𪸩煇 +𪹀𤑹 +𪹠𤓌 +𪹳爥 +𪹹𤒻 +𪺣𤘀 +𪺪𤜆 +𪺭犞 +𪺷獊 +𪺸𤠮 +𪺻㺜 +𪺽猌 +𪻐瑽 +𪻨瓄 +𪻲瑻 +𪻺璝 +𪼋㻶 +𪼴𤬅 +𪽈畼 +𪽝𤳷 +𪽪痮 +𪽭𤷃 +𪽮㿖 +𪽴𤺔 +𪽷瘱 +𪾔盨 +𪾢睍 +𪾣眝 +𪾦矑 +𪾸矉 +𪿊𥏝 +𪿞𥖲 +𪿫礮 +𪿵𥗇 +𫀌𥜰 +𫀓𥜐 +𫀨䅐 +𫀬䅳 +𫀮𥢷 +𫁂䆉 +𫁟竱 +𫁡鴗 +𫁱𥶽 +𫁲䉑 +𫁳𥯤 +𫁷䉶 +𫁺𥴼 +𫂃簢 +𫂆簂 +𫂈䉬 +𫂖𥴨 +𫂿𥻦 +𫃗𩏷 +𫄙糺 +𫄚䊺 +𫄛紟 +𫄜䋃 +𫄝𥾯 +𫄞䋔 +𫄟絁 +𫄠絙 +𫄡絧 +𫄢絥 +𫄣繷 +𫄤繨 +𫄥纚 +𫄦𦀖 +𫄧綖 +𫄨絺 +𫄩䋦 +𫄪𦅇 +𫄫綟 +𫄬緤 +𫄭緮 +𫄮䋼 +𫄯𦃩 +𫄰縍 +𫄱繬 +𫄲縸 +𫄳縰 +𫄴繂 +𫄵𦅈 +𫄶繈 +𫄷繶 +𫄸纁 +𫄹纗 +𫅅䍤 +𫅗羵 +𫅥𦒀 +𫅭䎙 +𫅼𦔖 +𫆏聻 +𫆝𦟼 +𫆫𦡝 +𫇘𦧺 +𫇛艣 +𫇪𦱌 +𫇭蔿 +𫇴蒭 +𫇽蕽 +𫈉蕳 +𫈎葝 +𫈟蔯 +𫈵蕝 +𫉁薆 +𫉄藷 +𫊪䗅 +𫊮蠦 +𫊸蟜 +𫊹𧒯 +𫊻蟳 +𫋇蟂 +𫋌蟘 +𫋲䙔 +𫋷襗 +𫋹襓 +𫋻襘 +𫌀襀 +𫌇襵 +𫌋𧞫 +𫌨覼 +𫌪覛 +𫌫𧡴 +𫌬𧢄 +𫌭覹 +𫌯䚩 +𫍐𧭹 +𫍙訑 +𫍚訞 +𫍛訜 +𫍜詓 +𫍝諫 +𫍞𧦝 +𫍟𧦧 +𫍠䛄 +𫍡詑 +𫍢譊 +𫍣詷 +𫍤譑 +𫍥誂 +𫍦譨 +𫍧誺 +𫍨誫 +𫍩諣 +𫍪誋 +𫍫䛳 +𫍬誷 +𫍭𧩕 +𫍮誳 +𫍯諴 +𫍰諰 +𫍱諯 +𫍲謏 +𫍳諥 +𫍴謱 +𫍵謸 +𫍶𧩼 +𫍷謉 +𫍸謆 +𫍹謯 +𫍺𧫝 +𫍻譆 +𫍼𧬤 +𫍽譞 +𫍾𧭈 +𫍿譾 +𫎆豵 +𫎌貗 +𫎦贚 +𫎧䝭 +𫎨𧸘 +𫎩賝 +𫎪䞋 +𫎫贉 +𫎬贑 +𫎭䞓 +𫎱䟐 +𫎳䟆 +𫎸𧽯 +𫎺䟃 +𫏃䠆 +𫏆蹳 +𫏋蹻 +𫏌𨂐 +𫏐蹔 +𫏑𨇽 +𫏕𨆪 +𫏞𨇰 +𫏨𨇤 +𫐄軏 +𫐅軕 +𫐆轣 +𫐇軜 +𫐈軷 +𫐉軨 +𫐊軬 +𫐋𨎌 +𫐌軿 +𫐍𨌈 +𫐎輢 +𫐏輖 +𫐐輗 +𫐑輨 +𫐒輷 +𫐓輮 +𫐔𨍰 +𫐕轊 +𫐖轇 +𫐗轐 +𫐘轗 +𫐙轠 +𫐷遱 +𫑘鄟 +𫑡鄳 +𫑷醶 +𫓥釟 +𫓦釨 +𫓧鈇 +𫓨鈛 +𫓩鏦 +𫓪鈆 +𫓫𨥟 +𫓬鉔 +𫓭鉠 +𫓮𨪕 +𫓯銈 +𫓰銊 +𫓱鐈 +𫓲銁 +𫓳𨰋 +𫓴鉾 +𫓵鋠 +𫓶鋗 +𫓷𫒡 +𫓸錽 +𫓹錤 +𫓺鐪 +𫓻錜 +𫓼𨨛 +𫓽錝 +𫓾錥 +𫓿𨨢 +𫔀鍊 +𫔁鐼 +𫔂鍉 +𫔃𨰲 +𫔄鍒 +𫔅鎍 +𫔆䥯 +𫔇鎞 +𫔈鎙 +𫔉𨰃 +𫔊鏥 +𫔋䥗 +𫔌鏾 +𫔍鐇 +𫔎鐍 +𫔏𨬖 +𫔐𨭸 +𫔑𨭖 +𫔒𨮳 +𫔓𨯟 +𫔔鑴 +𫔕𨰥 +𫔖𨲳 +𫔭開 +𫔮閒 +𫔯閗 +𫔰閞 +𫔲𨴹 +𫔴閵 +𫔵䦯 +𫔶闑 +𫔽𨼳 +𫕚𩀨 +𫕥霣 +𫕨𩅙 +𫖃靧 +𫖅䪊 +𫖇鞾 +𫖑𩎖 +𫖒韠 +𫖓𩏂 +𫖔韛 +𫖕韝 +𫖖𩏠 +𫖪𩑔 +𫖫䪴 +𫖬䪾 +𫖭𩒎 +𫖮顗 +𫖯頫 +𫖰䫂 +𫖱䫀 +𫖲䫟 +𫖳頵 +𫖴𩔳 +𫖵𩓥 +𫖶顅 +𫖷𩔑 +𫖸願 +𫖹顣 +𫖺䫶 +𫗇䫻 +𫗈𩗓 +𫗉𩗴 +𫗊䬓 +𫗋飋 +𫗚𩟗 +𫗞飦 +𫗟䬧 +𫗠餦 +𫗡𩚩 +𫗢飵 +𫗣飶 +𫗤𩛌 +𫗥餫 +𫗦餔 +𫗧餗 +𫗨𩛡 +𫗩饠 +𫗪餧 +𫗫餬 +𫗬餪 +𫗭餵 +𫗮餭 +𫗯餱 +𫗰䭔 +𫗱䭑 +𫗳𩝽 +𫗴饘 +𫗵饟 +𫘛馯 +𫘜馼 +𫘝駃 +𫘞駞 +𫘟駊 +𫘠駤 +𫘡駫 +𫘣駻 +𫘤騃 +𫘥騉 +𫘦騊 +𫘧騄 +𫘨騠 +𫘩騜 +𫘪騵 +𫘫騴 +𫘬騱 +𫘭騻 +𫘮䮰 +𫘯驓 +𫘰驙 +𫘱驨 +𫘽鬠 +𫙂𩯁 +𫚈鱮 +𫚉魟 +𫚊鰑 +𫚋鱄 +𫚌魦 +𫚍魵 +𫚎𩶁 +𫚏䱁 +𫚐䱀 +𫚑鮅 +𫚒鮄 +𫚓鮤 +𫚔鮰 +𫚕鰤 +𫚖鮆 +𫚗鮯 +𫚘𩻮 +𫚙鯆 +𫚚鮿 +𫚛鮵 +𫚜䲅 +𫚝𩸄 +𫚞鯬 +𫚟𩸡 +𫚠䱧 +𫚡鯞 +𫚢鰋 +𫚣鯾 +𫚤鰦 +𫚥鰕 +𫚦鰫 +𫚧鰽 +𫚨𩻗 +𫚩𩻬 +𫚪鱊 +𫚫鱢 +𫚬𩼶 +𫚭鱲 +𫛚鳽 +𫛛鳷 +𫛜鴀 +𫛝鴅 +𫛞鴃 +𫛟鸗 +𫛠𩿤 +𫛡鴔 +𫛢鸋 +𫛣鴥 +𫛤鴐 +𫛥鵊 +𫛦鴮 +𫛧𪀖 +𫛨鵧 +𫛩鴳 +𫛪鴽 +𫛫鶰 +𫛬䳜 +𫛭鵟 +𫛮䳤 +𫛯鶭 +𫛰䳢 +𫛱鵫 +𫛲鵰 +𫛳鵩 +𫛴鷤 +𫛵鶌 +𫛶鶒 +𫛷鶦 +𫛸鶗 +𫛹𪃧 +𫛺䳧 +𫛻𪃒 +𫛼䳫 +𫛽鷅 +𫛾𪆷 +𫜀鷐 +𫜁鷩 +𫜂𪅂 +𫜃鷣 +𫜄鷷 +𫜅䴋 +𫜊𪉸 +𫜑麷 +𫜒䴱 +𫜓𪌭 +𫜔䴽 +𫜕𪍠 +𫜙䵴 +𫜟𪓰 +𫜨䶕 +𫜩齧 +𫜪齩 +𫜫𫜦 +𫜬齰 +𫜭齭 +𫜮齴 +𫜯𪙏 +𫜰齾 +𫜲龓 +𫜳䶲 +𫝈㑮 +𫝋𠐊 +𫝦㛝 +𫝧㜐 +𫝨媈 +𫝩嬦 +𫝪𡟫 +𫝫婡 +𫝬嬇 +𫝭孆 +𫝮孄 +𫝵嶹 +𫞅𦠅 +𫞗潣 +𫞚澬 +𫞛㶆 +𫞝灍 +𫞠爧 +𫞡爃 +𫞢𤛱 +𫞣㹽 +𫞥珼 +𫞦璾 +𫞧𤩂 +𫞨璼 +𫞩璊 +𫞷𥢶 +𫟃絍 +𫟄綋 +𫟅綡 +𫟆緟 +𫟇𦆲 +𫟑䖅 +𫟕䕤 +𫟞訨 +𫟟詊 +𫟠譂 +𫟡誴 +𫟢䜖 +𫟤䡐 +𫟥䡩 +𫟦䡵 +𫟫𨞺 +𫟬𨟊 +𫟲釚 +𫟳釲 +𫟴鈖 +𫟵鈗 +𫟶銏 +𫟷鉝 +𫟸鉽 +𫟹鉷 +𫟺䤤 +𫟻銂 +𫟼鐽 +𫟽𨧰 +𫟾𨩰 +𫟿鎈 +𫠀䥄 +𫠁鑉 +𫠂閝 +𫠅韚 +𫠆頍 +𫠇𩖰 +𫠈䫾 +𫠊䮄 +𫠋騼 +𫠌𩦠 +𫠏𩵦 +𫠐魽 +𫠑䱸 +𫠒鱆 +𫠖𩿅 +𫠜齯 +𫢸僤 +𫧃𣍐 +𫧮𪋿 +𫫇噁 +𫬐㘔 +𫭟塸 +𫭢埨 +𫭼𡑍 +𫮃墠 +𫰛娙 +𫵷㠣 +𫶇嵽 +𫷷廞 +𫸩彄 +𬀩暐 +𬀪晛 +𬂩梜 +𬃊櫍 +𬇕澫 +𬇙浿 +𬇹漍 +𬉼熰 +𬊈燖 +𬊤燀 +𬍛瓅 +𬍡璗 +𬍤璕 +𬒈礐 +𬒗𥗽 +𬕂篢 +𬘓紃 +𬘘紞 +𬘡絪 +𬘩綎 +𬘫綄 +𬘬綪 +𬘭綝 +𬘯綧 +𬙂縯 +𬙊纆 +𬙋纕 +𬜬蔄 +𬜯䓣 +𬞟蘋 +𬟁虉 +𬟽蝀 +𬣙訏 +𬣞詝 +𬣡諓 +𬣳詪 +𬤇諲 +𬤊諟 +𬤝譓 +𬨂軝 +𬨎輶 +𬩽鄩 +𬪩醲 +𬬩釴 +𬬭錀 +𬬮鋹 +𬬱釿 +𬬸鉥 +𬬹鉮 +𬬻鑪 +𬬿鉊 +𬭁鉧 +𬭊𨧀 +𬭎鋐 +𬭚錞 +𬭛𨨏 +𬭤鍭 +𬭩鎓 +𬭬鏏 +𬭭鏚 +𬭯䥕 +𬭳𨭎 +𬭶𨭆 +𬭸鏻 +𬭼鐩 +𬮱闉 +𬮿隑 +𬯀隮 +𬯎隤 +𬱖頔 +𬱟頠 +𬳵駓 +𬳶駉 +𬳽駪 +𬳿駼 +𬴂騑 +𬴃騞 +𬴊驎 +𬶋鮈 +𬶍鮀 +𬶏鮠 +𬶐鮡 +𬶟鯻 +𬶠鰊 +𬶨鱀 +𬶭鰶 +𬶮鱚 +𬷕鵏 +𬸘鶠 +𬸚鸑 +𬸣鶱 +𬸦鷟 +𬸪鷭 +𬸯鷿 +𬹼齘 +𬺈齮 +𬺓齼 +𰬸繐 +𰰨菕 +𰶎譅 +𰾄鋂 +𰾭鑀 +𱊜𪈼 \ No newline at end of file diff --git a/assets/translation.json b/assets/translation.json index 2ec3f9a..ae4c74b 100644 --- a/assets/translation.json +++ b/assets/translation.json @@ -400,7 +400,13 @@ "Delete Chapters": "删除章节", "Open Folder": "打开文件夹", "Path copied to clipboard": "路径已复制到剪贴板", - "Reverse default chapter order": "反转默认章节顺序" + "Reverse default chapter order": "反转默认章节顺序", + "Reload Configs": "重新加载配置文件", + "Reload": "重载", + "Disable Length Limitation": "禁用长度限制", + "Only valid for this run": "仅对本次运行有效", + "Logs": "日志", + "Export logs": "导出日志" }, "zh_TW": { "Home": "首頁", @@ -803,6 +809,12 @@ "Delete Chapters": "刪除章節", "Open Folder": "打開資料夾", "Path copied to clipboard": "路徑已複製到剪貼簿", - "Reverse default chapter order": "反轉預設章節順序" + "Reverse default chapter order": "反轉預設章節順序", + "Reload Configs": "重新載入設定檔", + "Reload": "重載", + "Disable Length Limitation": "禁用長度限制", + "Only valid for this run": "僅對本次運行有效", + "Logs": "日誌", + "Export logs": "匯出日誌" } } \ No newline at end of file diff --git a/doc/comic_source.md b/doc/comic_source.md index 3b136bd..db5d6ab 100644 --- a/doc/comic_source.md +++ b/doc/comic_source.md @@ -13,6 +13,14 @@ This document will describe how to write a comic source for Venera. Venera can display a list of comic sources in the app. +You can use the following repo url: +``` +https://git.nyne.dev/nyne/venera-configs/raw/branch/main/index.json +``` +The repo is maintained by the Venera team. + +> The link is a mirror of the original repo. To contribute your comic source, please visit the [original repo](https://github.com/venera-app/venera-configs) + You should provide a repository url to let the app load the comic source list. The url should point to a JSON file that contains the list of comic sources. @@ -33,12 +41,6 @@ The JSON file should have the following format: Only one of `url` and `filename` should be provided. The description field is optional. -Currently, you can use the following repo url: -``` -https://cdn.jsdelivr.net/gh/venera-app/venera-configs@main/index.json -``` -The repo is maintained by the Venera team, and you can submit a pull request to add your comic source. - ## Create a Comic Source ### Preparation diff --git a/lib/components/components.dart b/lib/components/components.dart index 200c4d5..30350a5 100644 --- a/lib/components/components.dart +++ b/lib/components/components.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:collection'; +import 'dart:convert'; import 'dart:math' as math; import 'dart:ui' as ui; @@ -21,11 +22,13 @@ import 'package:venera/foundation/image_provider/cached_image.dart'; import 'package:venera/foundation/image_provider/history_image_provider.dart'; import 'package:venera/foundation/image_provider/local_comic_image.dart'; import 'package:venera/foundation/local.dart'; +import 'package:venera/foundation/log.dart'; import 'package:venera/foundation/res.dart'; import 'package:venera/network/cloudflare.dart'; import 'package:venera/pages/comic_details_page/comic_page.dart'; import 'package:venera/pages/favorites/favorites_page.dart'; import 'package:venera/utils/ext.dart'; +import 'package:venera/utils/io.dart'; import 'package:venera/utils/tags_translation.dart'; import 'package:venera/utils/translations.dart'; diff --git a/lib/components/js_ui.dart b/lib/components/js_ui.dart index 04068e5..0a2e0cf 100644 --- a/lib/components/js_ui.dart +++ b/lib/components/js_ui.dart @@ -37,9 +37,11 @@ mixin class JsUiApi { case 'showInputDialog': var title = message['title']; var validator = message['validator']; + var image = message['image']; if (title is! String) return; if (validator != null && validator is! JSInvokable) return; - return _showInputDialog(title, validator); + if (image != null && image is! String) return; + return _showInputDialog(title, validator, image); case 'showSelectDialog': var title = message['title']; var options = message['options']; @@ -124,12 +126,13 @@ mixin class JsUiApi { controller?.close(); } - Future _showInputDialog(String title, JSInvokable? validator) async { + Future _showInputDialog(String title, JSInvokable? validator, String? image) async { String? result; var func = validator == null ? null : JSAutoFreeFunction(validator); await showInputDialog( context: App.rootContext, title: title, + image: image, onConfirm: (v) { if (func != null) { var res = func.call([v]); diff --git a/lib/components/loading.dart b/lib/components/loading.dart index 234d0ef..fd65b5c 100644 --- a/lib/components/loading.dart +++ b/lib/components/loading.dart @@ -41,18 +41,22 @@ class NetworkError extends StatelessWidget { ], ), ), - const SizedBox( - height: 8, - ), + const SizedBox(height: 8), Text( cfe == null ? message : "Cloudflare verification required".tl, textAlign: TextAlign.center, maxLines: 3, ), - if (retry != null) - const SizedBox( - height: 12, - ), + TextButton( + onPressed: () { + saveFile( + data: utf8.encode(Log().toString()), + filename: 'log.txt', + ); + }, + child: Text("Export logs".tl), + ), + const SizedBox(height: 8), if (retry != null) if (cfe != null) FilledButton( @@ -74,15 +78,11 @@ class NetworkError extends StatelessWidget { body = Column( children: [ const Appbar(title: Text("")), - Expanded( - child: body, - ) + Expanded(child: body), ], ); } - return Material( - child: body, - ); + return Material(child: body); } } @@ -94,9 +94,7 @@ class ListLoadingIndicator extends StatelessWidget { return const SizedBox( width: double.infinity, height: 80, - child: Center( - child: FiveDotLoadingAnimation(), - ), + child: Center(child: FiveDotLoadingAnimation()), ); } } @@ -108,10 +106,9 @@ class SliverListLoadingIndicator extends StatelessWidget { Widget build(BuildContext context) { // SliverToBoxAdapter can not been lazy loaded. // Use SliverList to make sure the animation can be lazy loaded. - return SliverList.list(children: const [ - SizedBox(), - ListLoadingIndicator(), - ]); + return SliverList.list( + children: const [SizedBox(), ListLoadingIndicator()], + ); } } @@ -178,10 +175,7 @@ abstract class LoadingState } Widget buildError() { - return NetworkError( - message: error!, - retry: retry, - ); + return NetworkError(message: error!, retry: retry); } @override @@ -323,11 +317,7 @@ abstract class MultiPageLoadingState } Widget buildError(BuildContext context, String error) { - return NetworkError( - withAppbar: false, - message: error, - retry: reset, - ); + return NetworkError(withAppbar: false, message: error, retry: reset); } @override @@ -388,7 +378,7 @@ class _FiveDotLoadingAnimationState extends State Colors.green, Colors.blue, Colors.yellow, - Colors.purple + Colors.purple, ]; static const _padding = 12.0; @@ -400,16 +390,15 @@ class _FiveDotLoadingAnimationState extends State @override Widget build(BuildContext context) { return AnimatedBuilder( - animation: _controller, - builder: (context, child) { - return SizedBox( - width: _dotSize * 5 + _padding * 6, - height: _height, - child: Stack( - children: List.generate(5, (index) => buildDot(index)), - ), - ); - }); + animation: _controller, + builder: (context, child) { + return SizedBox( + width: _dotSize * 5 + _padding * 6, + height: _height, + child: Stack(children: List.generate(5, (index) => buildDot(index))), + ); + }, + ); } Widget buildDot(int index) { @@ -417,7 +406,8 @@ class _FiveDotLoadingAnimationState extends State var startValue = index * 0.8; return Positioned( left: index * _dotSize + (index + 1) * _padding, - bottom: (math.sin(math.pi / 2 * (value - startValue).clamp(0, 2))) * + bottom: + (math.sin(math.pi / 2 * (value - startValue).clamp(0, 2))) * (_height - _dotSize), child: Container( width: _dotSize, diff --git a/lib/components/message.dart b/lib/components/message.dart index 9c27e24..f1c760e 100644 --- a/lib/components/message.dart +++ b/lib/components/message.dart @@ -359,6 +359,7 @@ Future showInputDialog({ String confirmText = "Confirm", String cancelText = "Cancel", RegExp? inputValidator, + String? image, }) { var controller = TextEditingController(text: initialValue); bool isLoading = false; @@ -371,14 +372,23 @@ Future showInputDialog({ builder: (context, setState) { return ContentDialog( title: title, - content: TextField( - controller: controller, - decoration: InputDecoration( - hintText: hintText, - border: const OutlineInputBorder(), - errorText: error, - ), - ).paddingHorizontal(12), + content: Column( + children: [ + if (image != null) + SizedBox( + height: 108, + child: Image.network(image, fit: BoxFit.none), + ).paddingBottom(8), + TextField( + controller: controller, + decoration: InputDecoration( + hintText: hintText, + border: const OutlineInputBorder(), + errorText: error, + ), + ).paddingHorizontal(12), + ], + ), actions: [ Button.filled( isLoading: isLoading, diff --git a/lib/foundation/app.dart b/lib/foundation/app.dart index a0403f2..105b985 100644 --- a/lib/foundation/app.dart +++ b/lib/foundation/app.dart @@ -13,7 +13,7 @@ export "widget_utils.dart"; export "context.dart"; class _App { - final version = "1.4.5"; + final version = "1.4.6"; bool get isAndroid => Platform.isAndroid; diff --git a/lib/foundation/appdata.dart b/lib/foundation/appdata.dart index f6ba39d..7c691f9 100644 --- a/lib/foundation/appdata.dart +++ b/lib/foundation/appdata.dart @@ -189,7 +189,7 @@ class Settings with ChangeNotifier { 'customImageProcessing': defaultCustomImageProcessing, 'sni': true, 'autoAddLanguageFilter': 'none', // none, chinese, english, japanese - 'comicSourceListUrl': '', + 'comicSourceListUrl': _defaultSourceListUrl, 'preloadImageCount': 4, 'followUpdatesFolder': null, 'initialPage': '0', @@ -235,3 +235,5 @@ function processImage(image, cid, eid, page, sourceKey) { return futureImage; } '''; + +const _defaultSourceListUrl = "https://git.nyne.dev/nyne/venera-configs/raw/branch/main/index.json"; diff --git a/lib/init.dart b/lib/init.dart index 48d40da..3e21d24 100644 --- a/lib/init.dart +++ b/lib/init.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:display_mode/display_mode.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_saf/flutter_saf.dart'; @@ -15,6 +16,7 @@ import 'package:venera/pages/follow_updates_page.dart'; import 'package:venera/pages/settings/settings_page.dart'; import 'package:venera/utils/app_links.dart'; import 'package:venera/utils/handle_text_share.dart'; +import 'package:venera/utils/opencc.dart'; import 'package:venera/utils/tags_translation.dart'; import 'package:venera/utils/translations.dart'; import 'foundation/appdata.dart'; @@ -43,6 +45,7 @@ Future init() async { TagsTranslation.readData().wait(), JsEngine().init().wait(), ComicSourceManager().init().wait(), + OpenCC.init(), ]; await Future.wait(futures); CacheManager().setLimitSize(appdata.settings['cacheSize']); @@ -50,6 +53,11 @@ Future init() async { if (App.isAndroid) { handleLinks(); handleTextShare(); + try { + await FlutterDisplayMode.setHighRefreshRate(); + } catch(e) { + Log.error("Display Mode", "Failed to set high refresh rate: $e"); + } } FlutterError.onError = (details) { Log.error("Unhandled Exception", "${details.exception}\n${details.stack}"); diff --git a/lib/pages/comic_source_page.dart b/lib/pages/comic_source_page.dart index d79a403..42ebe9c 100644 --- a/lib/pages/comic_source_page.dart +++ b/lib/pages/comic_source_page.dart @@ -191,13 +191,6 @@ class _BodyState extends State<_Body> { } Widget buildCard(BuildContext context) { - Widget buildButton({ - required Widget child, - required VoidCallback onPressed, - }) { - return Button.normal(onPressed: onPressed, child: child).fixHeight(32); - } - return SliverToBoxAdapter( child: SizedBox( width: double.infinity, @@ -224,33 +217,33 @@ class _BodyState extends State<_Body> { }, onSubmitted: handleAddSource, ).paddingHorizontal(16).paddingBottom(8), - ListTile( - title: Text("Comic Source list".tl), - trailing: buildButton( - child: Text("View".tl), - onPressed: () { - showPopUpWidget( - App.rootContext, - _ComicSourceList(handleAddSource), - ); - }, - ), - ), - ListTile( - title: Text("Use a config file".tl), - trailing: buildButton( - onPressed: _selectFile, - child: Text("Select".tl), - ), - ), - ListTile( - title: Text("Help".tl), - trailing: buildButton(onPressed: help, child: Text("Open".tl)), - ), - ListTile( - title: Text("Check updates".tl), - trailing: _CheckUpdatesButton(), - ), + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + FilledButton.tonalIcon( + icon: Icon(Icons.article_outlined), + label: Text("Comic Source list".tl), + onPressed: () { + showPopUpWidget( + App.rootContext, + _ComicSourceList(handleAddSource), + ); + }, + ), + FilledButton.tonalIcon( + icon: Icon(Icons.file_open_outlined), + label: Text("Use a config file".tl), + onPressed: _selectFile, + ), + FilledButton.tonalIcon( + icon: Icon(Icons.help_outline), + label: Text("Help".tl), + onPressed: help, + ), + _CheckUpdatesButton(), + ], + ).paddingHorizontal(12).paddingVertical(8), const SizedBox(height: 8), ], ), @@ -699,11 +692,15 @@ class _CheckUpdatesButtonState extends State<_CheckUpdatesButton> { @override Widget build(BuildContext context) { - return Button.normal( + return FilledButton.tonalIcon( + icon: isLoading ? SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator(strokeWidth: 2), + ) : Icon(Icons.update), + label: Text("Check updates".tl), onPressed: check, - isLoading: isLoading, - child: Text("Check".tl), - ).fixHeight(32); + ); } } diff --git a/lib/pages/favorites/favorites_page.dart b/lib/pages/favorites/favorites_page.dart index bbdf963..df76067 100644 --- a/lib/pages/favorites/favorites_page.dart +++ b/lib/pages/favorites/favorites_page.dart @@ -20,6 +20,7 @@ import 'package:venera/pages/reader/reader.dart'; import 'package:venera/pages/settings/settings_page.dart'; import 'package:venera/utils/ext.dart'; import 'package:venera/utils/io.dart'; +import 'package:venera/utils/opencc.dart'; import 'package:venera/utils/tags_translation.dart'; import 'package:venera/utils/translations.dart'; diff --git a/lib/pages/favorites/local_favorites_page.dart b/lib/pages/favorites/local_favorites_page.dart index 12f258c..2d4fc17 100644 --- a/lib/pages/favorites/local_favorites_page.dart +++ b/lib/pages/favorites/local_favorites_page.dart @@ -52,7 +52,9 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> { } else { searchResults = []; for (var comic in comics) { - if (matchKeyword(keyword, comic)) { + if (matchKeyword(keyword, comic) || + matchKeywordT(keyword, comic) || + matchKeywordS(keyword, comic)) { searchResults.add(comic); } } @@ -130,6 +132,24 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> { return true; } + // Convert keyword to traditional Chinese to match comics + bool matchKeywordT(String keyword, FavoriteItem comic) { + if (!OpenCC.hasChineseSimplified(keyword)) { + return false; + } + keyword = OpenCC.simplifiedToTraditional(keyword); + return matchKeyword(keyword, comic); + } + + // Convert keyword to simplified Chinese to match comics + bool matchKeywordS(String keyword, FavoriteItem comic) { + if (!OpenCC.hasChineseTraditional(keyword)) { + return false; + } + keyword = OpenCC.traditionalToSimplified(keyword); + return matchKeyword(keyword, comic); + } + @override void initState() { favPage = context.findAncestorStateOfType<_FavoritesPageState>()!; diff --git a/lib/pages/reader/images.dart b/lib/pages/reader/images.dart index 90f9b35..0b3ebc0 100644 --- a/lib/pages/reader/images.dart +++ b/lib/pages/reader/images.dart @@ -85,14 +85,21 @@ class _ReaderImagesState extends State<_ReaderImages> { child: CircularProgressIndicator(), ); } else if (error != null) { - return NetworkError( - message: error!, - retry: () { - setState(() { - reader.isLoading = true; - error = null; - }); + return GestureDetector( + onTap: () { + context.readerScaffold.openOrClose(); }, + child: SizedBox.expand( + child: NetworkError( + message: error!, + retry: () { + setState(() { + reader.isLoading = true; + error = null; + }); + }, + ), + ), ); } else { if (reader.mode.isGallery) { diff --git a/lib/pages/reader/reader.dart b/lib/pages/reader/reader.dart index 66c23ac..c0148f3 100644 --- a/lib/pages/reader/reader.dart +++ b/lib/pages/reader/reader.dart @@ -177,10 +177,18 @@ class _ReaderState extends State super.initState(); } + bool _isInitialized = false; + @override void didChangeDependencies() { super.didChangeDependencies(); - initImagesPerPage(widget.initialPage ?? 1); + if (!_isInitialized) { + initImagesPerPage(widget.initialPage ?? 1); + _isInitialized = true; + } else { + // For orientation changed + _checkImagesPerPageChange(); + } initReaderWindow(); } @@ -345,6 +353,8 @@ class _ReaderState extends State abstract mixin class _ImagePerPageHandler { late int _lastImagesPerPage; + late bool _lastOrientation; + bool get isPortrait; int get page; @@ -355,6 +365,7 @@ abstract mixin class _ImagePerPageHandler { void initImagesPerPage(int initialPage) { _lastImagesPerPage = imagesPerPage; + _lastOrientation = isPortrait; if (imagesPerPage != 1) { if (showSingleImageOnFirstPage) { page = ((initialPage - 1) / imagesPerPage).ceil() + 1; @@ -380,19 +391,42 @@ abstract mixin class _ImagePerPageHandler { /// Check if the number of images per page has changed void _checkImagesPerPageChange() { int currentImagesPerPage = imagesPerPage; - if (_lastImagesPerPage != currentImagesPerPage) { + bool currentOrientation = isPortrait; + + if (_lastImagesPerPage != currentImagesPerPage || _lastOrientation != currentOrientation) { _adjustPageForImagesPerPageChange( _lastImagesPerPage, currentImagesPerPage); _lastImagesPerPage = currentImagesPerPage; + _lastOrientation = currentOrientation; } } /// Adjust the page number when the number of images per page changes void _adjustPageForImagesPerPageChange( int oldImagesPerPage, int newImagesPerPage) { - int previousImageIndex = (page - 1) * oldImagesPerPage; - int newPage = (previousImageIndex ~/ newImagesPerPage) + 1; - page = newPage; + int previousImageIndex = 1; + if (!showSingleImageOnFirstPage || oldImagesPerPage == 1) { + previousImageIndex = (page - 1) * oldImagesPerPage + 1; + } else { + if (page == 1) { + previousImageIndex = 1; + } else { + previousImageIndex = (page - 2) * oldImagesPerPage + 2; + } + } + + int newPage; + if (newImagesPerPage != 1) { + if (showSingleImageOnFirstPage) { + newPage = ((previousImageIndex - 1) / newImagesPerPage).ceil() + 1; + } else { + newPage = (previousImageIndex / newImagesPerPage).ceil(); + } + } else { + newPage = previousImageIndex; + } + + page = newPage>0 ? newPage : 1; } } diff --git a/lib/pages/settings/app.dart b/lib/pages/settings/app.dart index a6f91f8..c057eb3 100644 --- a/lib/pages/settings/app.dart +++ b/lib/pages/settings/app.dart @@ -193,12 +193,46 @@ class LogsPage extends StatefulWidget { } class _LogsPageState extends State { + String logLevelToShow = "all"; + @override Widget build(BuildContext context) { + var logToShow = logLevelToShow == "all" + ? Log.logs + : Log.logs.where((log) => log.level.name == logLevelToShow).toList(); return Scaffold( appBar: Appbar( - title: const Text("Logs"), + title: Text("Logs".tl), actions: [ + IconButton( + onPressed: () => setState(() { + final RelativeRect position = RelativeRect.fromLTRB( + MediaQuery.of(context).size.width, + MediaQuery.of(context).padding.top + kToolbarHeight, + 0.0, + 0.0, + ); + showMenu(context: context, position: position, items: [ + PopupMenuItem( + child: Text("all"), + onTap: () => setState(() => logLevelToShow = "all") + ), + PopupMenuItem( + child: Text("info"), + onTap: () => setState(() => logLevelToShow = "info") + ), + PopupMenuItem( + child: Text("warning"), + onTap: () => setState(() => logLevelToShow = "warning") + ), + PopupMenuItem( + child: Text("error"), + onTap: () => setState(() => logLevelToShow = "error") + ), + ]); + }), + icon: const Icon(Icons.filter_list_outlined) + ), IconButton( onPressed: () => setState(() { final RelativeRect position = RelativeRect.fromLTRB( @@ -217,7 +251,7 @@ class _LogsPageState extends State { onTap: () { Log.ignoreLimitation = true; context.showMessage( - message: "Only valid for this run"); + message: "Only valid for this run".tl); }, ), PopupMenuItem( @@ -232,9 +266,9 @@ class _LogsPageState extends State { body: ListView.builder( reverse: true, controller: ScrollController(), - itemCount: Log.logs.length, + itemCount: logToShow.length, itemBuilder: (context, index) { - index = Log.logs.length - index - 1; + index = logToShow.length - index - 1; return Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), child: SelectionArea( @@ -253,7 +287,7 @@ class _LogsPageState extends State { ), child: Padding( padding: const EdgeInsets.fromLTRB(5, 0, 5, 1), - child: Text(Log.logs[index].title), + child: Text(logToShow[index].title), ), ), const SizedBox( @@ -265,16 +299,16 @@ class _LogsPageState extends State { Theme.of(context).colorScheme.error, Theme.of(context).colorScheme.errorContainer, Theme.of(context).colorScheme.primaryContainer - ][Log.logs[index].level.index], + ][logToShow[index].level.index], borderRadius: const BorderRadius.all(Radius.circular(16)), ), child: Padding( padding: const EdgeInsets.fromLTRB(5, 0, 5, 1), child: Text( - Log.logs[index].level.name, + logToShow[index].level.name, style: TextStyle( - color: Log.logs[index].level.index == 0 + color: logToShow[index].level.index == 0 ? Colors.white : Colors.black), ), @@ -282,14 +316,14 @@ class _LogsPageState extends State { ), ], ), - Text(Log.logs[index].content), - Text(Log.logs[index].time + Text(logToShow[index].content), + Text(logToShow[index].time .toString() .replaceAll(RegExp(r"\.\w+"), "")), TextButton( onPressed: () { Clipboard.setData( - ClipboardData(text: Log.logs[index].content)); + ClipboardData(text: logToShow[index].content)); }, child: Text("Copy".tl), ), diff --git a/lib/pages/settings/debug.dart b/lib/pages/settings/debug.dart index 232861b..e5889fd 100644 --- a/lib/pages/settings/debug.dart +++ b/lib/pages/settings/debug.dart @@ -18,8 +18,8 @@ class DebugPageState extends State { slivers: [ SliverAppbar(title: Text("Debug".tl)), _CallbackSetting( - title: "Reload Configs", - actionTitle: "Reload", + title: "Reload Configs".tl, + actionTitle: "Reload".tl, callback: () { ComicSourceManager().reload(); }, diff --git a/lib/utils/opencc.dart b/lib/utils/opencc.dart new file mode 100644 index 0000000..20464de --- /dev/null +++ b/lib/utils/opencc.dart @@ -0,0 +1,67 @@ +import 'dart:convert'; + +import 'package:flutter/services.dart'; + +abstract class OpenCC { + static late final Map _s2t; + static late final Map _t2s; + + static Future init() async { + var data = await rootBundle.load("assets/opencc.txt"); + var txt = utf8.decode(data.buffer.asUint8List()); + _s2t = {}; + _t2s = {}; + for (var line in txt.split('\n')) { + if (line.isEmpty || line.startsWith('#') || line.length != 2) continue; + var s = line.runes.elementAt(0); + var t = line.runes.elementAt(1); + _s2t[s] = t; + _t2s[t] = s; + } + } + + static bool hasChineseSimplified(String text) { + if (text != "监禁") { + return false; + } + for (var rune in text.runes) { + if (_s2t.containsKey(rune)) { + return true; + } + } + return false; + } + + static bool hasChineseTraditional(String text) { + for (var rune in text.runes) { + if (_t2s.containsKey(rune)) { + return true; + } + } + return false; + } + + static String simplifiedToTraditional(String text) { + var sb = StringBuffer(); + for (var rune in text.runes) { + if (_s2t.containsKey(rune)) { + sb.write(String.fromCharCodes([_s2t[rune]!])); + } else { + sb.write(String.fromCharCodes([rune])); + } + } + return sb.toString(); + } + + static String traditionalToSimplified(String text) { + var sb = StringBuffer(); + for (var rune in text.runes) { + if (_t2s.containsKey(rune)) { + sb.write(String.fromCharCodes([_t2s[rune]!])); + } else { + sb.write(String.fromCharCodes([rune])); + } + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 46382b0..ddf1f2d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -170,6 +170,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + display_mode: + dependency: "direct main" + description: + name: display_mode + sha256: "8a381f3602a09dc4e96140a0df30808631468d6d0dfff7722f67b1f83757a7cc" + url: "https://pub.dev" + source: hosted + version: "0.0.2" dynamic_color: dependency: "direct main" description: @@ -1108,4 +1116,4 @@ packages: version: "0.0.12" sdks: dart: ">=3.8.0 <4.0.0" - flutter: ">=3.32.4" + flutter: ">=3.32.6" diff --git a/pubspec.yaml b/pubspec.yaml index 34048d9..3255127 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,11 +2,11 @@ name: venera description: "A comic app." publish_to: 'none' -version: 1.4.5+145 +version: 1.4.6+146 environment: sdk: '>=3.8.0 <4.0.0' - flutter: 3.32.4 + flutter: 3.32.6 dependencies: flutter: @@ -86,6 +86,7 @@ dependencies: sdk: flutter yaml: ^3.1.3 enough_convert: ^1.6.0 + display_mode: ^0.0.2 dev_dependencies: flutter_test: @@ -102,6 +103,7 @@ flutter: - assets/app_icon.png - assets/tags.json - assets/tags_tw.json + - assets/opencc.txt flutter_to_arch: name: Venera diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp index fd0590a..1f45d6d 100644 --- a/windows/runner/flutter_window.cpp +++ b/windows/runner/flutter_window.cpp @@ -98,14 +98,20 @@ bool FlutterWindow::OnCreate() { else result->Success(flutter::EncodableValue("No Proxy")); delete(res); + return; } +#ifdef NDEBUG else if (call.method_name() == "heartBeat") { + if (monitorThread == nullptr) { monitorThread = new std::thread{ monitorUIThread }; } lastHeartbeat = std::chrono::steady_clock::now(); result->Success(); + return; } +#endif + result->Success(); // Default response for unhandled method calls }); flutter::EventChannel<> channel2(