Update theme and fix bugs.

This commit is contained in:
Bruce
2025-12-10 22:12:32 +08:00
parent 85b0d2b5b9
commit fc66b6de72
14 changed files with 543 additions and 102 deletions

View File

@@ -10,6 +10,7 @@
#include "themeinfo.h"
#include "localeex.h"
#include "syncutil.h"
#include "strcmp.h"
#include <string>
#include <vector>
@@ -116,44 +117,6 @@ ref class PriFileInst
}
}
};
std::wstring GetStringLeft (const std::wstring &str, size_t length = 1)
{
std::wstring ret = L"";
ret.reserve (length + 1);
size_t slen = lstrlenW (str.c_str ());
for (size_t i = 0; i < length && i < slen; i ++)
{
ret += str.at (i);
}
return ret;
}
std::wstring GetStringRight (const std::wstring &str, size_t length = 1)
{
std::wstring ret = L"";
ret.reserve (length + 1);
size_t slen = lstrlenW (str.c_str ());
for (size_t i = ((int64_t)slen - length) < 0 ? 0 : slen - length; i < slen; i ++) ret += str.at (i);
return ret;
}
std::string GetStringLeft (const std::string &str, size_t length = 1)
{
std::string ret = "";
ret.reserve (length + 1);
size_t slen = strlen (str.c_str ());
for (size_t i = 0; i < length && i < slen; i ++)
{
ret += str.at (i);
}
return ret;
}
std::string GetStringRight (const std::string &str, size_t length = 1)
{
std::string ret = "";
ret.reserve (length + 1);
size_t slen = strlen (str.c_str ());
for (size_t i = ((int64_t)slen - length) < 0 ? 0 : slen - length; i < slen; i ++) ret += str.at (i);
return ret;
}
size_t KeyToPath (const std::wstring &key, std::vector <std::wnstring> &output);
typedef struct _TASKITEM_SEARCH
{
@@ -531,7 +494,7 @@ std::wstring GetSuitablePathValueByDPI (std::vector<candidate_value> &pathcand)
});
if (pathcand.empty ()) return L"";
uint32_t nowdpi = GetDPI ();
for (auto &cv : pathcand) if (cv.get_scale () >= nowdpi) return cv.value;
for (auto &cv : pathcand) if (cv.get_scale () >= nowdpi && !StrInclude (cv.value, L"layoutdir-RTL", true)) return cv.value;
return pathcand.back ().value;
}
std::wstring GetSuitablePathValue (std::vector <candidate_value> &pathcand)

View File

@@ -159,6 +159,7 @@
<ClInclude Include="priformatcli.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="strcmp.h" />
<ClInclude Include="syncutil.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="themeinfo.h" />

View File

@@ -51,6 +51,9 @@
<ClInclude Include="resource.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="strcmp.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">

154
priformatcli/strcmp.h Normal file
View File

@@ -0,0 +1,154 @@
#pragma once
#include <Shlwapi.h>
#include "nstring.h"
#ifdef __cplusplus
#define ptrnull(ptr) (!(ptr))
#else
#define ptrnull(ptr) ((ptr) == NULL)
#endif
#define ptrvalid(ptr) (!ptrnull (ptr))
// 用于 char * 或 WCHAR * 字符串(结尾为 NULL判断是否为非空字符串指针有效且长度大于 0。千万不能是野指针否则一定会崩溃
#define strvalid(strptr) (ptrvalid (strptr) && *(strptr))
// 用于 char * 或 WCHAR * 字符串(结尾为 NULL判断是否为空字符串指针为 NULL 或长度为 0。千万不能是野指针否则一定会崩溃
#define strnull(strptr) (ptrnull (strptr) || !*(strptr))
typedef std::wnstring strlabel, StringLabel;
std::wstring StringTrim (const std::wstring &str) { return std::wnstring::trim (str); }
std::string StringTrim (const std::string &str) { return std::nstring::trim (str); }
#define StringToUpper l0km::toupper
#define StringToLower l0km::tolower
int LabelCompare (const std::wstring &l1, const std::wstring &l2)
{
return std::wnstring::compare (l1, l2);
}
int LabelCompare (const std::string &l1, const std::string &l2)
{
return std::nstring::compare (l1, l2);
}
bool LabelEqual (const std::wstring &l1, const std::wstring &l2)
{
return std::wnstring::equals (l1, l2);
}
bool LabelEqual (const std::string &l1, const std::string &l2)
{
return std::wnstring::equals (l1, l2);
}
bool LabelEmpty (const std::wstring &str) { return std::wnstring::empty (str); }
bool LabelEmpty (const std::string &str) { return std::nstring::empty (str); }
#define LabelNoEmpty(_str_) (!LabelEmpty (_str_))
int InStr (const std::string &text, const std::string &keyword, bool ignoreCase = false)
{
std::string s1, s2;
if (ignoreCase)
{
s1 = StringToUpper (text);
s2 = StringToUpper (keyword);
}
else
{
s1 = text;
s2 = keyword;
}
const char *found = StrStrIA (s1.c_str (), s2.c_str ());
if (!found)
{
return -1;
}
return found - text.c_str ();
}
int InStr (const std::wstring &text, const std::wstring &keyword, bool ignoreCase = false)
{
std::wstring s1, s2;
if (ignoreCase)
{
s1 = StringToUpper (text);
s2 = StringToUpper (keyword);
}
else
{
s1 = text;
s2 = keyword;
}
const WCHAR *found = StrStrIW (s1.c_str (), s2.c_str ());
if (!found)
{
return -1;
}
return found - text.c_str ();
}
bool StrInclude (const std::string &text, const std::string &keyword, bool ignoreCase = false)
{
std::string s1, s2;
if (ignoreCase)
{
s1 = StringToUpper (text);
s2 = StringToUpper (keyword);
}
else
{
s1 = text;
s2 = keyword;
}
const char *found = StrStrIA (s1.c_str (), s2.c_str ());
if (!found) return false;
return true;
}
bool StrInclude (const std::wstring &text, const std::wstring &keyword, bool ignoreCase = false)
{
std::wstring s1, s2;
if (ignoreCase)
{
s1 = StringToUpper (text);
s2 = StringToUpper (keyword);
}
else
{
s1 = text;
s2 = keyword;
}
const WCHAR *found = StrStrIW (s1.c_str (), s2.c_str ());
if (!found) return false;
return true;
}
// 该函数帮助构成 "<str1>\0<str2>\0" 这种字符串,用于通用对话框中的文件框
LPCWSTR strcpynull (LPWSTR dest, LPCWSTR endwith, size_t bufsize)
{
if (!dest || !endwith || bufsize == 0)
return dest;
if (dest [0] == L'\0' && bufsize > 1)
{
dest [1] = L'\0';
}
size_t pos = 0;
while (pos < bufsize - 1)
{
if (dest [pos] == L'\0' && dest [pos + 1] == L'\0')
{
if (dest [0]) pos ++;
break;
}
pos ++;
}
size_t i = 0;
while (pos < bufsize - 1 && endwith [i] != L'\0')
{
dest [pos ++] = endwith [i ++];
}
if (pos < bufsize)
{
dest [pos] = L'\0';
}
return dest;
}
// 取文本左边注意长度指的是文本字符数比如“ch”的长度为2
std::wstring GetStringLeft (const std::wstring &str, size_t length)
{
std::vector <WCHAR> buf (length + 1);
lstrcpynW (buf.data (), str.c_str (), length + 1);
return buf.data ();
}
// 取文本右边
std::wstring GetStringRight (const std::wstring &str, size_t length)
{
if (length >= str.length ()) return str;
return str.substr (str.length () - length, length).c_str ();
}

Binary file not shown.

View File

@@ -6,7 +6,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="libs/winjs/2.0/css/ui-light.css">
<link rel="stylesheet" href="libs/winjs/2.0/css/ui-light.css" id="winjs-style">
<script type="text/javascript" src="js/module.js"></script>
<script type="text/javascript" src="js/polyfill-ie.js"></script>
<script type="text/javascript" src="js/bridge.js"></script>
@@ -245,11 +245,13 @@
font-weight: normal;
}
</style>
<link rel="stylesheet" type="text/css" href="theme/light/default/default.css" id="theme-style">
<script type="text/javascript" src="js/theme.js"></script>
</head>
<body>
<div role="template" id="applist-item-template">
<div class="applist-list-item">
<div class="applist-list-item" role="template">
<div class="applist-item-picbox" style="background-color: rgb(0,0,0);">
<img class="applist-item-pic" src="images/applogo.default.png" width="32" height="32">
<div class="applist-item-img-border"></div>
@@ -345,6 +347,7 @@
function createItem(title, logo, appid, color) {
var item = AppListElements.template.cloneNode(true);
item.removeAttribute("role");
var inode = new AppListNodeElement(item);
inode.title = title;
inode.logo = logo;

View File

@@ -22,12 +22,12 @@
<script type="text/javascript" src="js/event.js"></script>
<script type="text/javascript" src="js/tileback.js"></script>
<script type="text/javascript" src="js/pages.js"></script>
<script type="text/javascript" src="js/theme.js"></script>
<script type="text/javascript" src="js/load.js"></script>
<script type="text/javascript" src="js/init.js"></script>
<link rel="stylesheet" type="text/css" href="libs/msgbox/msgbox.css">
<script type="text/javascript" src="libs/msgbox/msgbox.js"></script>
<link rel="stylesheet" type="text/css" href="theme/light/default.css" id="theme-style">
<link rel="stylesheet" type="text/css" href="theme/light/default/default.css" id="theme-style">
<script type="text/javascript" src="js/theme.js"></script>
</head>
<body>

View File

@@ -1,5 +1,200 @@
(function(global) {
"use strict";
var winjsCss = document.querySelector("link#winjs-style");
var themeCss = document.querySelector("link#theme-style");
var winjsPath = "libs/winjs/2.0/css/ui-{themecolor}.css";
var themePath = "theme/{themecolor}/{id}/{id}.css";
var ini = Bridge.External.Config.getConfig();
var themeSection = ini.getSection("Personalization");
var ThemeType = {
light: 1, // 浅色模式
dark: 2, // 深色模式
auto: 3, // 跟随系统
time: 4, // 跟随时间
custom: 5 // 自定义
};
var nstrutil = Bridge.NString;
var ColorType = {
light: 0xFFFFFF,
dark: 0x000000,
};
function changeDarkMode(mode) {}
function getThemeSwitchType() {
var themeType = themeSection.getKey("AppInstaller:ThemeMode").value;
if (nstrutil.equals(themeType, "light")) return ThemeType.light;
else if (nstrutil.equals(themeType, "dark")) return ThemeType.dark;
else if (nstrutil.equals(themeType, "auto")) return ThemeType.auto;
else if (nstrutil.equals(themeType, "time")) return ThemeType.time;
else if (nstrutil.equals(themeType, "custom")) return ThemeType.custom;
else return ThemeType.light;
}
function getCurrentThemeColor() {
try {
var themeType = getThemeSwitchType();
if (themeType === ThemeType.light) return ColorType.light;
else if (themeType === ThemeType.dark) return ColorType.dark;
else if (themeType === ThemeType.auto) {
if (Bridge.UI.darkmode) return ColorType.dark;
else return ColorType.light;
} else if (themeType === ThemeType.time) {
var daytime = new Date();
var nighttime = new Date();
try {
var daytimestr = themeSection.getKey("AppInstaller:DayTime").value;
daytime = new Date(daytimestr);
} catch (e) {
console.error(e);
daytime = new Date('2011-07-15T08:00:00.000Z');
}
try {
var nighttimestr = themeSection.getKey("AppInstaller:NightTime").value;
nighttime = new Date(nighttimestr);
} catch (e) {
console.error(e);
nighttime = new Date('2011-07-15T20:00:00.000Z');
}
var now = new Date();
daytime.setFullYear(now.getFullYear());
nighttime.setFullYear(now.getFullYear());
daytime.setMonth(now.getMonth());
nighttime.setMonth(now.getMonth());
daytime.setDate(now.getDate());
nighttime.setDate(now.getDate());
if (now >= daytime && now < nighttime) return ColorType.light;
else return ColorType.dark;
} else if (themeType === ThemeType.custom) {
var customColor = themeSection.getKey("AppInstaller:CustomColor").value;
if (nstrutil.equals(customColor, "light")) return ColorType.light;
else if (nstrutil.equals(customColor, "dark")) return ColorType.dark;
else return ColorType.light;
} else {
return ColorType.light;
}
} catch (e) {
return ColorType.light;
}
}
function getSuitableTheme() {
var color = getCurrentThemeColor();
var ret = "";
if (color === ColorType.light) ret = themeSection.getKey("AppInstaller:LightTheme").value;
else ret = themeSection.getKey("AppInstaller:DarkTheme").value;
if (nstrutil.empty(ret)) ret = "default";
return ret;
}
function getTimeModeTimeLimit() {
var ret = {
day: new Date(),
night: new Date()
};
try {
var daytimestr = themeSection.getKey("AppInstaller:DayTime").value;
ret.day = new Date(daytimestr);
} catch (e) {
console.error(e);
ret.day = new Date('2011-07-15T08:00:00.000Z');
}
try {
var nighttimestr = themeSection.getKey("AppInstaller:NightTime").value;
ret.night = new Date(nighttimestr);
} catch (e) {
console.error(e);
ret.night = new Date('2011-07-15T20:00:00.000Z');
}
var now = new Date();
ret.day.setFullYear(now.getFullYear());
ret.night.setFullYear(now.getFullYear());
ret.day.setMonth(now.getMonth());
ret.night.setMonth(now.getMonth());
ret.day.setDate(now.getDate());
ret.night.setDate(now.getDate());
return ret;
}
function copyTime(to, from) {
to.setHours(
from.getHours(),
from.getMinutes(),
from.getSeconds(),
from.getMilliseconds()
);
}
var dayTimer = null;
var nightTimer = null;
function setupThemeTimers(limit, execFunc) {
if (limit === null || limit === void 0) limit = getTimeModeTimeLimit();
var now = new Date();
var dayTime = new Date(now);
var nightTime = new Date(now);
copyTime(dayTime, limit.day);
copyTime(nightTime, limit.night);
// 处理跨天:如果 night <= day说明夜晚跨到第二天
var nightIsNextDay = nightTime <= dayTime;
if (nightIsNextDay) {
nightTime.setDate(nightTime.getDate() + 1);
}
var isDayTime;
if (nightIsNextDay) {
isDayTime = now >= dayTime && now < nightTime;
} else {
isDayTime = now >= dayTime && now < nightTime;
}
var nextDay = new Date(dayTime);
var nextNight = new Date(nightTime);
if (now >= dayTime) nextDay.setDate(nextDay.getDate() + 1);
if (now >= nightTime) nextNight.setDate(nextNight.getDate() + 1);
if (dayTimer) {
clearTimeout(dayTimer);
dayTimer = null;
}
if (nightTimer) {
clearTimeout(nightTimer);
nightTimer = null;
}
dayTimer = setTimeout(function() {
execFunc("day");
setupThemeTimers(); // 递归重建,防漂移
}, nextDay - now);
nightTimer = setTimeout(function() {
execFunc("night");
setupThemeTimers();
}, nextNight - now);
return isDayTime ? "day" : "night";
}
function refreshTheme() {
var type = getThemeSwitchType();
var color = getCurrentThemeColor();
var theme = getSuitableTheme();
if (type === ThemeType.time) {
setupThemeTimers(getTimeModeTimeLimit(), refreshTheme);
}
var colorstr = "light";
if (color === ColorType.light) colorstr = "light";
else if (color === ColorType.dark) colorstr = "dark";
winjsCss.setAttribute("href", winjsPath.replace("{themecolor}", colorstr));
themeCss.setAttribute("href", themePath.replace("{themecolor}", colorstr).replace("{id}", theme).replace("{id}", theme));
setTimeout(function() {
try { Windows.UI.DPI.mode = 1; } catch (e) {}
}, 0);
}
module.exports = {
Theme: {
ThemeType: ThemeType,
ColorType: ColorType,
getType: getThemeSwitchType,
getColor: getCurrentThemeColor,
getTheme: getSuitableTheme,
getTimeModeTimeLimit: getTimeModeTimeLimit,
refresh: refreshTheme
}
};
if (typeof OnLoad !== "undefined") {
OnLoad.add(refreshTheme);
}
})(this);

View File

@@ -219,6 +219,8 @@
var json = JSON.parse(resp.responseText);
var decoderesult = decodeBase64(json.content);
content.innerHTML = decoderesult;
content.style.height = "300px";
content.style.maxHeight = "100%";
},
function(err) {
progress.style.display = "none";
@@ -257,6 +259,9 @@
script.src = jsfile;
content.contentWindow.document.head.appendChild(script);
}
var style2 = document.createElement("style");
style2.innerHTML = '*,button,input,select,textarea,a,label,p,span,h1,h2,h3,h4,h5,h6,ul,ol,li,dl,dt,dd,table,th,td,tr,img,iframe,object,embed,audio,video,canvas,form,fieldset,legend,.win-type-x-large,.win-type-xx-large,.font-fixed{font-family:"Microsoft YaHei","Segoe UI","Ebrima","Nirmala","Gadugi","Segoe UI Emoji","Segoe UI Symbol","Meiryo","Leelawadee","Microsoft JhengHei","Malgun Gothic","Estrangelo Edessa","Microsoft Himalaya","Microsoft New Tai Lue","Microsoft PhagsPa","Microsoft Tai Le","Microsoft Yi Baiti","Mongolian Baiti","MV Boli","Myanmar Text","Javanese Text","Cambria Math";}';
content.contentWindow.document.head.appendChild(style2);
content.contentWindow.document.body.style.overflowY = "auto";
content.contentWindow.Windows.UI.DPI.mode = 1;
} catch (e) {}

View File

@@ -64,14 +64,14 @@
<div class="win-settings-row">
<div class="win-settings-label" style="font-weight: normal;">白天</div>
<div class="win-settings-control">
<div data-win-control="WinJS.UI.TimePicker" data-win-options="{ hour: 9, minute: 0, clock: '24HourClock' }">
<div data-win-control="WinJS.UI.TimePicker" data-win-options="{ hour: 9, minute: 0, clock: '24HourClock' }" id="theme-day-time">
</div>
</div>
</div>
<div class="win-settings-row">
<div class="win-settings-label" style="font-weight: normal;">夜晚</div>
<div class="win-settings-control">
<div data-win-control="WinJS.UI.TimePicker" data-win-options="{ hour: 18, minute: 0, clock: '24HourClock' }">
<div data-win-control="WinJS.UI.TimePicker" data-win-options="{ hour: 18, minute: 0, clock: '24HourClock' }" id="theme-night-time">
</div>
</div>
</div>
@@ -79,7 +79,7 @@
</div>
<div class="win-settings-section" id="item-theme">
<br>
<label>主题模式</label><br>
<label>自定义主题模式</label><br>
<script>
(function() {
var sect = document.getElementById("item-theme");
@@ -93,7 +93,10 @@
</script>
<br>
<label>选择主题</label>
<div id="theme-items-select" data-win-control="WinJS.UI.ListView"></div>
<p>浅色主题</p>
<div class="win-listview"></div>
<p>深色主题</p>
<div class="win-listview"></div>
</div>
</div>
</div>

View File

@@ -1,35 +0,0 @@
* {
transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.page {
background-color: #1d1d1d;
}
.page.splash {
background-color: #001629;
}
.page.splash .content,
.page.splash .content * {
transition: none;
}
.page .content.loading,
.page .content.main,
.page .progress,
.page .reason p,
.page .controls .checkbox {
color: white;
}
.page .content.main .pkgapplabel {
color: #299fff;
}
.page .reason textarea {
background-color: rgba (255, 255, 255, 0);
color: white;
border: 2px solid white;
box-sizing: border-box;
}

View File

@@ -0,0 +1,91 @@
/*
[ThemeInfo]
Id = default
DisplayName = Default Theme
Author = Bruce Winter
Version = 1.0
Description = Default theme.
Url = https://github.com/modernw
Color = Dark
*/
.page,
.page * {
transition: background-color 0.3s cubic-bezier(0.1, 0.9, 0.2, 1), color 0.5s cubic-bezier(0.1, 0.9, 0.2, 1), border-color 0.5s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.page {
background-color: #1d1d1d;
}
.page.splash {
background-color: #001629;
}
.page.splash .content,
.page.splash .content * {
transition: none;
}
.page .content.loading,
.page .content.main,
.page .progress,
.page .reason p,
.page .controls .checkbox {
color: white;
}
.page .content.main .pkgapplabel {
color: #299fff;
}
.page .reason textarea {
background-color: rgba (255, 255, 255, 0);
color: white;
border: 2px solid white;
box-sizing: border-box;
}
/* App Launch List */
.applist-font-title {
color: white;
}
.applist-font-text {
color: white;
}
.applist-window {
border: 2px solid rgb(42, 42, 42);
background-color: #1d1d1d;
}
.applist-title {
background: #1d1d1d;
}
.applist-control {
background: #1d1d1d;
}
.applist-list-item {
background-color: rgba(0, 255, 255, 0);
}
.applist-list-item:hover {
background-color: rgba(255, 255, 255, 0.13);
}
.applist-item-picbox {
background-color: #001020;
}
.applist-item-img-border {
border: 1px solid rgba(254, 254, 254, 0.1);
}
.win10.applist-window {
border: 1px solid #ccc;
}

View File

@@ -1,19 +0,0 @@
.page {
background-color: #F3F3F3;
}
.page.splash {
background-color: #0078d7;
}
.page .content.loading,
.page .content.main,
.page .progress,
.page .reason p,
.page .controls .checkbox {
color: black;
}
.page .content.main .pkgapplabel {
color: #0078d7;
}

View File

@@ -0,0 +1,77 @@
/*
[ThemeInfo]
Id = default
DisplayName = Default Theme
Author = Bruce Winter
Version = 1.0
Description = Default theme.
Url = https://github.com/modernw
Color = Light
*/
/* Installer */
.page {
background-color: #F3F3F3;
}
.page.splash {
background-color: #0078d7;
}
.page .content.loading,
.page .content.main,
.page .progress,
.page .reason p,
.page .controls .checkbox {
color: black;
}
.page .content.main .pkgapplabel {
color: #0078d7;
}
/* App Launch List */
.applist-font-title {
color: black;
}
.applist-font-text {
color: black;
}
.applist-window {
border: 2px solid rgb(42, 42, 42);
background-color: white;
}
.applist-title {
background: white;
}
.applist-control {
background: white;
}
.applist-list-item {
background-color: rgba(0, 255, 255, 0);
}
.applist-list-item:hover {
background-color: rgb(222, 222, 222);
}
.applist-item-picbox {
background-color: #001020;
}
.applist-item-img-border {
border: 1px solid rgba(254, 254, 254, 0.1);
}
.win10.applist-window {
border: 1px solid #ccc;
}